view-ignored 0.2.2 → 0.3.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 (58) hide show
  1. package/README.md +23 -27
  2. package/bin/viewig +3 -1
  3. package/out/src/browser/binds/index.d.ts +40 -21
  4. package/out/src/browser/binds/index.js +62 -48
  5. package/out/src/browser/binds/plugins/git.d.ts +22 -3
  6. package/out/src/browser/binds/plugins/git.js +57 -21
  7. package/out/src/browser/binds/plugins/npm.d.ts +36 -9
  8. package/out/src/browser/binds/plugins/npm.js +125 -59
  9. package/out/src/browser/binds/plugins/vsce.d.ts +24 -8
  10. package/out/src/browser/binds/plugins/vsce.js +56 -16
  11. package/out/src/browser/binds/plugins/yarn.d.ts +5 -10
  12. package/out/src/browser/binds/plugins/yarn.js +18 -68
  13. package/out/src/browser/binds/scanner.d.ts +56 -0
  14. package/out/src/browser/binds/scanner.js +134 -0
  15. package/out/src/browser/binds/targets.d.ts +35 -11
  16. package/out/src/browser/binds/targets.js +10 -17
  17. package/out/src/browser/errors.d.ts +58 -7
  18. package/out/src/browser/errors.js +40 -12
  19. package/out/src/browser/filtering.d.ts +15 -0
  20. package/out/src/browser/filtering.js +12 -0
  21. package/out/src/browser/fs/directory.d.ts +181 -0
  22. package/out/src/browser/fs/directory.js +235 -0
  23. package/out/src/browser/{fileinfo.d.ts → fs/file-info.d.ts} +38 -27
  24. package/out/src/browser/fs/file-info.js +86 -0
  25. package/out/src/browser/fs/file.d.ts +41 -0
  26. package/out/src/browser/fs/file.js +43 -0
  27. package/out/src/browser/fs/index.d.ts +4 -0
  28. package/out/src/browser/fs/index.js +4 -0
  29. package/out/src/browser/fs/source-info.d.ts +29 -0
  30. package/out/src/browser/fs/source-info.js +31 -0
  31. package/out/src/browser/index.d.ts +2 -2
  32. package/out/src/browser/index.js +2 -2
  33. package/out/src/browser/lib.d.ts +102 -101
  34. package/out/src/browser/lib.js +86 -120
  35. package/out/src/browser/sorting.d.ts +22 -2
  36. package/out/src/browser/sorting.js +37 -32
  37. package/out/src/browser/styling.d.ts +41 -15
  38. package/out/src/browser/styling.js +28 -97
  39. package/out/src/cli.d.ts +73 -34
  40. package/out/src/cli.js +308 -155
  41. package/out/src/config.d.ts +163 -65
  42. package/out/src/config.js +285 -171
  43. package/out/src/errors.d.ts +7 -0
  44. package/out/src/errors.js +1 -0
  45. package/out/src/index.d.ts +2 -2
  46. package/out/src/index.js +2 -2
  47. package/out/src/lib.d.ts +4 -4
  48. package/out/src/lib.js +4 -4
  49. package/out/src/styling.d.ts +10 -4
  50. package/out/src/styling.js +46 -33
  51. package/package.json +37 -23
  52. package/out/src/bin.d.ts +0 -2
  53. package/out/src/bin.js +0 -3
  54. package/out/src/browser/fileinfo.js +0 -78
  55. package/out/src/browser/scanner.d.ts +0 -103
  56. package/out/src/browser/scanner.js +0 -161
  57. package/out/src/browser/sourceinfo.d.ts +0 -62
  58. package/out/src/browser/sourceinfo.js +0 -107
