view-ignored 0.9.1 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +18 -19
  2. package/out/browser_scan.js +5 -5
  3. package/out/opendir.d.ts +3 -3
  4. package/out/opendir.js +24 -14
  5. package/out/patterns/extractor.d.ts +1 -8
  6. package/out/patterns/gitignore.d.ts +3 -3
  7. package/out/patterns/gitignore.js +8 -8
  8. package/out/patterns/ignores.d.ts +9 -3
  9. package/out/patterns/index.d.ts +3 -3
  10. package/out/patterns/index.js +3 -3
  11. package/out/patterns/initState.d.ts +7 -0
  12. package/out/patterns/jsrjson.d.ts +1 -1
  13. package/out/patterns/jsrjson.js +5 -5
  14. package/out/patterns/matcherContext.d.ts +2 -2
  15. package/out/patterns/matcherContextPatch.js +18 -14
  16. package/out/patterns/matcherStream.d.ts +2 -2
  17. package/out/patterns/matcherStream.js +5 -5
  18. package/out/patterns/packagejson.d.ts +2 -2
  19. package/out/patterns/packagejson.js +7 -7
  20. package/out/patterns/patternCompile.d.ts +22 -0
  21. package/out/patterns/patternCompile.js +62 -0
  22. package/out/patterns/patternList.d.ts +52 -0
  23. package/out/patterns/patternList.js +20 -0
  24. package/out/patterns/resolveSources.d.ts +5 -5
  25. package/out/patterns/resolveSources.js +20 -27
  26. package/out/patterns/rule.d.ts +121 -0
  27. package/out/patterns/{signedPattern.js → rule.js} +18 -17
  28. package/out/patterns/source.d.ts +9 -6
  29. package/out/patterns/source.js +5 -2
  30. package/out/targets/bun.js +8 -13
  31. package/out/targets/deno.js +6 -11
  32. package/out/targets/git.js +6 -11
  33. package/out/targets/jsr.js +6 -11
  34. package/out/targets/npm.js +8 -13
  35. package/out/targets/target.d.ts +14 -0
  36. package/out/targets/vsce.js +6 -11
  37. package/out/targets/yarn.js +8 -13
  38. package/out/targets/yarnClassic.js +7 -12
  39. package/out/unixify.js +7 -5
  40. package/out/walk.d.ts +1 -0
  41. package/out/walk.js +11 -3
  42. package/package.json +5 -4
  43. package/out/patterns/pattern.d.ts +0 -50
  44. package/out/patterns/pattern.js +0 -21
  45. package/out/patterns/signedPattern.d.ts +0 -121
  46. package/out/patterns/stringCompile.d.ts +0 -22
  47. package/out/patterns/stringCompile.js +0 -31
package/README.md CHANGED
@@ -18,7 +18,9 @@ Node.js 18 or later
18
18
  readers, not command-line wrappers.
