Repository navigation
Expand file tree
/
Copy pathcodegen-index-mjs.mts
More file actions
executable file
·86 lines (69 loc) · 2.45 KB
/
Copy pathcodegen-index-mjs.mts
File metadata and controls
executable file
·86 lines (69 loc) · 2.45 KB
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
#!/usr/bin/env bun
import { readFileSync, writeFileSync } from "node:fs"
import * as path from "node:path"
import * as ts from "typescript"
import { fileURLToPath } from "node:url"
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const repoRoot = path.resolve(__dirname, "..")
const declarationsPath = path.join(repoRoot, "index.d.ts")
const outputPath = path.join(repoRoot, "index.mjs")
export function generateIndexMjs(): void {
const sourceText = readFileSync(declarationsPath, "utf8")
const sourceFile = ts.createSourceFile(declarationsPath, sourceText, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS)
const exportNames = getRuntimeExportNames(sourceFile)
if (exportNames.length === 0) {
throw new Error(`expected ${path.relative(repoRoot, declarationsPath)} to declare at least one runtime export`)
}
const output = [
"// Generated from index.d.ts by scripts/codegen-index-mjs.mts. Do not edit.",
'import { createRequire } from "node:module"',
"",
"const require = createRequire(import.meta.url)",
'const binding = require("./index.js")',
"",
...exportNames.map((name) => `export const ${name} = binding.${name}`),
"",
].join("\n")
writeFileSync(outputPath, output)
}
function getRuntimeExportNames(sourceFile: ts.SourceFile): string[] {
const names: string[] = []
for (const statement of sourceFile.statements) {
if (!hasExportModifier(statement)) {
continue
}
if (ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement) || ts.isEnumDeclaration(statement)) {
if (statement.name) {
names.push(statement.name.text)
}
continue
}
if (ts.isVariableStatement(statement)) {
for (const declaration of statement.declarationList.declarations) {
collectBindingNames(declaration.name, names)
}
}
}
return names
}
function hasExportModifier(node: ts.Node): boolean {
if (!ts.canHaveModifiers(node)) {
return false
}
return ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ?? false
}
function collectBindingNames(name: ts.BindingName, names: string[]): void {
if (ts.isIdentifier(name)) {
names.push(name.text)
return
}
for (const element of name.elements) {
if (ts.isBindingElement(element)) {
collectBindingNames(element.name, names)
}
}
}
if (path.resolve(process.argv[1] ?? "") === __filename) {
generateIndexMjs()
}