@@ -1,99 +1,81 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- import { PatternType } from "./scanner.js";
3
- import { FSOption } from "glob";
4
- import { FileInfo } from "./fileinfo.js";
5
- import { SourceInfo } from "./sourceinfo.js";
6
- import * as FS from "fs";
7
- export * from "./errors.js";
8
- export * from "./scanner.js";
9
- export * from "./fileinfo.js";
10
- export * from "./sourceinfo.js";
11
- export * as Styling from "./styling.js";
12
- export * as Sorting from "./sorting.js";
13
- export * as Plugins from "./binds/index.js";
1
+ import * as PATH from 'node:path';
2
+ import * as FS from 'node:fs';
3
+ import { Directory, File, FileInfo, type DeepStreamEventEmitter, type SourceInfo } from './fs/index.js';
4
+ import { type FilterName } from './filtering.js';
5
+ export * from './errors.js';
6
+ export * from './fs/index.js';
7
+ export * as Filtering from './filtering.js';
8
+ export * as Styling from './styling.js';
9
+ export * as Sorting from './sorting.js';
10
+ export * as Plugins from './binds/index.js';
14
11
  /**
15
- * Contains all filter names.
16
- */
17
- export declare const filterNameList: readonly ["ignored", "included", "all"];
12
+ * ViewIgnored's package.json.
13
+ * @public
14
+ */
15
+ export declare const package_: typeof import("../../package.json");
18
16
  /**
19
- * Contains all filter names as a type.
17
+ * Uses `node:fs` and `node:fs/promises` by default.
18
+ * @public
20
19
  */
21
- export type FilterName = typeof filterNameList[number];
20
+ export type FileSystemAdapter = {
21
+ readFileSync?: typeof FS.readFileSync;
22
+ readdirSync?: typeof FS.readdirSync;
23
+ promises?: {
24
+ readdir(path: string, options: {
25
+ withFileTypes: true;
26
+ }): Promise<FS.Dirent[]>;
27
+ stat(path: string): Promise<FS.Stats>;
28
+ };
29
+ };
22
30
  /**
23
- * Checks if the value is the {@link FilterName}.
31
+ * The custom scanner.
32
+ * @public
24
33
  */
25
- export declare function isFilterName(value: unknown): value is FilterName;
34
+ export type Scanner = {
35
+ /**
36
+ * @returns `true`, if the given path is ignored.
37
+ */
38
+ ignores(path: string): boolean;
39
+ };
26
40
  /**
27
- * Uses `readFileSync` and `readFile`.
28
- * @extends glob.FileSystemAdapter
41
+ * Recursively creates a cache scanner for each file.
42
+ * @throws If the target does not allow the current ignore configurations: {@link ViewIgnoredError}.
43
+ * For example, {@link https://www.npmjs.com/package/@vscode/vsce vsce} considers it invalid if your manifest is missing the 'engines' field.
44
+ * Similarly, npm will raise an error if you attempt to publish a package without a basic 'package.json'.
45
+ * @public
29
46
  */
30
- export interface FileSystemAdapter extends FSOption {
31
- readFileSync?: typeof FS.readFileSync;
32
- readdirSync?: typeof FS.readdirSync;
33
- statSync?: typeof FS.statSync;
34
- }
47
+ export type Methodology = (tree: Directory, realOptions: RealScanOptions) => Map<File, SourceInfo>;
35
48
  /**
36
- * Also can write rules to the {@link Scanner}.
37
- * @returns `true`, if the given source is valid.
49
+ * Options with defaults and additional properties.
50
+ * @public
38
51
  */
39
- export type ScanMethod = (sourceInfo: SourceInfo) => boolean;
52
+ export type RealScanOptions = Required<Omit<ScanOptions, 'fsa'>> & {
53
+ modules: {
54
+ /**
55
+ * File system adapter.
56
+ */
57
+ fs: Required<FileSystemAdapter>;
58
+ /**
59
+ * Path module adapter.
60
+ */
61
+ path: PATH.PlatformPath;
62
+ };
63
+ };
40
64
  /**
41
- * Represents the methodology for reading the target's source.
65
+ * Folder deep scanning options.
66
+ * @public
42
67
  */