19
19
  - **Plugins.** Built-in [targets](#targets) for popular tools. Use custom
20
20
  targets by implementing/extending the `Target` interface.
21
- - **TypeScript.** Written in TypeScript with type definitions included.
21
+ - **Streaming.** Native `scanStream` support for processing massive file trees with minimal memory overhead.
22
+ - **Execution Control.** Use `fastDepth` and `fastInternal` options to fine-tune traversal depth and skip unnecessary directory checks.
23
+ - **Abortable.** Full support for `AbortSignal` to cancel long-running scans instantly.
22
24
  - **Lightweight.** Minimal dependencies for fast performance and small bundle size.
23
25
  - **Easy-to-modify.** Well-written and MIT-licensed.
24
26
  - **Browser.** Can be bundled for browser use. See `ScanOptions.fs` and `import ... "view-ignored/browser"`.
@@ -56,9 +58,9 @@ if (match.kind === "external") {
56
58
  import {
57
59
  type Extractor,
58
60
  extractGitignore,
59
- signedPatternIgnores,
60
- signedPatternCompile,
61
- type SignedPattern,
61
+ ruleTest,
62
+ ruleCompile,
63
+ type Rule,
62
64
  } from "view-ignored/patterns"
63
65
 
64
66
  import type { Target } from "view-ignored/targets"
@@ -74,24 +76,21 @@ const extractors: Extractor[] = [
74
76
  },
75
77
  ]
76
78
 
77
- const internal: SignedPattern = {
78
- exclude: [".git", ".DS_Store"],
79
- include: [],
80
- compiled: null,
81
- }
82
-
83
- signedPatternCompile(internal)
79
+ const internal: Rule[] = [
80
+ ruleCompile({
81
+ excludes: true,
82
+ pattern: [".git", ".DS_Store"],
83
+ compiled: null,
84
+ }),
85
+ ]
84
86
 
85
87
  export const Git: Target = {
88
+ internalRules: internal,
86
89
  extractors,
87
- ignores(o) {
88
- return signedPatternIgnores({
89
- ...o,
90
- internal,
91
- root: "/",
92
- target: Git,
93
- })
94
- },
90
+ root: "/",
91
+ // TODO: Git should read configs
92
+ init() {},
93
+ ignores: ruleTest,
95
94
  }
96
95
 
97
96
  const ctx = await vign.scan({ target })
@@ -1,5 +1,5 @@
1
1
  import { opendir } from "./opendir.js";
2
- import { unixify, relative, join } from "./unixify.js";
2
+ import { unixify, join } from "./unixify.js";
3
3
  import { walkIncludes } from "./walk.js";
4
4
  /**
5
5
  * Scan the directory for included files based on the provided targets.
@@ -41,13 +41,13 @@ export function scan(options) {
41
41
  target,
42
42
  };
43
43
  return (async () => {
44
- await target.init?.({ ctx, cwd, fs, signal });
45
- let from = join(unixify(normalCwd), within);
46
- await opendir(fs, from, (entry) => {
47
- const path = relative(normalCwd, unixify(entry.parentPath) + "/" + entry.name);
44
+ await target.init?.({ ctx, cwd, fs, signal, target });
45
+ let from = join(normalCwd, within);
46
+ await opendir({ ctx, cwd: normalCwd, fs, signal, target }, from, (entry, parentPath, path) => {
48
47
  return walkIncludes({
49
48
  path,
50
49
  entry,
50
+ parentPath,
51
51
  ctx,
52
52
  stream: undefined,
53
53
  scanOptions,
package/out/opendir.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import type { Dirent, PathLike } from "node:fs";
2
- import type { FsAdapter } from "./types.js";
3
- export declare function opendir(fs: FsAdapter, path: PathLike, cb: (entry: Dirent) => Promise<0 | 1 | 2>): Promise<void | 2>;
1
+ import type { Dirent } from "node:fs";
2
+ import type { PatternFinderOptions } from "./patterns/extractor.js";
3
+ export declare function opendir(options: PatternFinderOptions, place: string, cb: (dirent: Dirent, parentPath: string, path: string) => Promise<0 | 1 | 2>): Promise<boolean>;
package/out/opendir.js CHANGED
@@ -1,18 +1,28 @@
1
- export async function opendir(fs, path, cb) {
2
- const dir = await fs.promises.opendir(path);
1
+ import { resolveSources } from "./patterns/resolveSources.js";
2
+ export async function opendir(options, place, cb) {
3
+ const { ctx, cwd, fs, signal, target } = options;
4
+ const dir = await fs.promises.opendir(place);
5
+ const tasks = [];
6
+ const normalParentPath = place;
7
+ const substr = normalParentPath.substring(cwd.length + 1);
8
+ const isRootDir = normalParentPath.length === cwd.length;
9
+ const parentPath = isRootDir ? "." : substr;
10
+ await resolveSources({ ctx, cwd, fs, signal, target, dir: parentPath });
11
+ let stop = false;
3
12
  for await (const entry of dir) {
4
- const r = await cb(entry);
5
- if (r === 2) {
6
- return 2;
7
- }
8
- if (r === 1) {
9
- continue;
10
- }
11
- if (entry.isDirectory()) {
12
- const r = await opendir(fs, path + "/" + entry.name, cb);
13
- if (r === 2) {
14
- return 2;
13
+ const from = place + "/" + entry.name;
14
+ const path = isRootDir ? entry.name : substr + "/" + entry.name;
15
+ const task = (async () => {
16
+ const r = await cb(entry, parentPath, path);
17
+ if (r === 1)
18
+ return;
19
+ if (r === 2 || (entry.isDirectory() && (await opendir(options, from, cb)))) {
20
+ stop = true;
21
+ return;
15
22
  }
16
- }
23
+ })();
24
+ tasks.push(task);
17
25
  }
26
+ await Promise.all(tasks);
27
+ return stop;
18
28
  }
@@ -41,7 +41,7 @@ export interface Extractor {
41
41
  * Options for finding and extracting patterns from source files.
42
42
  *
43
43
  * @see {@link resolveSources}
44
- * @see {@link signedPatternIgnores}
44
+ * @see {@link ruleTest}
45
45
  *
46
46
  * @since 0.6.0
47
47
  */
@@ -70,13 +70,6 @@ export interface PatternFinderOptions {
70
70
  * @since 0.6.0
71
71
  */
72
72
  target: Target;
73
- /**
74
- * Initial search directory.
75
- * Relative to the `cwd` path or absolute path.
76
- *
77
- * @since 0.6.0
78
- */
79
- root: string;
80
73
  /**
81
74
  * Return as soon as possible.
82
75
  *
@@ -2,7 +2,7 @@ import { type Source } from "./source.js";
2
2
  /**
3
3
  * Extracts and compiles patterns from the file.
4
4
  *
5
- * @see {@link signedPatternCompile}
5
+ * @see {@link ruleCompile}
6
6
  *
7
7
  * @since 0.6.0
8
8
  */
@@ -10,8 +10,8 @@ export declare function extractGitignore(source: Source, content: Buffer): void;
10
10
  /**
11
11
  * Extracts and compiles patterns from the file.
12
12
  *
13
- * @see {@link signedPatternCompile}
13
+ * @see {@link ruleCompile}
14
14
  *
15
- * @since 0.6.0
15
+ * @since 0.8.0
16
16
  */
17
17
  export declare function extractGitignoreNocase(source: Source, content: Buffer): void;
@@ -1,29 +1,29 @@
1
- import { signedPatternCompile } from "./resolveSources.js";
2
- import { sourcePushNegatable } from "./source.js";
1
+ import { ruleCompile } from "./resolveSources.js";
2
+ import { resolveNegatable } from "./source.js";
3
3
  /**
4
4
  * Extracts and compiles patterns from the file.
5
5
  *
6
- * @see {@link signedPatternCompile}
6
+ * @see {@link ruleCompile}
7
7
  *
8
8
  * @since 0.6.0
9
9
  */
10
10
  export function extractGitignore(source, content) {
11
11
  extract(source, content);
12
12
  for (const element of source.pattern) {
13
- signedPatternCompile(element);
13
+ ruleCompile(element);
14
14
  }
15
15
  }
16
16
  /**
17
17
  * Extracts and compiles patterns from the file.
18
18
  *
19
- * @see {@link signedPatternCompile}
19
+ * @see {@link ruleCompile}
20
20
  *
21
- * @since 0.6.0
21
+ * @since 0.8.0
22
22
  */
23
23
  export function extractGitignoreNocase(source, content) {
24
24
  extract(source, content);
25
25
  for (const element of source.pattern) {
26
- signedPatternCompile(element, { nocase: true });
26
+ ruleCompile(element, { nocase: true });
27
27
  }
28
28
  }
29
29
  extractGitignore;
@@ -39,7 +39,7 @@ function extract(source, content) {
39
39
  if (cdx >= 0) {
40
40
  line = line.substring(-cdx);
41
41
  }
42
- sourcePushNegatable(line, false, include, exclude);
42
+ resolveNegatable(line, false, include, exclude);
43
43
  }
44
44
  source.pattern.push(include, exclude);
45
45
  }
@@ -1,5 +1,5 @@
1
- import type { SignedPatternMatch } from "../patterns/signedPattern.js";
2
1
  import type { InitState } from "./initState.js";
2
+ import type { RuleMatch } from "./rule.js";
3
3
  /**
4
4
  * Used in {@link Ignores}.
5
5
  *
@@ -12,14 +12,20 @@ export interface IgnoresOptions extends InitState {
12
12
  * @since 0.6.0
13
13
  */
14
14
  entry: string;
15
+ /**
16
+ * Result of the `dirname(entry)` call.
17
+ *
18
+ * @since 0.10.1
19
+ */
20
+ parentPath: string;
15
21
  }
