view-ignored 0.5.0 → 0.5.2

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 CHANGED
@@ -85,19 +85,32 @@ vign.scan({ target: Git });
85
85
 
86
86
  ## Targets
87
87
 
88
-
89
- The following built-in targets are available:
90
-
91
- - `git`
92
- - `npm` (compatible with Bun, PNPM, and others)
93
- - `yarn`
94
- - `vsce`
95
- - `jsr` (compatible with Deno)
88
+ > [!NOTE]
89
+ > Each scanner expects minimal configurations, but the actual tool can have
90
+ > more/less complex rules. Refer to the documentation of each tool for details.
91
+
92
+ The following built-in scanners are available:
93
+
94
+ - Git
95
+ - Reads `.gitignore` files but does not consider global settings.
96
+ - Check this scanner by running `git ls-tree -r HEAD --name-only`.
97
+ - See the implementation of [Git target](https://github.com/Mopsgamer/view-ignored/tree/main/src/targets/git.ts) for details.
98
+ - NPM (compatible with Bun, PNPM, and others)
99
+ - Reads `.npmignore` and `package.json` `files` field.
100
+ - No additional checks for `name`, `version` or `publishConfig`.
101
+ - Check this scanner by running `npm pack --dry-run`.
102
+ - See the implementation of [NPM target](https://github.com/Mopsgamer/view-ignored/tree/main/src/targets/npm.ts) for details.
103
+ - Yarn
104
+ - Same behavior as `npm`, but also reads `.yarnignore`.
105
+ - See the implementation of [Yarn target](https://github.com/Mopsgamer/view-ignored/tree/main/src/targets/yarn.ts) for details.
106
+ - VSCE
107
+ - Reads `.vscodeignore` and `package.json` `files` field.
108
+ - Check this scanner by running `vsce ls`.
109
+ - See the implementation of [VSCE target](https://github.com/Mopsgamer/view-ignored/tree/main/src/targets/vsce.ts) for details.
110
+ - JSR (compatible with Deno)
111
+ - Reads `jsr.json(c)` and `deno.json(c)` `include` and `exclude` fields.
112
+ - See the implementation of [JSR target](https://github.com/Mopsgamer/view-ignored/tree/main/src/targets/jsr.ts) for details.
96
113
 
97
114
  ## License
98
115
 
99
116
  MIT License. See [LICENSE.txt](LICENSE.txt) for details.
100
-
101
- ## Target implementations
102
- <!-- .ts links -->
103
- See [Target implementations](src/targets/README.md) for details.
@@ -1,3 +1,3 @@
1
- import type { Source } from './matcher.js';
1
+ import { type Source } from './matcher.js';
2
2
  export declare function extractGitignore(source: Source, content: Buffer<ArrayBuffer>): void;
3
3
  export declare function gitignoreMatch(pattern: string, path: string): boolean;
@@ -1,3 +1,4 @@
1
+ import { sourcePushNegatable } from './matcher.js';
1
2
  import { minimatch } from 'minimatch';
2
3
  export function extractGitignore(source, content) {
3
4
  for (let line of content.toString().split('\n')) {
@@ -9,12 +10,7 @@ export function extractGitignore(source, content) {
9
10
  if (cdx >= 0) {
10
11
  line = line.substring(-cdx);
11
12
  }
12
- if (line.startsWith('!')) {
13
- source.pattern.include.push(line.substring(1));
14
- }
15
- else {
16
- source.pattern.exclude.push(line);
17
- }
13
+ sourcePushNegatable(source, line);
18
14
  }
19
15
  // TODO: validate gitignore
20
16
  }
@@ -1,10 +1,41 @@
1
+ /**
2
+ * The results and statistics of a scanning operation.
3
+ */
1
4
  export type MatcherContext = {
5
+ /**
6
+ * `Set` can be sorted, but `view-ignored`
7
+ * does not sort paths.
8
+ * @example
9
+ * new Set(sort(new Set(['a/b', 'a/a'])))
10
+ */
2
11
  paths: Set<string>;
12
+ /**
13
+ * Maps directory paths to their corresponding sources.
14
+ * @example
15
+ * "src" => Source
16
+ */
3
17
  external: Map<string, Source>;
18
+ /**
19
+ * Maps directory paths to the quantity of path segments they contain.
20
+ * @example
21
+ * "src/components" => 2
22
+ */
4
23
  depthPaths: Map<string, number>;
24
+ /**
25
+ * Any errors encountered while processing source files.
26
+ */
5
27
  sourceErrors: Error[];
28
+ /**
29
+ * Total number of files scanned.
30
+ */
6
31
  totalFiles: number;
32
+ /**
33
+ * Total number of files matched by the target.
34
+ */
7
35
  totalMatchedFiles: number;
36
+ /**
37
+ * Total number of directories scanned.
38
+ */
8
39
  totalDirs: number;
9
40
  };
10
41
  /**
@@ -15,6 +46,8 @@ export declare function patternMatches(pattern: Pattern, path: string): boolean;
15
46
  /**
16
47
  * Represents a set of include and exclude patterns.
17
48
  * These patterns are positive minimatch patterns.
49
+ *
50
+ * @see {@link PatternMatcher}
18
51
  */
19
52
  export type SignedPattern = {
20
53
  include: Pattern;
@@ -22,18 +55,60 @@ export type SignedPattern = {
22
55
  };
23
56
  /**
24
57
  * Combined internal and external patterns for matching.
25
- * Used in {@link signedPatternIgnores} function.
58
+ *
59
+ * `exclude` patterns take precedence over `include` patterns.
60
+ *
61
+ * `internal` patterns take precedence over `external` patterns.
62
+ * @see {@link signedPatternIgnores}
26
63
  */
27
64
  export type PatternMatcher = {
28
65
  internal: SignedPattern;
29
66
  external: SignedPattern;
30
67
  };
68
+ /**
69
+ * Checks whether a given path should be ignored based on its patterns.
70
+ * @see {@link findAndExtract}
71
+ * @see {@link signedPatternIgnores}
72
+ * @see {@link https://github.com/Mopsgamer/view-ignored/tree/main/src/targets} for usage examples.
73
+ */
31
74
  export type PathChecker = (path: string, isDir: boolean, ctx: MatcherContext) => Promise<boolean>;
75
+ /**
76
+ * Represents a source of patterns for matching paths.
77
+ */
32
78
  export type Source = {
79
+ /**
80
+ * Patterns defined within the source file.
81
+ * Those patterns are for ignoring files.
82
+ */
33
83
  pattern: SignedPattern;
84
+ /**
85
+ * Name of the source file.
86
+ */
34
87
  name: string;
88
+ /**
89
+ * Indicates if the matching logic is inverted.
90
+ * For example, `package.json` `files` field inverts the matching logic,
91
+ * because it specifies files to include rather than exclude.
92
+ */
35
93
  inverted: boolean;
36
94
  };
95
+ /**
96
+ * Adds a negatable pattern to the source's pattern lists.
97
+ * Strips the leading '!' for include patterns,
98
+ * and adds to exclude patterns otherwise.
99
+ */
100
+ export declare function sourcePushNegatable(source: Source, pattern: string): void;
101
+ /**
102
+ * Populates a `Source` object from the content of a source file.
103
+ * @see {@link Source.pattern} for more details.
104
+ */
37
105
  export type SourceExtractor = (source: Source, content: Buffer<ArrayBuffer>) => void;
106
+ /**
107
+ * Populates the {@link MatcherContext.external} map with {@link Source} objects.
108
+ */
38
109
  export declare function findAndExtract(directory: string, sources: string[], matcher: Map<string, SourceExtractor>, ctx: MatcherContext): Promise<void>;
110
+ /**
111
+ * Checks whether a given file should be ignored based on internal and external patterns.
112
+ * Populates unknown sources using {@link findAndExtract}.
113
+ */
39
114
  export declare function signedPatternIgnores(internal: SignedPattern, file: string, sources: string[], sourceMap: Map<string, SourceExtractor>, ctx: MatcherContext): Promise<boolean>;
@@ -10,6 +10,21 @@ export function patternMatches(pattern, path) {
10
10
  }
11
11
  return false;
12
12
  }
13
+ /**
14
+ * Adds a negatable pattern to the source's pattern lists.
15
+ * Strips the leading '!' for include patterns,
16
+ * and adds to exclude patterns otherwise.
17
+ */
18
+ export function sourcePushNegatable(source, pattern) {
19
+ if (pattern.startsWith('!')) {
20
+ source.pattern.include.push(pattern.substring(1));
21
+ return;
22
+ }
23
+ source.pattern.exclude.push(pattern);
24
+ }
25
+ /**
26
+ * Populates the {@link MatcherContext.external} map with {@link Source} objects.
27
+ */
13
28
  export async function findAndExtract(directory, sources, matcher, ctx) {
14
29
  const keys = [];
15
30
  for (const sourceFileName of sources) {
@@ -74,6 +89,10 @@ export async function findAndExtract(directory, sources, matcher, ctx) {
74
89
  }
75
90
  }
76
91
  }
92
+ /**
93
+ * Checks whether a given file should be ignored based on internal and external patterns.
94
+ * Populates unknown sources using {@link findAndExtract}.
95
+ */
77
96
  export async function signedPatternIgnores(internal, file, sources, sourceMap, ctx) {
78
97
  const parent = dirname(file);
79
98
  let source = ctx.external.get(parent);
@@ -1,3 +1,3 @@
1
1
  import { type } from 'arktype';
2
- import type { Source } from './matcher.js';
2
+ import { type Source } from './matcher.js';
3
3
  export declare function extractPackageJson(source: Source, content: Buffer<ArrayBuffer>): type.errors | undefined;
@@ -1,4 +1,5 @@
1
1
  import { type } from 'arktype';
2
+ import { sourcePushNegatable, } from './matcher.js';
2
3
  const nodeJsManifest = type({
3
4
  files: 'string[]?',
4
5
  });
@@ -12,13 +13,8 @@ export function extractPackageJson(source, content) {
12
13
  if (!dist.files) {
13
14
  return;
14
15
  }
15
- for (const p of dist.files) {
16
- if (p.startsWith('!')) {
17
- source.pattern.exclude.push(...p.substring(1));
18
- }
19
- else {
20
- source.pattern.include.push(...p);
21
- }
16
+ for (const pattern of dist.files) {
17
+ sourcePushNegatable(source, pattern);
22
18
  }
23
19
  return;
24
20
  }
package/out/scan.d.ts CHANGED
@@ -11,7 +11,7 @@ export type ScanOptions = {
11
11
  */
12
12
  cwd?: string;
13
13
  /**
14
- * If enabled, the scan will return files that are ignored by the target matchers.
14
+ * If enabled, the scan will return files that are ignored by the target matcher.
15
15
  */
16
16
  invert?: boolean;
17
17
  /**
@@ -24,8 +24,9 @@ export type ScanOptions = {
24
24
  */
25
25
  signal?: AbortSignal;
26
26
  /**
27
- * If enabled, Depth will be calculated faster by skipping
28
- * other files after first match.
27
+ * Requires depth >= 0.
28
+ * If enabled, directories will be processed faster
29
+ * by skipping files after first match.
29
30
  * This makes the scan faster but affects
30
31
  * {@link MatcherContext.totalDirs},
31
32
  * {@link MatcherContext.totalFiles},
@@ -37,10 +38,12 @@ export type ScanOptions = {
37
38
  /**
38
39
  * Scan the directory for included files based on the provided targets.
39
40
  *
40
- * Note that this function uses `fs/promises.opendir` with recursive option,
41
- * and `fs/promises.readFile`. It also normalizes paths to use forward slashes..
41
+ * Note that this function uses `fs/promises.readFile` and `fs/promises.opendir` without options within
42
+ * custom recursion, instead of `fs.promises.readdir` with `{ withFileTypes: true }.
43
+ * It also normalizes paths to use forward slashes.
44
+ * Please report any issues if you encounter problems related to this behavior.
42
45
  *
43
46
  * @param options Scan options.
44
- * @returns A promise that resolves to a map of targets to their matcher contexts.
47
+ * @returns A promise that resolves to a {@link MatcherContext} containing the scan results.
45
48
  */
46
49
  export declare function scan(options: ScanOptions): Promise<MatcherContext>;
package/out/scan.js CHANGED
@@ -3,14 +3,19 @@ import { opendir } from './walk.js';
3
3
  /**
4
4
  * Scan the directory for included files based on the provided targets.
5
5
  *
6
- * Note that this function uses `fs/promises.opendir` with recursive option,
7
- * and `fs/promises.readFile`. It also normalizes paths to use forward slashes..
6
+ * Note that this function uses `fs/promises.readFile` and `fs/promises.opendir` without options within
7
+ * custom recursion, instead of `fs.promises.readdir` with `{ withFileTypes: true }.
8
+ * It also normalizes paths to use forward slashes.
9
+ * Please report any issues if you encounter problems related to this behavior.
8
10
  *
9
11
  * @param options Scan options.
10
- * @returns A promise that resolves to a map of targets to their matcher contexts.
12
+ * @returns A promise that resolves to a {@link MatcherContext} containing the scan results.
11
13
  */
12
14
  export async function scan(options) {
13
15
  const { target, cwd: cwdo = (await import('node:process')).cwd(), depth: maxDepth = Infinity, invert = false, signal = undefined, fastDepth = false, } = options;
16
+ if (maxDepth < 0) {
17
+ throw new TypeError('Depth must be a non-negative integer');
18
+ }
14
19
  const cwd = cwdo.replaceAll('\\', '/');
15
20
  const ctx = {
16
21
  paths: new Set(),
@@ -22,9 +27,7 @@ export async function scan(options) {
22
27
  totalDirs: 0,
23
28
  };
24
29
  await opendir(cwd, async (entry) => {
25
- if (signal?.aborted) {
26
- return 2;
27
- }
30
+ signal?.throwIfAborted();
28
31
  const path = posix.join(posix.relative(cwd, entry.parentPath.replaceAll('\\', '/')), entry.name);
29
32
  if (entry.isDirectory()) {
30
33
  ctx.totalDirs++;
@@ -77,16 +80,13 @@ export async function scan(options) {
77
80
  }
78
81
  return 0;
79
82
  });
80
- if (signal?.aborted) {
81
- return ctx;
82
- }
83
+ signal?.throwIfAborted();
83
84
  for (const [dir, count] of ctx.depthPaths) {
84
85
  if (count === 0) {
85
86
  continue;
86
87
  }
87
88
  ctx.paths.add(dir + '/');
88
89
  }
89
- console.log(ctx.paths);
90
90
  return ctx;
91
91
  }
92
92
  function getDepth(path, maxDepth) {
@@ -1,4 +1,7 @@
1
1
  import type { PathChecker } from '../patterns/matcher.js';
2
+ /**
3
+ * Contains the matcher used for target scanning.
4
+ */
2
5
  export interface Target {
3
6
  /**
4
7
  * Glob-pattern parser.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "view-ignored",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Retrieve list of files ignored/included by Git, NPM, Yarn, JSR, VSCE or other tools.",
5
5
  "type": "module",
6
6
  "scripts": {