Skip to content

Commit 9646d84

Browse files
committed
generate .js.mjs and .js.d.mts files
1 parent 85ecc7a commit 9646d84

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed

resources/build-npm.js

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ const {
1313
showDirStats,
1414
} = require('./utils.js');
1515

16+
const entryPoints = [
17+
'index.ts',
18+
'execution/execute.ts',
19+
'jsutils/instanceOf.ts',
20+
'language/parser.ts',
21+
'language/ast.ts',
22+
];
23+
1624
if (require.main === module) {
1725
fs.rmSync('./npmDist', { recursive: true, force: true });
1826
fs.mkdirSync('./npmDist');
@@ -57,11 +65,21 @@ if (require.main === module) {
5765

5866
const tsProgram = ts.createProgram(['src/index.ts'], tsOptions, tsHost);
5967
const tsResult = tsProgram.emit();
68+
6069
assert(
6170
!tsResult.emitSkipped,
6271
'Fail to generate `*.d.ts` files, please run `npm run check`',
6372
);
6473

74+
for (const [filename, contents] of Object.entries(
75+
buildCjsEsmWrapper(
76+
entryPoints.map((e) => './src/' + e),
77+
tsProgram,
78+
),
79+
)) {
80+
writeGeneratedFile(filename, contents);
81+
}
82+
6583
assert(packageJSON.types === undefined, 'Unexpected "types" in package.json');
6684
const supportedTSVersions = Object.keys(packageJSON.typesVersions);
6785
assert(
@@ -137,3 +155,130 @@ function buildPackageJSON() {
137155

138156
return packageJSON;
139157
}
158+
159+
/**
160+
*
161+
* @param {string[]} files
162+
* @param {ts.Program} tsProgram
163+
* @returns
164+
*/
165+
function buildCjsEsmWrapper(files, tsProgram) {
166+
/**
167+
* @type {Record<string, string>} inputFiles
168+
*/
169+
const inputFiles = {};
170+
for (const file of files) {
171+
const sourceFile = tsProgram.getSourceFile(file);
172+
assert(sourceFile, `No source file found for ${file}`);
173+
174+
const generatedFileName = path.relative(
175+
path.dirname(tsProgram.getRootFileNames()[0]),
176+
file.replace(/\.ts$/, '.js.mts'),
177+
);
178+
const exportFrom = ts.factory.createStringLiteral(
179+
'./' + path.basename(file, '.ts') + '.js',
180+
);
181+
182+
/**
183+
* @type {ts.Statement[]}
184+
*/
185+
const statements = [];
186+
187+
/** @type {string[]} */
188+
const exports = [];
189+
190+
/** @type {string[]} */
191+
const typeExports = [];
192+
193+
sourceFile.forEachChild((node) => {
194+
if (ts.isExportDeclaration(node)) {
195+
if (node.exportClause && ts.isNamedExports(node.exportClause)) {
196+
for (const element of node.exportClause.elements) {
197+
if (node.isTypeOnly || element.isTypeOnly) {
198+
typeExports.push(element.name.text);
199+
} else {
200+
exports.push(element.name.text);
201+
}
202+
}
203+
}
204+
} else if (
205+
node.modifiers?.some(
206+
(modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword,
207+
)
208+
) {
209+
if (ts.isVariableStatement(node)) {
210+
for (const declaration of node.declarationList.declarations) {
211+
if (declaration.name && ts.isIdentifier(declaration.name)) {
212+
exports.push(declaration.name.text);
213+
}
214+
}
215+
} else if (
216+
ts.isFunctionDeclaration(node) ||
217+
ts.isClassDeclaration(node)
218+
) {
219+
exports.push(node.name.text);
220+
} else if (ts.isTypeAliasDeclaration(node)) {
221+
typeExports.push(node.name.text);
222+
}
223+
}
224+
});
225+
if (exports.length > 0) {
226+
statements.push(
227+
ts.factory.createExportDeclaration(
228+
undefined,
229+
undefined,
230+
false,
231+
ts.factory.createNamedExports(
232+
exports.map((name) =>
233+
ts.factory.createExportSpecifier(false, undefined, name),
234+
),
235+
),
236+
exportFrom,
237+
),
238+
);
239+
}
240+
if (typeExports.length > 0) {
241+
statements.push(
242+
ts.factory.createExportDeclaration(
243+
undefined,
244+
undefined,
245+
true,
246+
ts.factory.createNamedExports(
247+
typeExports.map((name) =>
248+
ts.factory.createExportSpecifier(false, undefined, name),
249+
),
250+
),
251+
exportFrom,
252+
),
253+
);
254+
}
255+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
256+
inputFiles[generatedFileName] = printer.printFile(
257+
ts.factory.createSourceFile(
258+
statements,
259+
ts.factory.createToken(ts.SyntaxKind.EndOfFileToken),
260+
ts.NodeFlags.None,
261+
),
262+
);
263+
}
264+
/**
265+
* @type {ts.CompilerOptions} options
266+
*/
267+
const options = {
268+
...tsProgram.getCompilerOptions(),
269+
declaration: true,
270+
emitDeclarationOnly: false,
271+
isolatedModules: true,
272+
module: ts.ModuleKind.ESNext,
273+
};
274+
options.outDir = options.declarationDir;
275+
const results = {};
276+
const host = ts.createCompilerHost(options);
277+
host.writeFile = (fileName, contents) => (results[fileName] = contents);
278+
host.readFile = (fileName) => inputFiles[fileName];
279+
280+
const program = ts.createProgram(Object.keys(inputFiles), options, host);
281+
program.emit();
282+
283+
return results;
284+
}

0 commit comments

Comments
 (0)