16
22
  /**
17
23
  * Checks whether a given entry path should be ignored based on its patterns.
18
24
  *
19
25
  * @see {@link resolveSources}
20
- * @see {@link signedPatternIgnores}
26
+ * @see {@link ruleTest}
21
27
  * @see {@link https://github.com/Mopsgamer/view-ignored/tree/main/src/targets} for usage examples.
22
28
  *
23
29
  * @since 0.6.0
24
30
  */
25
- export type Ignores = (options: IgnoresOptions) => Promise<SignedPatternMatch>;
31
+ export type Ignores = (options: IgnoresOptions) => Promise<RuleMatch>;
@@ -8,8 +8,8 @@ export * from "./matcherContext.js";
8
8
  export * from "./matcherContextPatch.js";
9
9
  export * from "./matcherStream.js";
10
10
  export * from "./packagejson.js";
11
- export * from "./pattern.js";
11
+ export * from "./patternList.js";
12
12
  export * from "./resolveSources.js";
13
- export * from "./signedPattern.js";
13
+ export * from "./rule.js";
14
14
  export * from "./source.js";
15
- export * from "./stringCompile.js";
15
+ export * from "./patternCompile.js";
@@ -8,8 +8,8 @@ export * from "./matcherContext.js";
8
8
  export * from "./matcherContextPatch.js";
