UNPKG

2.84 kBPlain TextView Raw
1import { fromSysPath, toPosixPath } from "furi";
2import minimatch from "minimatch";
3import { ParsedScriptUrl, parseSys as parseNodeScriptUrl } from "node-script-url";
4import sysPath from "path";
5import url from "url";
6
7export interface ModuleInfo {
8 url: string;
9 isModule?: boolean;
10}
11
12export type CoverageFilter = (info: ModuleInfo) => boolean;
13
14export interface FromGlobOptions {
15 patterns: ReadonlyArray<string>;
16
17 /**
18 * Base file URL for relative patterns.
19 */
20 base?: url.URL;
21}
22
23interface FuriMatch {
24 type: "negative" | "positive";
25 regexp: RegExp;
26}
27
28export function fromGlob(options: FromGlobOptions): CoverageFilter {
29 let basePath: string | undefined;
30 if (options.base !== undefined) {
31 basePath = toPosixPath(options.base.href);
32 }
33
34 const matches: FuriMatch[] = [];
35 const patterns: ReadonlyArray<string> = [...options.patterns, "**/*"];
36 for (const pattern of patterns) {
37 let absPattern: string;
38 let type: "negative" | "positive";
39 if (pattern.startsWith("!")) {
40 absPattern = pattern.substr(1);
41 type = "negative";
42 } else {
43 absPattern = pattern;
44 type = "positive";
45 }
46 const resolvedPattern: string = basePath !== undefined ? sysPath.resolve(basePath, absPattern) : absPattern;
47 matches.push({
48 type,
49 regexp: minimatch.makeRe(resolvedPattern, {dot: true}),
50 });
51 // Fix bad wildstar conversion to RegExp
52 if (absPattern.startsWith("**/")) {
53 const patternTail: string = absPattern.substr("**/".length);
54 const resolvedPattern: string = basePath !== undefined ? sysPath.resolve(basePath, patternTail) : patternTail;
55 matches.push({
56 type,
57 regexp: minimatch.makeRe(resolvedPattern, {dot: true}),
58 });
59 }
60 }
61
62 return function filter(info: ModuleInfo): boolean {
63 if (!isRegularFile(info)) {
64 return false;
65 }
66 const posixPath: string = toPosixPath(info.url);
67 for (const match of matches) {
68 if (match.regexp.test(posixPath)) {
69 return match.type === "positive";
70 }
71 }
72 return false;
73 };
74}
75
76export function isRegularFile(info: ModuleInfo): boolean {
77 return parseNodeScriptUrl(info.url).isFileUrl;
78}
79
80function inCwd(info: ModuleInfo): boolean {
81 const scriptUrl: ParsedScriptUrl = parseNodeScriptUrl(info.url);
82 if (!scriptUrl.isFileUrl) {
83 return false;
84 }
85 const cwdFuri: string = fromSysPath(sysPath.resolve(process.cwd())).href;
86 return isDescendantOf(scriptUrl.url, cwdFuri);
87}
88
89function isDescendantOf(curUrl: string, ancestorUrl: string): boolean {
90 const cur: ReadonlyArray<string> = new url.URL(curUrl).pathname.split("/");
91 const ancestor: ReadonlyArray<string> = new url.URL(ancestorUrl).pathname.split("/");
92 for (const [i, segment] of ancestor.entries()) {
93 if (cur[i] !== segment) {
94 return false;
95 }
96 }
97 return true;
98}