-
Notifications
You must be signed in to change notification settings - Fork 0
/
scanner.ts
93 lines (81 loc) · 2.5 KB
/
scanner.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import process from "node:process";
import { globbyStream, Options as GlobbyGlobOptions } from "globby";
import { read } from "to-vfile";
import type { VFile } from "vfile";
import { mdDefaultFileExts, mdDefaultType } from "./filetypes.js";
import type { MarkdownType } from "./markdown/types";
import { scanFileForLinks as scanMdFile } from "./markdown/link.js";
import type { Link } from "./types";
export interface ScanOptions {
readonly basePath: string;
readonly caseSensitive: boolean;
readonly mdType: MarkdownType;
readonly mdFileExts: ReadonlySet<string>;
readonly globConcurrency: number;
readonly useGitignore: boolean;
readonly ignoreFiles: ReadonlyArray<string>;
}
export interface ScanResult {
readonly file: VFile;
readonly links: IterableIterator<Link>;
}
const scanOptionsDefaults: ScanOptions = {
basePath: ".",
mdType: mdDefaultType,
mdFileExts: mdDefaultFileExts,
caseSensitive: false,
globConcurrency: 0,
useGitignore: false,
ignoreFiles: [],
};
interface GlobOptions extends GlobbyGlobOptions {
readonly cwd: string;
}
// Small wrapper around globby to yield VFile objects
async function* readGlob(
patterns: ReadonlyArray<string>,
options: GlobOptions,
): AsyncGenerator<VFile> {
const filePaths = globbyStream(patterns, options);
for await (const filePath of filePaths) {
yield read({ cwd: options.cwd, path: String(filePath) });
}
}
export async function* scanFiles(
includeGlobs: ReadonlyArray<string>,
excludeGlobs: ReadonlyArray<string>,
options?: Partial<ScanOptions>,
): AsyncGenerator<ScanResult> {
const mergedOptions: ScanOptions = {
...scanOptionsDefaults,
basePath: process.cwd(),
...options,
};
// The intent is clearer with a plain slice.
/* eslint-disable unicorn/prefer-spread */
const globOptions: GlobOptions = {
cwd: mergedOptions.basePath,
ignore: excludeGlobs.slice(),
caseSensitiveMatch: mergedOptions.caseSensitive,
onlyFiles: true,
gitignore: mergedOptions.useGitignore,
ignoreFiles: mergedOptions.ignoreFiles,
};
/* eslint-enable unicorn/prefer-spread */
if (mergedOptions.globConcurrency > 0) {
globOptions.concurrency = mergedOptions.globConcurrency;
}
const glob = readGlob(includeGlobs, globOptions);
for await (const file of glob) {
const fileExt = file.extname;
if (!fileExt) {
continue;
}
if (mergedOptions.mdFileExts.has(fileExt)) {
yield {
file,
links: scanMdFile(file, { mdType: mergedOptions.mdType }),
};
}
}
}