9
9
  export * from "./matcherStream.js";
10
10
  export * from "./packagejson.js";
11
- export * from "./pattern.js";
11
+ export * from "./patternList.js";
12
12
  export * from "./resolveSources.js";
13
- export * from "./signedPattern.js";
13
+ export * from "./rule.js";
14
14
  export * from "./source.js";
15
- export * from "./stringCompile.js";
15
+ export * from "./patternCompile.js";
@@ -1,3 +1,4 @@
1
+ import type { Target } from "../targets/target.js";
1
2
  import type { FsAdapter } from "../types.js";
2
3
  import type { MatcherContext } from "./matcherContext.js";
3
4
  /**
@@ -22,6 +23,12 @@ export interface InitState {
22
23
  * @since 0.6.0
23
24
  */
24
25
  ctx: MatcherContext;
26
+ /**
27
+ * The target implementation.
28
+ *
29
+ * @since 0.10.0
30
+ */
31
+ target: Target;
25
32
  /**
26
33
  * Return as soon as possible.
27
34
  *
@@ -9,7 +9,7 @@ export declare function extractJsrJson(source: Source, content: Buffer, ctx: Mat
9
9
  /**
10
10
  * Extracts and compiles patterns from the file.
11
11
  *
12
- * @see {@link signedPatternCompile}
12
+ * @see {@link ruleCompile}
13
13
  *
14
14
  * @since 0.6.0
15
15
  */
@@ -1,7 +1,7 @@
1
1
  import { type } from "arktype";
2
2
  import stripJsonComments from "strip-json-comments";
