view-ignored 0.10.1 → 0.11.0

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 (68) hide show
  1. package/README.md +116 -62
  2. package/out/browser.d.ts +1 -0
  3. package/out/browser.js +1 -0
  4. package/out/browser_scan.d.ts +1 -3
  5. package/out/browser_scan.js +11 -46
  6. package/out/browser_stream.d.ts +6 -1
  7. package/out/browser_stream.js +6 -1
  8. package/out/index.d.ts +1 -0
  9. package/out/index.js +1 -0
  10. package/out/patterns/extractor.d.ts +7 -7
  11. package/out/patterns/gitignore.d.ts +2 -2
  12. package/out/patterns/gitignore.js +14 -6
  13. package/out/patterns/ignores.d.ts +17 -8
  14. package/out/patterns/index.d.ts +1 -0
  15. package/out/patterns/index.js +1 -0
  16. package/out/patterns/init.d.ts +2 -2
  17. package/out/patterns/initState.d.ts +0 -7
  18. package/out/patterns/jsrjson.d.ts +2 -3
  19. package/out/patterns/jsrjson.js +25 -38
  20. package/out/patterns/matcherContext.d.ts +12 -9
  21. package/out/patterns/matcherContextPatch.js +153 -73
  22. package/out/patterns/matcherStream.d.ts +30 -11
  23. package/out/patterns/matcherStream.js +70 -25
  24. package/out/patterns/packagejson.d.ts +2 -2
  25. package/out/patterns/packagejson.js +11 -14
  26. package/out/patterns/patternCompile.js +35 -37
  27. package/out/patterns/patternList.d.ts +6 -2
  28. package/out/patterns/patternList.js +8 -3
  29. package/out/patterns/resolveSources.d.ts +22 -5
  30. package/out/patterns/resolveSources.js +153 -97
  31. package/out/patterns/resource.d.ts +16 -0
  32. package/out/patterns/resource.js +1 -0
  33. package/out/patterns/rule.d.ts +59 -11
  34. package/out/patterns/rule.js +101 -64
  35. package/out/patterns/source.d.ts +9 -17
  36. package/out/scan.d.ts +11 -3
  37. package/out/scan.js +16 -4
  38. package/out/scanCb.d.ts +16 -0
  39. package/out/scanCb.js +73 -0
  40. package/out/scanParallel.d.ts +18 -0
  41. package/out/scanParallel.js +146 -0
  42. package/out/stream.d.ts +6 -1
  43. package/out/stream.js +7 -2
  44. package/out/targets/bun.js +43 -36
  45. package/out/targets/deno.js +25 -23
  46. package/out/targets/git.js +3 -3
  47. package/out/targets/jsr.js +25 -23
  48. package/out/targets/jsrManifest.d.ts +8 -7
  49. package/out/targets/jsrManifest.js +40 -9
  50. package/out/targets/npm.js +30 -23
  51. package/out/targets/npmManifest.d.ts +18 -46
  52. package/out/targets/npmManifest.js +96 -23
  53. package/out/targets/target.d.ts +8 -16
  54. package/out/targets/vsce.js +20 -27
  55. package/out/targets/vsceManifest.d.ts +7 -0
  56. package/out/targets/vsceManifest.js +18 -0
  57. package/out/targets/yarn.js +48 -39
  58. package/out/targets/yarnClassic.js +20 -18
  59. package/out/types.d.ts +8 -7
  60. package/out/unixify.d.ts +1 -1
  61. package/out/unixify.js +40 -21
  62. package/out/walk.d.ts +42 -4
  63. package/out/walk.js +146 -92
  64. package/package.json +25 -22
  65. package/out/getDepth.d.ts +0 -4
  66. package/out/getDepth.js +0 -21
  67. package/out/opendir.d.ts +0 -3
  68. package/out/opendir.js +0 -28
@@ -1,26 +1,16 @@
1
- import { type } from "arktype";
2
1
  import stripJsonComments from "strip-json-comments";
3
2
  import { ruleCompile } from "./resolveSources.js";
4
3
  import { resolveNegatable } from "./source.js";
5
- const jsrManifest = type({
6
- exclude: "string[]?",
7
- include: "string[]?",
8
- "publish?": {
9
- exclude: "string[]?",
10
- include: "string[]?",
11
- },
12
- });
13
- const parse = type("string")
14
- .pipe((s) => JSON.parse(s))
15
- .pipe(jsrManifest);
16
4
  /**
17
5
  * Extracts and compiles patterns from the file.
18
6
  *
19
7
  * @since 0.6.0
20
8
  */
