Skip to content
Source
Sign inSign up
Open History to see the last commit

cli-executable-imports.ts

37 lines1.4 KB

1// @effect-diagnostics nodeBuiltinImport:off
2import * as NodeModule from "node:module";
3import ts from "typescript-legacy";
4​
5/** Node single-executable imports resolve only builtins; use createRequire for file-backed external packages. */
6export function findEsmImportsOfExternalPackages(source: string): ReadonlyArray<string> {
7 const specifiers = new Set<string>();
8 const module = ts.createSourceFile(
9 "bundle.mjs",
10 source,
11 ts.ScriptTarget.Latest,
12 false,
13 ts.ScriptKind.JS,
14 );
15 const visit = (node: ts.Node): void => {
16 const dynamic =
17 ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword;
18 const specifierNode =
19 ts.isImportDeclaration(node) || ts.isExportDeclaration(node)
20 ? node.moduleSpecifier
21 : dynamic
22 ? node.arguments[0]
23 : undefined;
24 if (specifierNode && ts.isStringLiteralLike(specifierNode)) {
25 const specifier = specifierNode.text;
26 // Optional Bun imports are runtime builtins; static Bun imports still fail under Node.
27 const runtimeBuiltin =
28 NodeModule.isBuiltin(specifier) || (dynamic && specifier.startsWith("bun:"));
29 if (!runtimeBuiltin && !specifier.startsWith("./") && !specifier.startsWith("../")) {
30 specifiers.add(specifier);
31 }
32 }
33 ts.forEachChild(node, visit);
34 };
35 visit(module);
36 return [...specifiers].sort();