3
- import { signedPatternCompile } from "./resolveSources.js";
4
- import { sourcePushNegatable } from "./source.js";
3
+ import { ruleCompile } from "./resolveSources.js";
4
+ import { resolveNegatable } from "./source.js";
5
5
  const jsrManifest = type({
6
6
  exclude: "string[]?",
7
7
  include: "string[]?",
@@ -21,14 +21,14 @@ const parse = type("string")
21
21
  export function extractJsrJson(source, content, ctx) {
22
22
  extract(source, content, ctx);
23
23
  for (const element of source.pattern) {
24
- signedPatternCompile(element);
24
+ ruleCompile(element);
25
25
  }
26
26
  }
27
27
  extractJsrJson;
28
28
  /**
29
29
  * Extracts and compiles patterns from the file.
30
30
  *
31
- * @see {@link signedPatternCompile}
31
+ * @see {@link ruleCompile}
32
32
  *
33
33
  * @since 0.6.0
34
34
  */
@@ -63,7 +63,7 @@ function extract(source, content, ctx) {
63
63
  }
64
64
  for (const si of [include, exclude]) {
65
65
  for (const pattern of si.pattern) {
66
- sourcePushNegatable(pattern, true, include, exclude);
66
+ resolveNegatable(pattern, true, include, exclude);
67
67
  }
68
68
  }
69
69
  source.pattern.push(include, exclude);
@@ -1,4 +1,4 @@
1
- import type { SignedPatternMatch } from "./signedPattern.js";
1
+ import type { RuleMatch } from "./rule.js";
2
2
  import type { Source } from "./source.js";
3
3
  /**
4
4
  * Post-scan results.
@@ -12,7 +12,7 @@ export interface MatcherContext {
12
12
  *
13
13
  * @since 0.6.0
14
14
  */
15
- paths: Map<string, SignedPatternMatch>;
15
+ paths: Map<string, RuleMatch>;
16
16
  /**
17
17
  * Maps directory paths to their corresponding sources.
18
18
  *
@@ -1,8 +1,9 @@
1
- import { resolve, dirname } from "node:path";
1
+ import { dirname } from "node:path";
2
2
  import { getDepth } from "../getDepth.js";
3
3
  import { opendir } from "../opendir.js";
4
- import { unixify, relative } from "../unixify.js";
4
+ import { unixify, join } from "../unixify.js";
5
5
  import { walkIncludes } from "../walk.js";
6
+ import { resolveSources } from "./resolveSources.js";
6
7
  /**
7
8
  * Provides patching abilities for the given {@link MatcherContext}.
8
9
  * Directories should have the slash suffix.
@@ -21,28 +22,29 @@ export async function matcherContextAddPath(ctx, options, entry) {
21
22
  if (direntPath === ".") {
22
23
  return true;
23
24
  }
24
- ctx.paths.set(entry, await target.ignores({ fs, cwd, entry: direntPath, ctx, signal }));
25
+ const parentPath = dirname(direntPath);
26
+ await resolveSources({ ctx, cwd, dir: direntPath, fs, signal, target });
27
+ ctx.paths.set(entry, await target.ignores({ fs, cwd, entry: direntPath, ctx, signal, target, parentPath }));
25
28
  if (ctx.totalFiles >= 0) {
26
29
  ctx.totalDirs++;
27
30
  }
28
- const parent = dirname(direntPath);
29
- if (parent !== ".") {
30
- void (await matcherContextAddPath(ctx, options, parent + "/"));
31
+ if (parentPath !== ".") {
32
+ void (await matcherContextAddPath(ctx, options, parentPath + "/"));
31
33
  }
32
34
  return true;
33
35
  }
34
- const parent = dirname(entry);
36
+ const parentPath = dirname(entry);
35
37
  const isSource = target.extractors.some((e) => e.path === entry);
36
38
  if (isSource) {
37
39
  // add pattern sources
38
- await matcherContextRemovePath(ctx, options, parent + "/");
39
- await rescan(ctx, { ...options, within: parent });
40
+ await matcherContextRemovePath(ctx, options, parentPath + "/");
41
+ await rescan(ctx, { ...options, within: parentPath });
40
42
  }
41
43
  // add paths
42
44
  // 1. recursively populate parents
43
- await matcherContextAddPath(ctx, options, parent + "/");
45
+ await matcherContextAddPath(ctx, options, parentPath + "/");
44
46
  // 2. if ignored, remove, otherwise add
45
- const match = await target.ignores({ fs, cwd, entry, ctx, signal });
47
+ const match = await target.ignores({ fs, cwd, entry, ctx, signal, target, parentPath });
46
48
  if (match.ignored) {
47
49
  // 2.1. remove
48
50
  await matcherContextRemovePath(ctx, options, entry);
@@ -140,11 +142,13 @@ export async function matcherContextRemovePath(ctx, options, entry) {
140
142
  return true;
141
143
  }
142
144
  async function rescan(ctx, options) {
143
- const normalCwd = unixify(options.cwd);
144
- await opendir(options.fs, resolve(normalCwd, options.within), (entry) => {
145
- const path = relative(normalCwd, unixify(entry.parentPath) + "/" + entry.name);
145
+ const { cwd, within, fs, signal, target } = options;
146
+ const normalCwd = unixify(cwd);
147
+ let from = join(normalCwd, within);
148
+ await opendir({ ctx, cwd: normalCwd, fs, signal, target }, from, (entry, parentPath, path) => {
146
149
  return walkIncludes({
147
150
  path,
151
+ parentPath,
148
152
  entry,
149
153
  ctx,
150
154
  stream: undefined,
@@ -2,7 +2,7 @@ import type { Dirent } from "node:fs";
2
2
  import { EventEmitter } from "node:events";
3
3
  import type { MatcherContext } from "../patterns/matcherContext.js";
4
4
  import type { ScanOptions, FsAdapter } from "../types.js";
5
- import type { SignedPatternMatch } from "./signedPattern.js";
5
+ import type { RuleMatch } from "./rule.js";
6
6
  /**
7
7
  * Post-scan entry information.
8
8
  *
@@ -26,7 +26,7 @@ export type EntryInfo = {
26
26
  *
27
27
  * @since 0.6.0
28
28
  */
29
- match: SignedPatternMatch;
29
+ match: RuleMatch;
30
30
  /**
31
31
  * The matcher context.
32
32
  *
@@ -1,6 +1,6 @@
1
1
  import { EventEmitter } from "node:events";
2
2
  import { opendir } from "../opendir.js";
3
- import { join, relative, unixify } from "../unixify.js";
3
+ import { join, unixify } from "../unixify.js";
4
4
  import { walkIncludes } from "../walk.js";
5
5
  /**
6
6
  * Event emitter.
@@ -49,12 +49,12 @@ export class MatcherStream extends EventEmitter {
49
49
  signal,
50
50
  target,
51
51
  };
52
- await target.init?.({ ctx, cwd, fs, signal });
53
- let from = join(unixify(normalCwd), within);
54
- await opendir(fs, from, (entry) => {
55
- const path = relative(normalCwd, unixify(entry.parentPath) + "/" + entry.name);
52
+ await target.init?.({ ctx, cwd, fs, signal, target });
53
+ let from = join(normalCwd, within);
54
+ await opendir({ ctx, cwd: normalCwd, fs, signal, target }, from, (entry, parentPath, path) => {
56
55
  return walkIncludes({
57
56
  path,
57
+ parentPath,
58
58
  entry,
59
59
  ctx,
60
60
  stream: this,
@@ -2,7 +2,7 @@ import { type Source } from "./source.js";
2
2
  /**
3
3
  * Extracts and compiles patterns from the file.
4
4
  *
5
- * @see {@link signedPatternCompile}
5
+ * @see {@link ruleCompile}
6
6
  *
7
7
  * @since 0.6.0
8
8
  */
@@ -10,7 +10,7 @@ export declare function extractPackageJson(source: Source, content: Buffer): voi
10
10
  /**
11
11
  * Extracts and compiles patterns from the file.
12
12
  *
13
- * @see {@link signedPatternCompile}
13
+ * @see {@link ruleCompile}
14
14
  *
15
15
  * @since 0.8.0
16
16
  */
@@ -1,11 +1,11 @@
1
1
  import { type } from "arktype";
2
2
  import { npmManifestParse } from "../targets/npmManifest.js";
3
- import { signedPatternCompile } from "./resolveSources.js";
4
- import { sourcePushNegatable } from "./source.js";
3
+ import { ruleCompile } from "./resolveSources.js";
4
+ import { resolveNegatable } from "./source.js";
5
5
  /**
6
6
  * Extracts and compiles patterns from the file.
7
7
  *
8
- * @see {@link signedPatternCompile}
8
+ * @see {@link ruleCompile}
9
9
  *
10
10
  * @since 0.6.0
11
11
  */
@@ -13,7 +13,7 @@ export function extractPackageJson(source, content) {
13
13
  const result = extract(source, content);
14
14
  if (result === undefined) {
15
15
  for (const element of source.pattern) {
16
- signedPatternCompile(element);
16
+ ruleCompile(element);
17
17
  }
18
18
  }
19
19
  if (result === "error")
@@ -23,7 +23,7 @@ export function extractPackageJson(source, content) {
23
23
  /**
24
24
  * Extracts and compiles patterns from the file.
25
25
  *
26
- * @see {@link signedPatternCompile}
26
+ * @see {@link ruleCompile}
27
27
  *
28
28
  * @since 0.8.0
29
29
  */
@@ -31,7 +31,7 @@ export function extractPackageJsonNocase(source, content) {
31
31
  const result = extract(source, content);
32
32
  if (result === undefined) {
33
33
  for (const element of source.pattern) {
34
- signedPatternCompile(element, { nocase: true });
34
+ ruleCompile(element, { nocase: true });
35
35
  }
36
36
  }
37
37
  if (result === "error")
@@ -51,7 +51,7 @@ function extract(source, content) {
51
51
  return "none";
52
52
  }
53
53
  for (const pattern of dist.files) {
54
- sourcePushNegatable(pattern, true, include, exclude);
54
+ resolveNegatable(pattern, true, include, exclude);
55
55
  }
56
56
  source.pattern.push(include, exclude);
57
57
  }
@@ -0,0 +1,22 @@
1
+ import type { PatternCache, PatternList } from "./patternList.js";
2
+ /**
3
+ * @since 0.8.0
4
+ */
5
+ export type PatternCompileOptions = {
6
+ /**
7
+ * Disables case sensitivity.
8
+ *
9
+ * @default false
10
+ *
11
+ * @since 0.8.0
12
+ */
13
+ nocase?: boolean;
14
+ };
15
+ /**
16
+ * Compiles a string of the {@link PatternList}.
17
+ *
18
+ * @see {@link patternCompile}
19
+ *
20
+ * @since 0.8.0
21
+ */
22
+ export declare function patternCompile(pattern: string, context?: PatternList, options?: PatternCompileOptions): PatternCache;
@@ -0,0 +1,62 @@
1
+ import glob from "micromatch";
2
+ /**
3
+ * Compiles a string of the {@link PatternList}.
4
+ *
5
+ * @see {@link patternCompile}
6
+ *
7
+ * @since 0.8.0
8
+ */
9
+ export function patternCompile(pattern, context = [], options) {
10
+ const original = pattern;
11
+ const isRoot = pattern.startsWith("/");
12
+ const nocase = !!options?.nocase;
13
+ let cleaned = pattern;
14
+ if (cleaned.endsWith("/"))
15
+ cleaned = cleaned.slice(0, -1);
16
+ if (isRoot)
17
+ cleaned = cleaned.slice(1);
18
+ const lowerCleaned = nocase ? cleaned.toLowerCase() : cleaned;
19
+ const prefix = lowerCleaned + "/";
20
+ const hasGlob = cleaned.includes("*");
21
+ const matchBase = !isRoot && !cleaned.includes("/");
22
+ const matcherOpts = {
23
+ dot: true,
24
+ nonegate: true,
25
+ nocomment: true,
26
+ nobrace: true,
27
+ nocase,
28
+ matchBase,
29
+ optimizationLevel: 2,
30
+ };
31
+ const re = {
32
+ test(str) {
33
+ const lowerStr = nocase ? str.toLowerCase() : str;
34
+ if (lowerStr === lowerCleaned || lowerStr.startsWith(prefix)) {
35
+ return true;
36
+ }
37
+ if (matchBase) {
38
+ if (str.includes(cleaned)) {
39
+ const segments = str.split("/");
40
+ for (const seg of segments) {
41
+ if (seg === lowerCleaned)
42
+ return true;
43
+ }
44
+ }
45
+ }
46
+ if (hasGlob) {
47
+ if (glob.isMatch(str, cleaned, matcherOpts))
48
+ return true;
49
+ // Check parents only if there's a glob
50
+ let lastSlash = str.lastIndexOf("/");
51
+ while (lastSlash !== -1) {
52
+ const parent = str.substring(0, lastSlash);
53
+ if (glob.isMatch(parent, cleaned, matcherOpts))
54
+ return true;
55
+ lastSlash = str.lastIndexOf("/", lastSlash - 1);
56
+ }
57
+ }
58
+ return false;
59
+ },
60
+ };
61
+ return { re, pattern: original, patternContext: context };
62
+ }