43
- export interface Methodology {
44
- /**
45
- * Git configuration property.
46
- * @see {@link https://git-scm.com/docs/git-config#Documentation/git-config.txt-coreignoreCase|git-config ignorecase}.
47
- * @default false
48
- */
49
- ignoreCase?: boolean;
50
- /**
51
- * The parser for the patterns.
52
- * @default "gitignore"
53
- */
54
- matcher: PatternType;
55
- /**
56
- * Use the patterns for including instead of excluding/ignoring.
57
- * @default false
58
- */
59
- matcherNegated?: boolean;
60
- /**
61
- * Additional patterns for files, provided by the {@link pattern}.
62
- *
63
- * Example: You have the '.gitignore' file. You want to scan patterns from it and add additional patterns. Use this property.
64
- * @default []
65
- */
66
- matcherAdd?: string[];
67
- /**
68
- * Force ignore patterns.
69
- * Takes precedence over {@link matcherAdd}.
70
- * @default []
71
- */
72
- matcherExclude?: string[];
73
- /**
74
- * Force include patterns.
75
- * Takes precedence over {@link matcherExclude}.
76
- * @default []
77
- */
78
- matcherInclude?: string[];
68
+ export type ScanOptions = {
79
69
  /**
80
- * First valid source will be used as {@link Scanner}.
70
+ * The target or the scan methodology.
71
+ * @default "git"
81
72
  */
82
- pattern: SourceInfo[] | string[] | SourceInfo | string;
73
+ target?: string | Methodology;
83
74
  /**
84
- * Scanner function. Should return `true`, if the given source is valid and also add patterns to the {@link FileInfo.scanner}.
75
+ * The max concurrency for file-system operations.
76
+ * @default 8
85
77
  */
86
- scan: ScanMethod;
87
- }
88
- /**
89
- * Checks if the value is the {@link Methodology}.
90
- */
91
- export declare function isMethodology(value: unknown): value is Methodology;
92
- /**
93
- * File scanning options.
94
- * @see {@link ScanFolderOptions}
95
- */
96
- export interface ScanFileOptions {
78
+ concurrency?: number;
97
79
  /**
98
80
  * Custom implementation of methods for working with the file system.
99
81
  * @default import * as FS from "fs"
@@ -104,38 +86,57 @@ export interface ScanFileOptions {
104
86
  * @default process.cwd()
105
87
  */
106
88
  cwd?: string;
107
- /**
108
- * Specifies the maximum number of concurrent requests from a reader to read
109
- * directories.
110
- * @default os.cpus().length
111
- */
112
- concurrency?: number;
113
89
  /**
114
90
  * Specifies the maximum depth of a read directory relative to the start
115
91
  * directory.
116
92
  * @default Infinity
117
93
  */
118
94
  maxDepth?: number;
119
- }
120
- /**
121
- * Folder deep scanning options.
122
- * @see {@link ScanFileOptions}
123
- */
124
- export interface ScanFolderOptions extends ScanFileOptions {
95
+ /**
96
+ * On posix systems, this has no effect. But, on Windows, it means that
97
+ * paths will be `/` delimited, and absolute paths will be their full
98
+ * resolved UNC forms, eg instead of `'C:\\foo\\bar'`, it would return
99
+ * `'//?/C:/foo/bar'`
100
+ * @default false
101
+ * @returns `/` delimited paths, even on Windows.
102
+ */
103
+ posix?: boolean;
125
104
  /**
126
105
  * Filter output.
127
106
  * @default "included"
128
107
  */
129
108
  filter?: FilterName | ((fileInfo: FileInfo) => boolean);
130
- }
109
+ };
110
+ /**
111
+ * Gets info about the each file: it is ignored or not.
112
+ * @param directoryPath The relative path to the directory.
113
+ * @throws If no valid sources: {@link ErrorNoSources}.
114
+ * @public
115
+ */
116
+ export declare function scan(directoryPath: string, options?: ScanOptions): Promise<FileInfo[]>;
117
+ /**
118
+ * Gets info about the each file: it is ignored or not.
119
+ * @param directory The current working directory.
120
+ * @throws If no valid sources: {@link ErrorNoSources}.
121
+ * @public
122
+ */
123
+ export declare function scan(directory: Directory, options?: ScanOptions): Promise<FileInfo[]>;
124
+ /**
125
+ * Gets info about the each file: it is ignored or not.
126
+ * @param stream The stream of the current working directory reading.
127
+ * @throws If no valid sources: {@link ErrorNoSources}.
128
+ * @public
129
+ */
130
+ export declare function scan(stream: DeepStreamEventEmitter, options?: ScanOptions): Promise<FileInfo[]>;
131
131
  /**
132
- * Gets info about the file: it is ignored or not.
133
- * @throws {ErrorNoSources} if the source is bad.
132
+ * Gets info about the each file: it is ignored or not.
133
+ * @param pathList The list of relative paths. The should be relative to the current working directory.
134
+ * @throws If no valid sources: {@link ErrorNoSources}.
135
+ * @public
134
136
  */
