view-ignored 0.10.0 → 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.
- package/README.md +3 -1
- package/out/browser_scan.js +2 -2
- package/out/opendir.d.ts +3 -3
- package/out/opendir.js +18 -12
- package/out/patterns/ignores.d.ts +6 -0
- package/out/patterns/matcherContextPatch.js +16 -13
- package/out/patterns/matcherStream.js +2 -2
- package/out/patterns/patternCompile.js +47 -16
- package/out/patterns/patternList.d.ts +7 -5
- package/out/patterns/patternList.js +0 -1
- package/out/patterns/rule.d.ts +7 -1
- package/out/patterns/rule.js +5 -7
- package/out/walk.d.ts +1 -0
- package/out/walk.js +11 -3
- package/package.json +3 -2
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
|
-
- **
|
|
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"`.
|
package/out/browser_scan.js
CHANGED
|
@@ -43,11 +43,11 @@ export function scan(options) {
|
|
|
43
43
|
return (async () => {
|
|
44
44
|
await target.init?.({ ctx, cwd, fs, signal, target });
|
|
45
45
|
let from = join(normalCwd, within);
|
|
46
|
-
await opendir(fs, from, (entry,
|
|
47
|
-
const path = from.substring(normalCwd.length + 1);
|
|
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
|
|
2
|
-
import type {
|
|
3
|
-
export declare function opendir(
|
|
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,22 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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);
|
|
3
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;
|
|
4
12
|
for await (const entry of dir) {
|
|
5
|
-
const from =
|
|
13
|
+
const from = place + "/" + entry.name;
|
|
14
|
+
const path = isRootDir ? entry.name : substr + "/" + entry.name;
|
|
6
15
|
const task = (async () => {
|
|
7
|
-
const r = await cb(entry,
|
|
8
|
-
if (r === 2)
|
|
9
|
-
return 2;
|
|
16
|
+
const r = await cb(entry, parentPath, path);
|
|
10
17
|
if (r === 1)
|
|
11
18
|
return;
|
|
12
|
-
if (entry.isDirectory()) {
|
|
13
|
-
|
|
19
|
+
if (r === 2 || (entry.isDirectory() && (await opendir(options, from, cb)))) {
|
|
20
|
+
stop = true;
|
|
21
|
+
return;
|
|
14
22
|
}
|
|
15
23
|
})();
|
|
16
24
|
tasks.push(task);
|
|
17
25
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return 2;
|
|
21
|
-
}
|
|
26
|
+
await Promise.all(tasks);
|
|
27
|
+
return stop;
|
|
22
28
|
}
|
|
@@ -12,6 +12,12 @@ 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.
|
|
@@ -3,6 +3,7 @@ import { getDepth } from "../getDepth.js";
|
|
|
3
3
|
import { opendir } from "../opendir.js";
|
|
4
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
|
-
|
|
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
|
-
|
|
29
|
-
|
|
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
|
|
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,
|
|
39
|
-
await rescan(ctx, { ...options, within:
|
|
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,
|
|
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, target });
|
|
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,12 +142,13 @@ export async function matcherContextRemovePath(ctx, options, entry) {
|
|
|
140
142
|
return true;
|
|
141
143
|
}
|
|
142
144
|
async function rescan(ctx, options) {
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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) => {
|
|
147
149
|
return walkIncludes({
|
|
148
150
|
path,
|
|
151
|
+
parentPath,
|
|
149
152
|
entry,
|
|
150
153
|
ctx,
|
|
151
154
|
stream: undefined,
|
|
@@ -51,10 +51,10 @@ export class MatcherStream extends EventEmitter {
|
|
|
51
51
|
};
|
|
52
52
|
await target.init?.({ ctx, cwd, fs, signal, target });
|
|
53
53
|
let from = join(normalCwd, within);
|
|
54
|
-
await opendir(fs, from, (entry,
|
|
55
|
-
const path = from.substring(normalCwd.length + 1);
|
|
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,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import glob from "micromatch";
|
|
2
2
|
/**
|
|
3
3
|
* Compiles a string of the {@link PatternList}.
|
|
4
4
|
*
|
|
@@ -8,24 +8,55 @@ import { makeRe } from "minimatch";
|
|
|
8
8
|
*/
|
|
9
9
|
export function patternCompile(pattern, context = [], options) {
|
|
10
10
|
const original = pattern;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const re = makeRe(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 = {
|
|
24
23
|
dot: true,
|
|
25
24
|
nonegate: true,
|
|
26
25
|
nocomment: true,
|
|
27
26
|
nobrace: true,
|
|
28
|
-
nocase
|
|
29
|
-
|
|
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
|
+
};
|
|
30
61
|
return { re, pattern: original, patternContext: context };
|
|
31
62
|
}
|
|
@@ -9,19 +9,21 @@ import { type PatternCompileOptions } from "./patternCompile.js";
|
|
|
9
9
|
*/
|
|
10
10
|
export type PatternCache = {
|
|
11
11
|
/**
|
|
12
|
-
* The regular expression
|
|
12
|
+
* The regular expression interface.
|
|
13
13
|
*
|
|
14
14
|
* @since 0.6.0
|
|
15
15
|
*/
|
|
16
|
-
re:
|
|
16
|
+
re: {
|
|
17
|
+
test(string: string): boolean;
|
|
18
|
+
};
|
|
17
19
|
/**
|
|
18
|
-
* The original pattern string this
|
|
20
|
+
* The original pattern string this cache was compiled from.
|
|
19
21
|
*
|
|
20
22
|
* @since 0.6.0
|
|
21
23
|
*/
|
|
22
24
|
pattern: string;
|
|
23
25
|
/**
|
|
24
|
-
* The original pattern list this
|
|
26
|
+
* The original pattern list this cache was compiled from.
|
|
25
27
|
*
|
|
26
28
|
* @since 0.6.0
|
|
27
29
|
*/
|
|
@@ -34,7 +36,7 @@ export type PatternCache = {
|
|
|
34
36
|
*/
|
|
35
37
|
export declare function patternCacheTest(cache: PatternCache, path: string): boolean;
|
|
36
38
|
/**
|
|
37
|
-
* Represents a list of positive
|
|
39
|
+
* Represents a list of positive glob patterns.
|
|
38
40
|
*
|
|
39
41
|
* @since 0.6.0
|
|
40
42
|
*/
|
package/out/patterns/rule.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { Source } from "./source.js";
|
|
|
3
3
|
import { type PatternList, type PatternCache } from "./patternList.js";
|
|
4
4
|
/**
|
|
5
5
|
* Represents a set of include and exclude patterns.
|
|
6
|
-
* These patterns are positive
|
|
6
|
+
* These patterns are positive glob patterns.
|
|
7
7
|
*
|
|
8
8
|
* @see {@link ruleTest} provides the ignoring algorithm.
|
|
9
9
|
* @see {@link ruleCompile} compiles the signed pattern.
|
|
@@ -105,6 +105,12 @@ export interface RuleTestOptions extends PatternFinderOptions {
|
|
|
105
105
|
* @since 0.6.0
|
|
106
106
|
*/
|
|
107
107
|
entry: string;
|
|
108
|
+
/**
|
|
109
|
+
* Result of the `dirname(entry)` call.
|
|
110
|
+
*
|
|
111
|
+
* @since 0.10.1
|
|
112
|
+
*/
|
|
113
|
+
parentPath: string;
|
|
108
114
|
}
|
|
109
115
|
/**
|
|
110
116
|
* Checks whether a given entry should be ignored based on internal and external patterns.
|
package/out/patterns/rule.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { dirname } from "node:path/posix";
|
|
2
1
|
import { patternCacheTest } from "./patternList.js";
|
|
3
|
-
import { resolveSources } from "./resolveSources.js";
|
|
4
2
|
function cacheTest(rs, path) {
|
|
5
3
|
for (const r of rs) {
|
|
6
4
|
try {
|
|
@@ -73,12 +71,12 @@ function testExternal(options, path, source) {
|
|
|
73
71
|
* @since 0.6.0
|
|
74
72
|
*/
|
|
75
73
|
export async function ruleTest(options) {
|
|
76
|
-
const parent =
|
|
74
|
+
const parent = options.parentPath;
|
|
77
75
|
let source = options.ctx?.external.get(parent);
|
|
78
|
-
if (source === undefined) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
76
|
+
// if (source === undefined) {
|
|
77
|
+
// await resolveSources({ ...options, dir: parent })
|
|
78
|
+
// source = options.ctx.external.get(parent)
|
|
79
|
+
// }
|
|
82
80
|
if (source === undefined) {
|
|
83
81
|
throw new Error("view-ignored has crashed: no source cached.");
|
|
84
82
|
}
|
package/out/walk.d.ts
CHANGED
package/out/walk.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getDepth } from "./getDepth.js";
|
|
2
2
|
export async function walkIncludes(options) {
|
|
3
|
-
const { entry, ctx, stream, scanOptions, path } = options;
|
|
3
|
+
const { entry, ctx, stream, scanOptions, path, parentPath } = options;
|
|
4
4
|
const { fs, target, cwd, depth: maxDepth, invert, signal, fastDepth, fastInternal } = scanOptions;
|
|
5
5
|
signal?.throwIfAborted();
|
|
6
6
|
const isDir = entry.isDirectory();
|
|
@@ -17,7 +17,7 @@ export async function walkIncludes(options) {
|
|
|
17
17
|
const { depth, depthSlash } = getDepth(path, maxDepth);
|
|
18
18
|
if (depth > maxDepth) {
|
|
19
19
|
const failedPrev = ctx.failed.length;
|
|
20
|
-
let match = await target.ignores({ fs, cwd, entry: path, ctx, signal, target });
|
|
20
|
+
let match = await target.ignores({ fs, cwd, entry: path, ctx, signal, target, parentPath });
|
|
21
21
|
if (invert) {
|
|
22
22
|
match.ignored = !match.ignored;
|
|
23
23
|
}
|
|
@@ -45,7 +45,15 @@ export async function walkIncludes(options) {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
const failedPrev = ctx.failed.length;
|
|
48
|
-
let match = await target.ignores({
|
|
48
|
+
let match = await target.ignores({
|
|
49
|
+
fs,
|
|
50
|
+
cwd,
|
|
51
|
+
entry: path,
|
|
52
|
+
ctx,
|
|
53
|
+
signal,
|
|
54
|
+
target,
|
|
55
|
+
parentPath: parentPath,
|
|
56
|
+
});
|
|
49
57
|
if (invert) {
|
|
50
58
|
match.ignored = !match.ignored;
|
|
51
59
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "view-ignored",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "Retrieve list of files ignored/included by Git, NPM, Yarn, JSR, VSCE or other tools.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
".gitignore",
|
|
@@ -97,13 +97,14 @@
|
|
|
97
97
|
},
|
|
98
98
|
"dependencies": {
|
|
99
99
|
"arktype": "^2.1.29",
|
|
100
|
-
"
|
|
100
|
+
"micromatch": "^4.0.8",
|
|
101
101
|
"strip-json-comments": "^5.0.3"
|
|
102
102
|
},
|
|
103
103
|
"devDependencies": {
|
|
104
104
|
"@release-it/keep-a-changelog": "^7.0.1",
|
|
105
105
|
"@types/bun": "^1.3.9",
|
|
106
106
|
"@types/ignore-walk": "^4.0.3",
|
|
107
|
+
"@types/micromatch": "^4.0.10",
|
|
107
108
|
"@types/node": "^18.19.130",
|
|
108
109
|
"@typescript/native-preview": "^7.0.0-dev.20260223.1",
|
|
109
110
|
"ignore-walk": "^8.0.0",
|