-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathast.ts
81 lines (73 loc) · 2.32 KB
/
ast.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
import ts from "https://esm.sh/[email protected]";
import * as path from "./vendor/https/deno.land/std/path/mod.ts";
const dec = new TextDecoder("utf-8");
export async function hasDefaultExportLocal(
filePath: string,
): Promise<boolean> {
const body = dec.decode(await Deno.readFile(filePath));
return hasDefaultExport(body);
}
export async function hasDefaultExportRemote(url: string): Promise<boolean> {
const res = await fetch(url, { redirect: "follow" });
const body = await res.text();
return hasDefaultExport(body);
}
export function hasDefaultExport(body: string): boolean {
const sourceFile = ts.createSourceFile("", body, ts.ScriptTarget.ES2020);
let hasDefault = false;
sourceFile.forEachChild((node: ts.Node) => {
hasDefault = hasDefault || node.kind === ts.SyntaxKind.ExportAssignment;
});
return hasDefault;
}
function removeQuotes(s: string): string {
return s.replace(/[\'\"\`]/g, "");
}
const crawlImport = (filePaths: string[], sourceFile: ts.SourceFile) =>
(
node: ts.Node,
) => {
if (node.kind === ts.SyntaxKind.ImportDeclaration) {
node.forEachChild((child: ts.Node) => {
if (child.kind === ts.SyntaxKind.StringLiteral) {
filePaths.push(removeQuotes(child.getText(sourceFile)));
}
});
}
};
async function getImportFilePaths(
dirName: string,
excludes: string[],
): Promise<string[]> {
const filePaths: string[] = [];
for await (const f of Deno.readDir(dirName)) {
if (!f.name) {
continue;
}
if (f.isFile && f.name.match(/\.(js|ts)x?$/)) {
const body = await Deno.readFile(path.join(dirName, f.name));
const sourceFile = ts.createSourceFile(
f.name,
dec.decode(body),
ts.ScriptTarget.ES2020,
);
sourceFile.forEachChild(crawlImport(filePaths, sourceFile));
} else if (f.isDirectory && !excludes.includes(f.name)) {
const result = await getImportFilePaths(
path.join(dirName, f.name),
excludes,
);
filePaths.push(...result);
}
}
return filePaths;
}
export async function getFormattedImportFilePaths(
dirName: string,
excludes: string[],
): Promise<string[]> {
return (await getImportFilePaths(dirName, excludes))
.filter((f) => f.match(/vendor/))
.map((f) => f.replace(/^.+vendor\//, ""))
.map((f) => f.replace(/\//, "://"));
}