135
- export declare function scanFile(filePath: string, sources: Methodology[], options: ScanFileOptions): Promise<FileInfo>;
137
+ export declare function scan(pathList: string[], options?: ScanOptions): Promise<FileInfo[]>;
136
138
  /**
137
- * Scans project's directory paths to determine whether they are being ignored.
138
- * @throws {ErrorNoSources} if the source is bad.
139
+ * @returns Options with defaults and additional properties.
140
+ * @public
139
141
  */
140
- export declare function scanProject(sources: Methodology[], options: ScanFolderOptions): Promise<FileInfo[]>;
141
- export declare function scanProject(target: string, options: ScanFolderOptions): Promise<FileInfo[]>;
142
+ export declare function makeOptionsReal(options?: ScanOptions): RealScanOptions;
@@ -1,126 +1,92 @@
1
- import { Scanner, isPatternType } from "./scanner.js";
2
- import { glob } from "glob";
3
- import { FileInfo } from "./fileinfo.js";
4
- import { SourceInfo } from "./sourceinfo.js";
5
- import { targetGet } from "./binds/index.js";
6
- import path from "path";
7
- import { ErrorNoSources, ErrorTargetNotBound } from "./errors.js";
8
- import * as FS from "fs";
9
- export * from "./errors.js";
10
- export * from "./scanner.js";
11
- export * from "./fileinfo.js";
12
- export * from "./sourceinfo.js";
13
- export * as Styling from "./styling.js";
14
- export * as Sorting from "./sorting.js";
15
- export * as Plugins from "./binds/index.js";
1
+ import * as PATH from 'node:path';
2
+ import process from 'node:process';
3
+ import * as FS from 'node:fs';
4
+ import { createRequire } from 'node:module';
5
+ import EventEmitter from 'node:events';
6
+ import pLimit from 'p-limit';
7
+ import { configDefault } from '../config.js';
8
+ import { Directory, File, FileInfo, } from './fs/index.js';
9
+ import { targetGet } from './binds/index.js';
10
+ import { TargetNotBoundError } from './errors.js';
11
+ export * from './errors.js';
12
+ export * from './fs/index.js';
13
+ export * as Filtering from './filtering.js';
14
+ export * as Styling from './styling.js';
15
+ export * as Sorting from './sorting.js';
16
+ export * as Plugins from './binds/index.js';
16
17
  /**
17
- * Contains all filter names.
18
- */
19
- export const filterNameList = ["ignored", "included", "all"];
20
- /**
21
- * Checks if the value is the {@link FilterName}.
22
- */
23
- export function isFilterName(value) {
24
- return typeof value === "string" && filterNameList.includes(value);
25
- }
26
- /**
27
- * Checks if the value is the {@link Methodology}.
28
- */
29
- export function isMethodology(value) {
30
- if (value?.constructor !== Object) {
31
- return false;
32
- }
33
- const v = value;
34
- return isPatternType(v.matcher)
35
- && (typeof v.pattern === "string")
36
- && (v.matcherAdd === undefined || Array.isArray(v.matcherAdd) && v.matcherAdd.every(p => Scanner.patternIsValid(p, { patternType: v.matcher })));
37
- }
38
- /**
39
- * Gets info about the file: it is ignored or not.
40
- * @throws {ErrorNoSources} if the source is bad.
41
- */
42
- export async function scanFile(filePath, sources, options) {
43
- const { fsa = FS, cwd = process.cwd() } = options ?? {};
44
- for (const methodology of sources) {
45
- const sourceInfoList = await SourceInfo.fromMethodology(methodology, options);
46
- for (const sourceInfo of sourceInfoList) {
47
- sourceInfo.readSync(cwd, fsa.readFileSync ?? FS.readFileSync);
48
- const isGoodSource = methodology.scan(sourceInfo);
49
- if (isGoodSource) {
50
- return FileInfo.from(filePath, sourceInfo);
51
- }
52
- }
53
- }
54
- throw new ErrorNoSources(sources);
55
- }
56
- export async function scanProject(arg1, options) {
57
- if (typeof arg1 === "string") {
58
- const bind = targetGet(arg1);
18
+ * ViewIgnored's package.json.
19
+ * @public
20
+ */
21
+ // eslint-disable-next-line @typescript-eslint/consistent-type-imports
22
+ export const package_ = createRequire(import.meta.url)('../../package.json');
23
+ export async function scan(argument0, options) {
24
+ options ??= {};
25
+ const optionsReal = makeOptionsReal(options);
26
+ if (typeof optionsReal.target === 'string') {
27
+ const bind = targetGet(optionsReal.target);
59
28
  if (bind === undefined) {
60
- throw new ErrorTargetNotBound(arg1);
29
+ throw new TargetNotBoundError(optionsReal.target);
61
30
  }
62
- return scanProject(bind.methodology, Object.assign(options, bind.scanOptions));
31
+ return scan(argument0, Object.assign(options, bind.scanOptions));
63
32
  }
64
- const allFilePaths = await glob("**", {
65
- ...options,
66
- nodir: true,
67
- dot: true,
68
- posix: true,
69
- });
70
- // Find good source.
71
- const { filter = "included", fsa = FS, cwd = process.cwd() } = options;
72
- for (const methodology of arg1) {
73
- const resultList = [];
74
- const sourceInfoList = await SourceInfo.fromMethodology(methodology, options);
75
- if (sourceInfoList.length < 1) {
76
- continue;
77
- }
78
- const cache = new Set();
79
- let noSource = false;
80
- for (const filePath of allFilePaths) {
81
- if (cache.has(filePath)) {
82
- continue;
83
- }
84
- const sourceInfo = SourceInfo.hierarcy(filePath, sourceInfoList, {
85
- closest: false,
86
- filter(sourceInfo) {
87
- if (!(sourceInfo instanceof SourceInfo)) {
88
- return true;
89
- }
90
- if (sourceInfo.content === undefined) {
91
- sourceInfo.readSync(cwd, fsa.readFileSync ?? FS.readFileSync);
92
- }
93
- return methodology.scan(sourceInfo);
94
- }
95
- });
96
- if (sourceInfo === undefined) {
97
- noSource = true;
98
- break;
99
- }
100
- // also create cache for each file in the direcotry
101
- const fileDir = path.dirname(filePath);
102
- const fileDirAbsolute = path.join(cwd, fileDir);
103
- const entryList = (fsa?.readdirSync ?? FS.readdirSync)(fileDirAbsolute);
104
- for (const entry of entryList) {
105
- const entryPath = path.join(fileDir, entry);
106
- const entryPathNormal = fileDir !== '.' ? fileDir + '/' + entry : entry;
107
- const entryPathAbsolute = path.join(cwd, entryPath);
108
- const stat = (fsa?.statSync ?? FS.statSync)(entryPathAbsolute);
109
- cache.add(entryPathNormal);
110
- if (stat.isFile()) {
111
- // push new FileInfo
112
- const fileInfo = FileInfo.from(entryPathNormal, sourceInfo);
113
- if (fileInfo.isIncludedBy(filter)) {
114
- resultList.push(fileInfo);
115
- }
116
- }
33
+ if (typeof argument0 === 'string') {
34
+ const stream = Directory.deepStream(argument0, optionsReal);
35
+ const result = scan(stream, options);
36
+ stream.run();
37
+ return result;
38
+ }
39
+ if (Array.isArray(argument0)) {
40
+ const tree = Directory.from(argument0, optionsReal.cwd);
41
+ return scan(tree, options);
42
+ }
43
+ if (argument0 instanceof EventEmitter) {
44
+ const { tree } = await argument0.endPromise;
45
+ return scan(tree, options);
46
+ }
47
+ const tree = argument0;
48
+ const cache = optionsReal.target(tree, optionsReal);
49
+ const fileInfoList = [];
50
+ const promiseList = [];
51
+ const cacheDirectories = new Map();
52
+ for (const directory of [tree].concat(tree.deep(Directory))) {
53
+ cacheDirectories.set(directory, pLimit(optionsReal.concurrency));
54
+ }
55
+ for (const entry of tree.deepIterator(File)) {
56
+ const limit = cacheDirectories.get(entry.parent);
57
+ promiseList.push(limit(async () => {
58
+ const sourceInfo = cache.get(entry);
59
+ const fileInfo = FileInfo.from(entry, sourceInfo);
60
+ const ignored = !fileInfo.isIncludedBy(optionsReal.filter);
61
+ if (ignored) {
62
+ return;
117
63
  }
118
- } // forend
119
- if (noSource) {
120
- continue;
121
- }
122
- return resultList;
123
- } // forend
124
- throw new ErrorNoSources(arg1);
64
+ fileInfoList.push(fileInfo);
65
+ }));
66
+ }
67
+ await Promise.all(promiseList);
68
+ return fileInfoList;
69
+ }
70
+ /**
71
+ * @returns Options with defaults and additional properties.
72
+ * @public
73
+ */
74
+ export function makeOptionsReal(options) {
75
+ options ??= {};
76
+ const posix = options.posix ?? false;
77
+ const concurrency = options.concurrency ?? configDefault.concurrency;
78
+ const optionsReal = {
79
+ concurrency,
80
+ target: options.target ?? 'git',
81
+ cwd: options.cwd ?? process.cwd(),
82
+ filter: options.filter ?? configDefault.filter,
83
+ modules: {
84
+ fs: (options.fsa ?? FS),
85
+ path: posix ? PATH.posix : PATH,
86
+ },
87
+ maxDepth: options.maxDepth ?? configDefault.depth,
88
+ posix,
89
+ };
90
+ return optionsReal;
125
91
  }
126
- //#endregion
92
+ // #endregion
@@ -1,41 +1,61 @@
1
1
  /**
2
2
  * Contains all file sort names.
3
+ * @public
3
4
  */
4
5
  export declare const sortNameList: readonly ["firstFolders", "firstFiles", "type", "mixed", "modified"];
5
6
  /**
6
7
  * Contains all file sort names as a type.
8
+ * @public
7
9
  */
8
10
  export type SortName = typeof sortNameList[number];
9
11
  /**
10
12
  * {@link Array.prototype.sort}'s file path comparator.
13
+ * @public
11
14
  */
12
- export type SortFunc = (a: string, b: string) => number;
15
+ export type SortFunction = (a: string, b: string) => number;
13
16
  /**
14
17
  * Checks if the value is the {@link SortName}.
18
+ * @public
15
19
  */
16
20
  export declare function isSortName(value: unknown): value is SortName;
21
+ /**
22
+ * @public
23
+ * @example
24
+ * "path/to/the/file" -> ["path", "to/the/file", false]
25
+ * "file" -> ["file", "file", true]
26
+ * "file/" -> ["file", "", false]
27
+ */
28
+ export declare function shiftPath(p: string): [next: string, other: string, isLast: boolean];
17
29
  /**
18
30
  * Files and folders are sorted by their names.
19
31
  * Folders are displayed before files.
32
+ * @public
20
33
  */
21
34
  export declare function firstFolders(a: string, b: string): number;
22
35
  /**
23
36
  * Files and folders are sorted by their names.
24
37
  * Files are displayed before folders.
38
+ * @public
25
39
  */
26
40
  export declare function firstFiles(a: string, b: string): number;
27
41
  /**
28
42
  * Files and folders are sorted by last modified date in descending order.
29
43
  * Folders are displayed before files.
44
+ * @see {@link makeMtimeCache}
45
+ * @public
30
46
  */
31
- export declare function modified(a: string, b: string, map: Map<string, number>): number;
47
+ export declare function modified(a: string, b: string, map: Map<{
48
+ toString(): string;
49
+ }, number>): number;
32
50
  /**
33
51
  * Files and folders are grouped by extension type then sorted by thir names.
34
52
  * Folders are displayed before files.
53
+ * @public
35
54
  */
36
55
  export declare function type(a: string, b: string): number;
37
56
  /**
38
57
  * Files and folders are sorted by their names.
39
58
  * Files are interwoven with folders.
59
+ * @public
40
60
  */
41
61
  export declare function mixed(a: string, b: string): number;