| 1 | import { describe, expect, it } from "bun:test"; |
| 2 | import ignore, { isPathValid } from "../src/ignore.ts"; |
| 3 | |
| 4 | describe("ignore v7.0.5 options and public methods", () => { |
| 5 | it("adds another Ignore instance", () => { |
| 6 | const a = ignore().add([".abc/*", "!.abc/d/"]); |
| 7 | const b = ignore().add(a).add("!.abc/e/"); |
| 8 | const paths = [".abc/a.js", ".abc/d/e.js", ".abc/e/e.js"]; |
| 9 | |
| 10 | expect(a.filter(paths)).toEqual([".abc/d/e.js"]); |
| 11 | expect(b.filter(paths)).toEqual([".abc/d/e.js", ".abc/e/e.js"]); |
| 12 | }); |
| 13 | |
| 14 | it("cannot invoke the instance constructor without new", () => { |
| 15 | const { constructor } = ignore(); |
| 16 | expect(() => (constructor as () => unknown)()).toThrow(); |
| 17 | }); |
| 18 | |
| 19 | it("accepts an Ignore-shaped instance from another module copy", () => { |
| 20 | const source = ignore().add([".abc/*", "!.abc/d/"]); |
| 21 | const compatible = { |
| 22 | _rules: { |
| 23 | _rules: (source as any)._rules._rules.slice(), |
| 24 | }, |
| 25 | [Symbol.for("node-ignore")]: true, |
| 26 | }; |
| 27 | const matcher = ignore() |
| 28 | .add(compatible as any) |
| 29 | .add("!.abc/e/"); |
| 30 | |
| 31 | expect(matcher.filter([".abc/a.js", ".abc/d/e.js", ".abc/e/e.js"])).toEqual( |
| 32 | [".abc/d/e.js", ".abc/e/e.js"], |
| 33 | ); |
| 34 | }); |
| 35 | |
| 36 | it("respects ignorecase", () => { |
| 37 | const matcher = ignore({ ignorecase: false }).add("*.[jJ][pP]g"); |
| 38 | expect(matcher.ignores("a.jpg")).toBe(true); |
| 39 | expect(matcher.ignores("a.JPg")).toBe(true); |
| 40 | expect(matcher.ignores("a.JPG")).toBe(false); |
| 41 | }); |
| 42 | |
| 43 | it("respects ignorecase without leaking the compiled-rule cache", () => { |
| 44 | const rule = "*.[jJ][pP]g"; |
| 45 | expect(ignore({ ignorecase: false }).add(rule).ignores("a.JPG")).toBe( |
| 46 | false, |
| 47 | ); |
| 48 | expect(ignore({ ignorecase: true }).add(rule).ignores("a.JPG")).toBe(true); |
| 49 | }); |
| 50 | |
| 51 | it("rejects invalid paths", () => { |
| 52 | const matcher = ignore(); |
| 53 | expect(() => matcher.ignores("")).toThrow(); |
| 54 | expect(() => matcher.ignores("/a")).toThrow("path.relative"); |
| 55 | expect(() => matcher.filter([""])).toThrow(); |
| 56 | expect(() => [""].filter(matcher.createFilter())).toThrow(); |
| 57 | }); |
| 58 | |
| 59 | it("validates paths", () => { |
| 60 | expect([".", "./foo", "../foo", "/foo", "foo"].filter(isPathValid)).toEqual( |
| 61 | ["foo"], |
| 62 | ); |
| 63 | }); |
| 64 | |
| 65 | it("returns ignored and unignored state from test", () => { |
| 66 | const cases: Array< |
| 67 | [string | string[] | undefined, string, boolean, boolean] |
| 68 | > = [ |
| 69 | [undefined, "foo", false, false], |
| 70 | ["bar", "foo", false, false], |
| 71 | ["!foo", "foo", false, true], |
| 72 | [["foo", "!foo"], "foo", false, true], |
| 73 | [["foo", "!foo"], "foo/bar", false, false], |
| 74 | [["*.js", "!a/a.js"], "a/a.js", false, true], |
| 75 | ...(process.platform === "win32" |
| 76 | ? [] |
| 77 | : ([[undefined, "...", false, false]] as Array< |
| 78 | [undefined, string, boolean, boolean] |
| 79 | >)), |
| 80 | ]; |
| 81 | |
| 82 | for (const [patterns, path, ignored, unignored] of cases) { |
| 83 | const matcher = ignore(); |
| 84 | if (patterns) matcher.add(patterns); |
| 85 | expect(matcher.test(path)).toEqual({ ignored, unignored }); |
| 86 | } |
| 87 | }); |
| 88 | |
| 89 | it("optionally permits relative paths", () => { |
| 90 | expect( |
| 91 | ignore({ allowRelativePaths: true }).add("foo").ignores("../foo/bar.js"), |
| 92 | ).toBe(true); |
| 93 | expect(() => ignore().ignores("../foo/bar.js")).toThrow("path.relative"); |
| 94 | expect(() => ignore().add("foo").ignores("/foo/bar.js")).toThrow( |
| 95 | "path.relative", |
| 96 | ); |
| 97 | }); |
| 98 | }); |