21
- export function extractJsrJson(source, content, ctx) {
22
- extract(source, content, ctx);
23
- for (const element of source.pattern) {
9
+ export function extractJsrJson(source, content) {
10
+ const result = extract(source, content);
11
+ if (result instanceof Error)
12
+ return result;
13
+ for (const element of source.rules) {
24
14
  ruleCompile(element);
25
15
  }
26
16
  }
@@ -32,39 +22,36 @@ extractJsrJson;
32
22
  *
33
23
  * @since 0.6.0
34
24
  */
35
- export function extractJsrJsonc(source, content, ctx) {
36
- extractJsrJson(source, Buffer.from(stripJsonComments(content.toString())), ctx);
25
+ export function extractJsrJsonc(source, content) {
26
+ return extractJsrJson(source, Buffer.from(stripJsonComments(content.toString())));
37
27
  }
38
28
  extractJsrJsonc;
39
- function extract(source, content, ctx) {
40
- const dist = parse(content.toString());
41
- const include = { compiled: null, excludes: false, pattern: [] };
42
- const exclude = { compiled: null, excludes: true, pattern: [] };
43
- if (dist instanceof type.errors) {
44
- source.error = new Error("Invalid '" + source.path + "': " + dist.summary, { cause: dist });
45
- ctx.failed.push(source);
46
- return;
29
+ function extract(source, content) {
30
+ let dist;
31
+ try {
32
+ dist = JSON.parse(content.toString());
47
33
  }
48
- if (!dist.publish) {
49
- if (dist.exclude) {
50
- exclude.pattern.push(...dist.exclude);
51
- }
34
+ catch (e) {
35
+ return new Error("Invalid JSON in " + source.path, { cause: e });
52
36
  }
53
- else if (dist.publish.exclude) {
54
- exclude.pattern.push(...dist.publish.exclude);
37
+ // Basic runtime check to ensure dist is an object
38
+ if (!dist || typeof dist !== "object" || Array.isArray(dist)) {
39
+ return new Error("Invalid " + source.path + ": Root must be an object");
55
40
  }
56
- if (!dist.publish) {
57
- if (dist.include) {
58
- include.pattern.push(...dist.include);
59
- }
41
+ const include = { compiled: null, excludes: false, pattern: [] };
42
+ const exclude = { compiled: null, excludes: true, pattern: [] };
43
+ // Resolve patterns based on the manifest hierarchy
44
+ const target = dist.publish ?? dist;
45
+ if (target.exclude && Array.isArray(target.exclude)) {
46
+ exclude.pattern.push(...target.exclude);
60
47
  }
61
- else if (dist.publish.include) {
62
- include.pattern.push(...dist.publish.include);
48
+ if (target.include && Array.isArray(target.include)) {
49
+ include.pattern.push(...target.include);
63
50
  }
64
51
  for (const si of [include, exclude]) {
65
52
  for (const pattern of si.pattern) {
66
53
  resolveNegatable(pattern, true, include, exclude);
67
54
  }
68
55
  }
69
- source.pattern.push(include, exclude);
56
+ source.rules.push(include, exclude);
70
57
  }
@@ -1,5 +1,5 @@
1
+ import type { Resource, InvalidSource } from "./resource.js";
1
2
  import type { RuleMatch } from "./rule.js";
2
- import type { Source } from "./source.js";
3
3
  /**
4
4
  * Post-scan results.
5
5
  *
@@ -22,16 +22,16 @@ export interface MatcherContext {
22
22
  *
23
23
  * @since 0.6.0
24
24
  */
25
- external: Map<string, Source | "none">;
25
+ external: Map<string, Resource>;
26
26
  /**
27
27
  * If any fatal errors were encountered during source extractions,
28
28
  * this property will contain an array of failed sources.
29
29
  *
30
30
  * @since 0.6.0
31
31
  */
32
- failed: Source[];
32
+ failed: InvalidSource[];
33
33
  /**
34
- * Maps directory paths to the quantity of files they contain.
34
+ * Total number of files and directories scanned.
35
35
  *
36
36
  * @example
37
37
  * // for
@@ -41,15 +41,18 @@ export interface MatcherContext {
41
41
  * "src/views/index.html"
42
42
  *
43
43
  * // depth: 0
44
- * "src" => 1
44
+ * "." => { totalFiles: 1, totalMatchedFiles: 1, totalDirs: 3 }
45
+ * "src" => { totalFiles: 1, totalMatchedFiles: 1, totalDirs: 2 }
45
46
  *
46
47
  * // depth: 1
47
- * "src/components" => 0
48
- * "src/views" => 1
48
+ * "src/components" => { totalFiles: 0, totalMatchedFiles: 0, totalDirs: 0 }
49
+ * "src/views" => { totalFiles: 1, totalMatchedFiles: 1, totalDirs: 0 }
49
50
  *
50
- * @since 0.6.0
51
+ * @since 0.11.0
51
52
  */
52
- depthPaths: Map<string, number>;
53
+ total: Map<string, Total>;
54
+ }
55
+ export interface Total {
53
56
  /**
54
57
  * Total number of files scanned.
55
58
  *
@@ -1,9 +1,16 @@
1
- import { dirname } from "node:path";
2
- import { getDepth } from "../getDepth.js";
3
- import { opendir } from "../opendir.js";
4
- import { unixify, join } from "../unixify.js";
5
- import { walkIncludes } from "../walk.js";
1
+ import { scanParallel } from "../scanParallel.js";
2
+ import { dirname } from "../unixify.js";
3
+ import { walkPatchResult, walkPatchTotal, propagateTotals, } from "../walk.js";
6
4
  import { resolveSources } from "./resolveSources.js";
5
+ function promiseCb(resolve, reject) {
6
+ return (err, res) => {
7
+ if (err) {
8
+ reject(err);
9
+ return;
10
+ }
11
+ resolve(res);
12
+ };
13
+ }
7
14
  /**
8
15
  * Provides patching abilities for the given {@link MatcherContext}.
9
16
  * Directories should have the slash suffix.
@@ -14,46 +21,110 @@ export async function matcherContextAddPath(ctx, options, entry) {
14
21
  if (ctx.paths.has(entry)) {
15
22
  return false;
16
23
  }
17
- const { target, fs, cwd, signal } = options;
18
24
  const isDir = entry.endsWith("/");
25
+ const direntPath = isDir ? entry.slice(0, -1) : entry;
26
+ if (isDir && direntPath === ".") {
27
+ return true;
28
+ }
29
+ const parentPath = dirname(direntPath);
30
+ const { target, fs, cwd, signal, depth: maxDepth } = options;
19
31
  if (isDir) {
20
32
  // recursive parent population
21
- const direntPath = entry.replace(/\/$/, "");
22
- if (direntPath === ".") {
23
- return true;
33
+ const resource = await new Promise((resolve, reject) => {
34
+ resolveSources({
35
+ cwd,
36
+ dir: direntPath,
37
+ external: ctx.external,
38
+ fs,
39
+ signal,
40
+ target,
41
+ }, promiseCb(resolve, reject));
42
+ });
43
+ ctx.paths.set(entry, await new Promise((resolve, reject) => {
44
+ target.ignores({
45
+ cwd,
46
+ entry: direntPath,
47
+ fs,
48
+ parentPath,
49
+ resource,
50
+ signal,
51
+ target,
52
+ }, promiseCb(resolve, reject));
53
+ }));
54
+ const total = ctx.total.get(parentPath);
55
+ if (!total) {
56
+ ctx.total.set(parentPath, { totalDirs: 1, totalFiles: 0, totalMatchedFiles: 0 });
24
57
  }
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 }));
28
- if (ctx.totalFiles >= 0) {
29
- ctx.totalDirs++;
58
+ else if (total.totalFiles >= 0) {
59
+ total.totalDirs++;
30
60
  }
31
61
  if (parentPath !== ".") {
32
62
  void (await matcherContextAddPath(ctx, options, parentPath + "/"));
33
63
  }
34
64
  return true;
35
65
  }
36
- const parentPath = dirname(entry);
37
66
  const isSource = target.extractors.some((e) => e.path === entry);
38
67
  if (isSource) {
39
68
  // add pattern sources
69
+ const resultPromise = new Promise((resolve, reject) => {
70
+ scanParallel({
71
+ external: ctx.external,
72
+ failed: ctx.failed,
73
+ onResult: (result) => {
74
+ if ("dir" in result) {
75
+ walkPatchTotal(ctx, maxDepth, result);
76
+ }
77
+ else {
78
+ walkPatchResult(ctx, result);
79
+ }
80
+ },
81
+ scanOptions: options,
82
+ stream: undefined,
83
+ within: parentPath,
84
+ }, promiseCb(resolve, reject));
85
+ });
40
86
  await matcherContextRemovePath(ctx, options, parentPath + "/");
41
- await rescan(ctx, { ...options, within: parentPath });
87
+ await resultPromise;
88
+ propagateTotals(ctx.total);
42
89
  }
43
90
  // add paths
44
91
  // 1. recursively populate parents
45
92
  await matcherContextAddPath(ctx, options, parentPath + "/");
46
93
  // 2. if ignored, remove, otherwise add
47
- const match = await target.ignores({ fs, cwd, entry, ctx, signal, target, parentPath });
94
+ const resource = (await new Promise((resolve, reject) => {
95
+ resolveSources({
96
+ cwd,
97
+ dir: parentPath,
98
+ external: ctx.external,
99
+ fs,
100
+ signal,
101
+ target,
102
+ }, promiseCb(resolve, reject));
103
+ }));
104
+ const match = await new Promise((resolve, reject) => {
105
+ target.ignores({
106
+ cwd,
107
+ entry,
108
+ fs,
109
+ parentPath,
110
+ resource,
111
+ signal,
112
+ target,
113
+ }, promiseCb(resolve, reject));
114
+ });
48
115
  if (match.ignored) {
49
116
  // 2.1. remove
50
117
  await matcherContextRemovePath(ctx, options, entry);
51
118
  return false;
52
119
  }
53
120
  // 2.2. add
54
- if (ctx.totalFiles >= 0) {
55
- ctx.totalFiles++;
56
- ctx.totalMatchedFiles++;
121
+ const total = ctx.total.get(parentPath);
122
+ if (!total) {
123
+ ctx.total.set(parentPath, { totalDirs: 0, totalFiles: 1, totalMatchedFiles: 1 });
124
+ }
125
+ else {
126
+ total.totalFiles++;
127
+ total.totalMatchedFiles++;
57
128
  }
58
129
  ctx.paths.set(entry, match);
59
130
  return true;
@@ -66,94 +137,103 @@ export async function matcherContextAddPath(ctx, options, entry) {
66
137
  */
67
138
  export async function matcherContextRemovePath(ctx, options, entry) {
68
139
  const isDir = entry.endsWith("/");
140
+ const direntPath = isDir ? entry.slice(0, -1) : entry;
141
+ if (isDir && direntPath === ".") {
142
+ ctx.paths.clear();
143
+ ctx.external.clear();
144
+ ctx.failed.length = 0;
145
+ ctx.total.set(direntPath, { totalDirs: 0, totalFiles: 0, totalMatchedFiles: 0 });
146
+ return true;
147
+ }
148
+ const parentPath = dirname(direntPath);
149
+ const parentPathDir = parentPath + "/";
69
150
  if (isDir) {
70
151
  // remove directories
71
- const direntPath = entry.replace(/\/$/, "");
152
+ let deletedDirs = 0, deletedFiles = 0;
153
+ const total = ctx.total.get(direntPath);
72
154
  for (const [element] of ctx.paths) {
73
- if (entry !== "./" && !element.startsWith(entry)) {
155
+ if (!element.startsWith(entry)) {
74
156
  continue;
75
157
  }
76
- if (ctx.totalFiles >= 0) {
158
+ if (total && total.totalFiles >= 0) {
77
159
  const isDir = element.endsWith("/");
78
160
  if (isDir) {
79
- ctx.totalDirs--;
161
+ deletedDirs++;
80
162
  }
81
163
  else {
82
- ctx.totalFiles--;
83
- ctx.totalMatchedFiles--;
164
+ deletedFiles++;
84
165
  }
85
166
  }
86
167
  ctx.paths.delete(element);
87
168
  }
88
- for (const [element] of ctx.depthPaths) {
89
- if (entry !== "./" && !element.startsWith(direntPath)) {
169
+ deleteTotals(ctx, entry, deletedDirs, deletedFiles);
170
+ for (const [element] of ctx.external) {
171
+ if (!element.startsWith(direntPath)) {
90
172
  continue;
91
173
  }
92
- ctx.depthPaths.delete(element);
93
- }
94
- for (const [element] of ctx.external) {
95
- if (entry !== "./" && !element.startsWith(direntPath)) {
174
+ if (!ctx.external.delete(element) || !ctx.failed.length) {
96
175
  continue;
97
176
  }
98
- if (ctx.external.delete(element) && ctx.failed.length) {
99
- // 3.1. remove failed sources
100
- const failedEntryIndex = ctx.failed.findIndex((fail) => dirname(fail.path) === element);
101
- if (failedEntryIndex >= 0) {
102
- ctx.failed.splice(failedEntryIndex, 1);
103
- }
177
+ // 3.1. remove failed sources
178
+ const failedEntryIndex = ctx.failed.findIndex((fail) => dirname(fail.source.path) === element);
179
+ if (failedEntryIndex >= 0) {
180
+ ctx.failed.splice(failedEntryIndex, 1);
104
181
  }
105
182
  }
106
183
  return true;
107
184
  }
108
- const parent = dirname(entry);
109
185
  const isSource = options.target.extractors.some((e) => e.path === entry);
110
186
  if (isSource) {
187
+ const maxDepth = options.depth;
111
188
  // remove pattern sources
112
189
  // rescan directory and repopulate stats
113
- await matcherContextRemovePath(ctx, options, parent + "/");
114
- await rescan(ctx, { ...options, within: parent });
190
+ const resultPromise = new Promise((resolve, reject) => {
191
+ scanParallel({
192
+ external: ctx.external,
193
+ failed: ctx.failed,
194
+ onResult: (result) => {
195
+ if ("dir" in result) {
196
+ walkPatchTotal(ctx, maxDepth, result);
197
+ }
198
+ else {
199
+ walkPatchResult(ctx, result);
200
+ }
201
+ },
202
+ scanOptions: options,
203
+ stream: undefined,
204
+ within: parentPath,
205
+ }, promiseCb(resolve, reject));
206
+ });
207
+ await matcherContextRemovePath(ctx, options, parentPathDir);
208
+ await resultPromise;
209
+ propagateTotals(ctx.total);
115
210
  return true;
116
211
  }
117
212
  // remove path
118
213
  // 1. change stats
119
214
  {
120
- if (ctx.totalFiles >= 0) {
121
- ctx.totalFiles--;
122
- ctx.totalMatchedFiles--;
215
+ const total = ctx.total.get(parentPath);
216
+ if (!total) {
217
+ ctx.total.set(parentPath, { totalDirs: 0, totalFiles: 0, totalMatchedFiles: 0 });
123
218
  }
124
- // 1.1 remove depthPaths
125
- const { depthSlash } = getDepth(entry, options.depth);
126
- if (depthSlash >= 0) {
127
- const dir = entry.substring(0, depthSlash);
128
- let num = ctx.depthPaths.get(dir);
129
- if (num) {
130
- num--;
131
- if (num <= 0) {
132
- ctx.depthPaths.delete(dir);
133
- }
134
- else {
135
- ctx.depthPaths.set(dir, num);
136
- }
137
- }
219
+ else if (total.totalFiles >= 0) {
220
+ total.totalFiles--;
221
+ total.totalMatchedFiles--;
138
222
  }
139
223
  }
140
224
  // 2. remove from paths
141
225
  ctx.paths.delete(entry);
142
226
  return true;
143
227
  }
144
- async function rescan(ctx, options) {
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) => {
149
- return walkIncludes({
150
- path,
151
- parentPath,
152
- entry,
153
- ctx,
154
- stream: undefined,
155
- scanOptions: { ...options, cwd: normalCwd },
156
- });
157
- });
158
- ctx.totalDirs = ctx.totalFiles = ctx.totalMatchedFiles = -1;
228
+ function deleteTotals(ctx, entry, deletedDirs = 0, deletedFiles = 0) {
229
+ if (entry.endsWith("/"))
230
+ ctx.total.delete(entry);
231
+ for (let parent = dirname(entry); parent !== "./"; parent = dirname(parent) + "/") {
232
+ const total = ctx.total.get(parent);
233
+ if (!total)
234
+ continue;
235
+ total.totalDirs -= deletedDirs;
236
+ total.totalFiles -= deletedFiles;
237
+ total.totalMatchedFiles -= deletedFiles;
238
+ }
159
239
  }
@@ -1,5 +1,4 @@
1
1
  import type { Dirent } from "node:fs";
2
- import { EventEmitter } from "node:events";
3
2
  import type { MatcherContext } from "../patterns/matcherContext.js";
4
3
  import type { ScanOptions, FsAdapter } from "../types.js";
5
4
  import type { RuleMatch } from "./rule.js";
@@ -27,12 +26,6 @@ export type EntryInfo = {
27
26
  * @since 0.6.0
28
27
  */
29
28
  match: RuleMatch;
30
- /**
31
- * The matcher context.
32
- *
33
- * @since 0.6.0
34
- */
35
- ctx: MatcherContext;
36
29
  };
37
30
  /**
38
31
  * @see {@link MatcherStream} uses it for the "dirent" event.
@@ -52,16 +45,32 @@ export type EndListener = (ctx: MatcherContext) => void;
52
45
  * @since 0.6.0
53
46
  */
54
47
  export type EventMap = {
55
- dirent: [EntryInfo];
56
- end: [MatcherContext];
48
+ dirent: CustomEvent<EntryInfo>;
49
+ end: CustomEvent<MatcherContext>;
57
50
  };
51
+ /**
52
+ * @see {@link MatcherStream} uses it for its event map.
53
+ *
54
+ * @since 0.11.0
55
+ */
56
+ interface EventListener<K extends keyof EventMap> {
57
+ (evt: EventMap[K]): void;
58
+ }
59
+ /**
60
+ * @see {@link MatcherStream} uses it for its event map.
61
+ *
62
+ * @since 0.11.0
63
+ */
64
+ interface EventListenerObject<K extends keyof EventMap> {
65
+ handleEvent(object: EventMap[K]): void;
66
+ }
58
67
  /**
59
68
  * Event emitter.
60
- * @extends EventEmitter
69
+ * @augments EventTarget
61
70
  *
62
71
  * @since 0.6.0
63
72
  */
64
- export declare class MatcherStream extends EventEmitter<EventMap> {
73
+ export declare class MatcherStream extends EventTarget {
65
74
  #private;
66
75
  constructor(options: ScanOptions & {
67
76
  fs: FsAdapter;
@@ -70,10 +79,20 @@ export declare class MatcherStream extends EventEmitter<EventMap> {
70
79
  } & {
71
80
  captureRejections?: boolean;
72
81
  });
82
+ addEventListener<K extends keyof EventMap>(type: K, callback: EventListenerObject<K> | EventListener<K>, options?: boolean | AddEventListenerOptions): void;
83
+ removeEventListener<K extends keyof EventMap>(type: K, callback: EventListenerObject<K> | EventListener<K>, options?: boolean | EventListenerOptions): void;
84
+ dispatchEvent(event: EventMap[keyof EventMap]): boolean;
73
85
  /**
74
86
  * Resolves when everything is scanned.
75
87
  *
76
88
  * @since 0.8.0
77
89
  */
78
90
  start(): Promise<void>;
91
+ /**
92
+ * Resolves when everything is scanned. (Callback version)
93
+ *
94
+ * @since 0.11.0
95
+ */
96
+ startCb(cb: (err: Error | null, ctx: MatcherContext) => void): void;
79
97
  }
98
+ export {};
@@ -1,18 +1,17 @@
1
- import { EventEmitter } from "node:events";
2
- import { opendir } from "../opendir.js";
3
- import { join, unixify } from "../unixify.js";
4
- import { walkIncludes } from "../walk.js";
1
+ import { scanParallel } from "../scanParallel.js";
2
+ import { unixify } from "../unixify.js";
3
+ import { walkPatchResult, walkPatchTotal, propagateTotals } from "../walk.js";
5
4
  /**
6
5
  * Event emitter.
7
- * @extends EventEmitter
6
+ * @augments EventTarget
8
7
  *
9
8
  * @since 0.6.0
10
9
  */
11
- export class MatcherStream extends EventEmitter {
10
+ export class MatcherStream extends EventTarget {
12
11
  #timeout;
13
12
  #options;
14
13
  constructor(options) {
15
- super({ captureRejections: options.captureRejections });
14
+ super();
16
15
  this.#options = options;
17
16
  if (!options.noTimeout) {
18
17
  this.#timeout = setTimeout(() => {
@@ -20,27 +19,48 @@ export class MatcherStream extends EventEmitter {
20
19
  }, 5e3);
21
20
  }
22
21
  }
22
+ addEventListener(type, callback, options) {
23
+ super.addEventListener(type, callback, options);
24
+ }
25
+ removeEventListener(type, callback, options) {
26
+ super.removeEventListener(type, callback, options);
27
+ }
28
+ dispatchEvent(event) {
29
+ return super.dispatchEvent(event);
30
+ }
23
31
  /**
24
32
  * Resolves when everything is scanned.
25
33
  *
26
34
  * @since 0.8.0
27
35
  */
28
- async start() {
36
+ start() {
37
+ const { promise, resolve, reject } = Promise.withResolvers();
38
+ this.startCb((err) => {
39
+ if (err) {
40
+ reject(err);
41
+ return;
42
+ }
43
+ resolve();
44
+ });
45
+ return promise;
46
+ }
47
+ /**
48
+ * Resolves when everything is scanned. (Callback version)
49
+ *
50
+ * @since 0.11.0
51
+ */
52
+ startCb(cb) {
29
53
  clearTimeout(this.#timeout);
30
54
  const { target, cwd, within = ".", invert = false, depth: maxDepth = Infinity, signal = null, fastDepth = false, fastInternal = false, fs, } = this.#options;
31
55
  const ctx = {
32
- paths: new Map(),
33
56
  external: new Map(),
34
57
  failed: [],
35
- depthPaths: new Map(),
36
- totalFiles: 0,
37
- totalMatchedFiles: 0,
38
- totalDirs: 0,
58
+ paths: new Map(),
59
+ total: new Map([[".", { totalDirs: 0, totalFiles: 0, totalMatchedFiles: 0 }]]),
39
60
  };
40
61
  const normalCwd = unixify(cwd);
41
62
  const scanOptions = {
42
63
  cwd: normalCwd,
43
- within,
44
64
  depth: maxDepth,
45
65
  fastDepth,
46
66
  fastInternal,
@@ -48,19 +68,44 @@ export class MatcherStream extends EventEmitter {
48
68
  invert,
49
69
  signal,
50
70
  target,
71
+ within,
51
72
  };
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) => {
55
- return walkIncludes({
56
- path,
57
- parentPath,
58
- entry,
59
- ctx,
60
- stream: this,
73
+ const startScan = () => {
74
+ scanParallel({
75
+ external: ctx.external,
76
+ failed: ctx.failed,
77
+ onResult: (result) => {
78
+ if ("dir" in result) {
79
+ walkPatchTotal(ctx, scanOptions.depth, result);
80
+ }
81
+ else {
82
+ walkPatchResult(ctx, result);
83
+ }
84
+ },
61
85
  scanOptions,
86
+ stream: this,
87
+ within,
88
+ }, (err) => {
89
+ if (err) {
90
+ cb(err, null);
91
+ return;
92
+ }
93
+ propagateTotals(ctx.total);
94
+ cb(null, ctx);
95
+ this.dispatchEvent(new CustomEvent("end", { detail: ctx }));
62
96
  });
63
- });
64
- this.emit("end", ctx);
97
+ };
98
+ if (target.init) {
99
+ target.init({ cwd: normalCwd, fs, signal, target }, (err) => {
100
+ if (err) {
101
+ cb(err, null);
102
+ return;
103
+ }
104
+ startScan();
105
+ });
106
+ }
107
+ else {
108
+ startScan();
109
+ }
65
110
  }
66
111
  }
@@ -6,7 +6,7 @@ import { type Source } from "./source.js";
6
6
  *
7
7
  * @since 0.6.0
8
8
  */
9
- export declare function extractPackageJson(source: Source, content: Buffer): void | "none";
9
+ export declare function extractPackageJson(source: Source, content: Buffer): void | null | Error;
10
10
  /**
11
11
  * Extracts and compiles patterns from the file.
12
12
  *
@@ -14,4 +14,4 @@ export declare function extractPackageJson(source: Source, content: Buffer): voi
14
14
  *
15
15
  * @since 0.8.0
16
16
  */
17
- export declare function extractPackageJsonNocase(source: Source, content: Buffer): void | "none";
17
+ export declare function extractPackageJsonNocase(source: Source, content: Buffer): void | null | Error;