mirror of
https://github.com/giancarloerra/socraticode.git
synced 2026-07-03 14:05:21 +02:00
236 lines
8.5 KiB
TypeScript
236 lines
8.5 KiB
TypeScript
// SPDX-License-Identifier: AGPL-3.0-only
|
|
// Copyright (C) 2026 Giancarlo Erra - Altaire Limited
|
|
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
import { createIgnoreFilter, shouldIgnore } from "../../src/services/ignore.js";
|
|
import { createFixtureProject, type FixtureProject } from "../helpers/fixtures.js";
|
|
|
|
describe("ignore", () => {
|
|
let fixture: FixtureProject | null = null;
|
|
const savedEnv: Record<string, string | undefined> = {};
|
|
|
|
beforeEach(() => {
|
|
savedEnv.RESPECT_GITIGNORE = process.env.RESPECT_GITIGNORE;
|
|
});
|
|
|
|
afterEach(() => {
|
|
fixture?.cleanup();
|
|
fixture = null;
|
|
// Restore env
|
|
if (savedEnv.RESPECT_GITIGNORE === undefined) {
|
|
delete process.env.RESPECT_GITIGNORE;
|
|
} else {
|
|
process.env.RESPECT_GITIGNORE = savedEnv.RESPECT_GITIGNORE;
|
|
}
|
|
});
|
|
|
|
describe("createIgnoreFilter", () => {
|
|
it("returns an ignore filter object", () => {
|
|
fixture = createFixtureProject("ignore-test");
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
expect(ig).toBeDefined();
|
|
expect(typeof ig.ignores).toBe("function");
|
|
});
|
|
|
|
it("ignores node_modules by default", () => {
|
|
fixture = createFixtureProject("ignore-defaults");
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
expect(ig.ignores("node_modules/package/index.js")).toBe(true);
|
|
});
|
|
|
|
it("ignores .git by default", () => {
|
|
fixture = createFixtureProject("ignore-git");
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
expect(ig.ignores(".git/config")).toBe(true);
|
|
});
|
|
|
|
it("ignores dist by default", () => {
|
|
fixture = createFixtureProject("ignore-dist");
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
expect(ig.ignores("dist/index.js")).toBe(true);
|
|
});
|
|
|
|
it("ignores common lock files by default", () => {
|
|
fixture = createFixtureProject("ignore-locks");
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
expect(ig.ignores("package-lock.json")).toBe(true);
|
|
expect(ig.ignores("yarn.lock")).toBe(true);
|
|
expect(ig.ignores("pnpm-lock.yaml")).toBe(true);
|
|
});
|
|
|
|
it("ignores .DS_Store by default", () => {
|
|
fixture = createFixtureProject("ignore-ds");
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
expect(ig.ignores(".DS_Store")).toBe(true);
|
|
});
|
|
|
|
it("respects .gitignore rules from the project root", () => {
|
|
fixture = createFixtureProject("ignore-gitignore");
|
|
// The fixture already has a .gitignore with "*.log"
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
expect(ig.ignores("debug.log")).toBe(true);
|
|
expect(ig.ignores("error.log")).toBe(true);
|
|
});
|
|
|
|
it("does not ignore source files", () => {
|
|
fixture = createFixtureProject("ignore-src");
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
expect(ig.ignores("src/index.ts")).toBe(false);
|
|
expect(ig.ignores("lib/data_processor.py")).toBe(false);
|
|
expect(ig.ignores("README.md")).toBe(false);
|
|
});
|
|
|
|
it("reads nested .gitignore files", () => {
|
|
fixture = createFixtureProject("ignore-nested");
|
|
|
|
// Create a nested .gitignore
|
|
fs.mkdirSync(path.join(fixture.root, "packages", "sub"), { recursive: true });
|
|
fs.writeFileSync(
|
|
path.join(fixture.root, "packages", "sub", ".gitignore"),
|
|
"temp/\n*.bak\n",
|
|
);
|
|
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
// Nested .gitignore patterns should be prefixed with the relative path
|
|
expect(ig.ignores("packages/sub/temp/file.txt")).toBe(true);
|
|
expect(ig.ignores("packages/sub/data.bak")).toBe(true);
|
|
});
|
|
|
|
it("reads .socraticodeignore if present", () => {
|
|
fixture = createFixtureProject("ignore-socraticode");
|
|
|
|
fs.writeFileSync(
|
|
path.join(fixture.root, ".socraticodeignore"),
|
|
"artifacts/\n*.generated.ts\n",
|
|
);
|
|
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
expect(ig.ignores("artifacts/bundle.js")).toBe(true);
|
|
expect(ig.ignores("src/schema.generated.ts")).toBe(true);
|
|
expect(ig.ignores("src/index.ts")).toBe(false);
|
|
});
|
|
|
|
it("does not load .socraticodeignore patterns when file is absent", () => {
|
|
fixture = createFixtureProject("ignore-no-socraticode");
|
|
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
// A pattern that would only match via .socraticodeignore
|
|
expect(ig.ignores("custom-exclude/file.txt")).toBe(false);
|
|
// Defaults still work
|
|
expect(ig.ignores("node_modules/x.js")).toBe(true);
|
|
});
|
|
|
|
it("skips .gitignore when RESPECT_GITIGNORE=false", () => {
|
|
fixture = createFixtureProject("ignore-skip-gitignore");
|
|
|
|
// Write a .gitignore with a pattern NOT in built-in defaults
|
|
fs.writeFileSync(
|
|
path.join(fixture.root, ".gitignore"),
|
|
"custom-ignored-dir/\n",
|
|
);
|
|
|
|
process.env.RESPECT_GITIGNORE = "false";
|
|
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
// .gitignore patterns should be skipped
|
|
expect(ig.ignores("custom-ignored-dir/file.txt")).toBe(false);
|
|
// But default patterns should still be applied
|
|
expect(ig.ignores("node_modules/x.js")).toBe(true);
|
|
});
|
|
|
|
it("respects .gitignore by default (RESPECT_GITIGNORE unset)", () => {
|
|
fixture = createFixtureProject("ignore-default-gitignore");
|
|
|
|
// Write a .gitignore with a pattern NOT in built-in defaults
|
|
fs.writeFileSync(
|
|
path.join(fixture.root, ".gitignore"),
|
|
"custom-ignored-dir/\n",
|
|
);
|
|
|
|
delete process.env.RESPECT_GITIGNORE;
|
|
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
// .gitignore patterns should work
|
|
expect(ig.ignores("custom-ignored-dir/file.txt")).toBe(true);
|
|
});
|
|
|
|
it("skips nested .gitignore when RESPECT_GITIGNORE=false", () => {
|
|
fixture = createFixtureProject("ignore-skip-nested");
|
|
|
|
fs.mkdirSync(path.join(fixture.root, "packages", "sub"), { recursive: true });
|
|
fs.writeFileSync(
|
|
path.join(fixture.root, "packages", "sub", ".gitignore"),
|
|
"temp/\n",
|
|
);
|
|
|
|
process.env.RESPECT_GITIGNORE = "false";
|
|
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
// Nested .gitignore patterns should NOT be loaded
|
|
expect(ig.ignores("packages/sub/temp/file.txt")).toBe(false);
|
|
});
|
|
|
|
it("handles project with no .gitignore", () => {
|
|
fixture = createFixtureProject("ignore-no-gitignore");
|
|
// Remove the .gitignore
|
|
fs.unlinkSync(path.join(fixture.root, ".gitignore"));
|
|
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
// Default patterns should still work
|
|
expect(ig.ignores("node_modules/x.js")).toBe(true);
|
|
// Source files should not be ignored
|
|
expect(ig.ignores("src/index.ts")).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("shouldIgnore", () => {
|
|
it("returns true for ignored paths", () => {
|
|
fixture = createFixtureProject("should-ignore-true");
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
expect(shouldIgnore(ig, "node_modules/x.js")).toBe(true);
|
|
});
|
|
|
|
it("returns false for non-ignored paths", () => {
|
|
fixture = createFixtureProject("should-ignore-false");
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
expect(shouldIgnore(ig, "src/index.ts")).toBe(false);
|
|
});
|
|
|
|
it("ignores Python cache directories", () => {
|
|
fixture = createFixtureProject("should-ignore-pycache");
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
expect(shouldIgnore(ig, "__pycache__/module.pyc")).toBe(true);
|
|
});
|
|
|
|
it("ignores build output directories", () => {
|
|
fixture = createFixtureProject("should-ignore-build");
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
expect(shouldIgnore(ig, "build/output.js")).toBe(true);
|
|
expect(shouldIgnore(ig, "out/bundle.js")).toBe(true);
|
|
});
|
|
|
|
it("ignores IDE directories", () => {
|
|
fixture = createFixtureProject("should-ignore-ide");
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
expect(shouldIgnore(ig, ".idea/workspace.xml")).toBe(true);
|
|
expect(shouldIgnore(ig, ".vscode/settings.json")).toBe(true);
|
|
});
|
|
|
|
it("ignores minified files", () => {
|
|
fixture = createFixtureProject("should-ignore-min");
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
expect(shouldIgnore(ig, "assets/app.min.js")).toBe(true);
|
|
expect(shouldIgnore(ig, "styles/main.min.css")).toBe(true);
|
|
});
|
|
|
|
it("ignores coverage directories", () => {
|
|
fixture = createFixtureProject("should-ignore-coverage");
|
|
const ig = createIgnoreFilter(fixture.root);
|
|
// The fixture .gitignore includes "coverage/"
|
|
expect(shouldIgnore(ig, "coverage/lcov.info")).toBe(true);
|
|
});
|
|
});
|
|
});
|