rolldown-plugin-dts 0.8.5 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.ts +68 -39
  2. package/dist/index.js +338 -202
  3. package/package.json +10 -6
package/dist/index.d.ts CHANGED
@@ -3,53 +3,82 @@ import { IsolatedDeclarationsOptions } from "oxc-transform";
3
3
  import { Plugin } from "rolldown";
4
4
 
5
5
  //#region src/fake-js.d.ts
6
- declare function createFakeJsPlugin({ dtsInput }: Pick<Options, "dtsInput">): Plugin;
6
+ declare function createFakeJsPlugin({
7
+ dtsInput,
8
+ sourcemap
9
+ }: OptionsResolved): Plugin;
7
10
 
8
11
  //#endregion
9
12
  //#region src/generate.d.ts
10
- declare function createGeneratePlugin({ tsconfig, compilerOptions, isolatedDeclarations, resolve, emitDtsOnly }: Pick<Options, "isolatedDeclarations" | "resolve" | "emitDtsOnly" | "tsconfig" | "compilerOptions">): Plugin;
13
+ declare function createGeneratePlugin({
14
+ tsconfig,
15
+ compilerOptions,
16
+ isolatedDeclarations,
17
+ resolve,
18
+ emitDtsOnly
19
+ }: OptionsResolved): Plugin;
11
20
 
12
21
  //#endregion
13
22
  //#region src/index.d.ts
14
23
  interface Options {
15
- /**
16
- * When entries are `.d.ts` files (instead of `.ts` files), this option should be set to `true`.
17
- *
18
- * If enabled, the plugin will skip generating a `.d.ts` file for the entry point.
19
- */
20
- dtsInput?: boolean;
21
- /**
22
- * When `true`, the plugin will only emit `.d.ts` files and remove all other chunks.
23
- *
24
- * This feature is particularly beneficial when you need to generate `d.ts` files for the CommonJS format as part of a separate build process.
25
- */
26
- emitDtsOnly?: boolean;
27
- /**
28
- * The path to the `tsconfig.json` file.
29
- *
30
- * When set to `false`, the plugin will ignore any `tsconfig.json` file.
31
- * However, `compilerOptions` can still be specified directly in the options.
32
- *
33
- * @default `tsconfig.json`
34
- */
35
- tsconfig?: string | boolean;
36
- /**
37
- * The `compilerOptions` for the TypeScript compiler.
38
- *
39
- * @see https://www.typescriptlang.org/docs/handbook/compiler-options.html
40
- */
41
- compilerOptions?: TsConfigJson.CompilerOptions;
42
- /**
43
- * When `true`, the plugin will generate `.d.ts` files using `oxc-transform`,
44
- * which is blazingly faster than `typescript` compiler.
45
- *
46
- * This option is enabled when `isolatedDeclarations` in `compilerOptions` is set to `true`.
47
- */
48
- isolatedDeclarations?: boolean | Omit<IsolatedDeclarationsOptions, "sourcemap">;
49
- /** Resolve external types used in dts files from `node_modules` */
50
- resolve?: boolean | (string | RegExp)[];
24
+ cwd?: string;
25
+ /**
26
+ * When entries are `.d.ts` files (instead of `.ts` files), this option should be set to `true`.
27
+ *
28
+ * If enabled, the plugin will skip generating a `.d.ts` file for the entry point.
29
+ */
30
+ dtsInput?: boolean;
31
+ /**
32
+ * When `true`, the plugin will only emit `.d.ts` files and remove all other chunks.
33
+ *
34
+ * This feature is particularly beneficial when you need to generate `d.ts` files for the CommonJS format as part of a separate build process.
35
+ */
36
+ emitDtsOnly?: boolean;
37
+ /**
38
+ * The path to the `tsconfig.json` file.
39
+ *
40
+ * When set to `false`, the plugin will ignore any `tsconfig.json` file.
41
+ * However, `compilerOptions` can still be specified directly in the options.
42
+ *
43
+ * @default `tsconfig.json`
44
+ */
45
+ tsconfig?: string | boolean;
46
+ /**
47
+ * The `compilerOptions` for the TypeScript compiler.
48
+ *
49
+ * @see https://www.typescriptlang.org/docs/handbook/compiler-options.html
50
+ */
51
+ compilerOptions?: TsConfigJson.CompilerOptions;
52
+ /**
53
+ * When `true`, the plugin will generate `.d.ts` files using `oxc-transform`,
54
+ * which is blazingly faster than `typescript` compiler.
55
+ *
56
+ * This option is enabled when `isolatedDeclarations` in `compilerOptions` is set to `true`.
57
+ */
58
+ isolatedDeclarations?: boolean | Omit<IsolatedDeclarationsOptions, "sourcemap">;
59
+ /**
60
+ * When `true`, the plugin will generate declaration maps for `.d.ts` files.
61
+ */
62
+ sourcemap?: boolean;
63
+ /** Resolve external types used in dts files from `node_modules` */
64
+ resolve?: boolean | (string | RegExp)[];
51
65
  }
66
+ type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U;
67
+ type OptionsResolved = Overwrite<Required<Options>, {
68
+ tsconfig: string | undefined;
69
+ isolatedDeclarations: IsolatedDeclarationsOptions | false;
70
+ }>;
52
71
  declare function dts(options?: Options): Plugin[];
72
+ declare function resolveOptions({
73
+ cwd,
74
+ tsconfig,
75
+ compilerOptions,
76
+ isolatedDeclarations,
77
+ sourcemap,
78
+ dtsInput,
79
+ emitDtsOnly,
80
+ resolve
81
+ }: Options): OptionsResolved;
53
82
 
54
83
  //#endregion
55
- export { Options, createFakeJsPlugin, createGeneratePlugin, dts };
84
+ export { Options, OptionsResolved, createFakeJsPlugin, createGeneratePlugin, dts, resolveOptions };
package/dist/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import path from "node:path";
2
- import { MagicStringAST } from "magic-string-ast";
3
- import { parseSync } from "oxc-parser";
4
2
  import process from "node:process";
5
- import { createResolver } from "dts-resolver";
6
3
  import { getTsconfig, parseTsconfig } from "get-tsconfig";
4
+ import _generate from "@babel/generator";
5
+ import { parse } from "@babel/parser";
6
+ import * as t from "@babel/types";
7
+ import { isDeclarationType, isTypeOf } from "ast-kit";
8
+ import { createResolver } from "dts-resolver";
7
9
  import { isolatedDeclaration } from "oxc-transform";
8
10
  import { createRequire } from "node:module";
9
11
  import Debug from "debug";
@@ -12,6 +14,7 @@ import Debug from "debug";
12
14
  const RE_JS = /\.([cm]?)jsx?$/;
13
15
  const RE_TS = /\.([cm]?)tsx?$/;
14
16
  const RE_DTS = /\.d\.([cm]?)ts$/;
17
+ const RE_DTS_MAP = /\.d\.([cm]?)ts\.map$/;
15
18
  const RE_NODE_MODULES = /[\\/]node_modules[\\/]/;
16
19
  function filename_js_to_dts(id) {
17
20
  return id.replace(RE_JS, ".d.$1ts");
@@ -31,10 +34,22 @@ function isRelative(id) {
31
34
  function createDtsInputPlugin() {
32
35
  return {
33
36
  name: "rolldown-plugin-dts:dts-input",
37
+ options(options) {
38
+ return {
39
+ treeshake: options.treeshake !== false ? {
40
+ ...options.treeshake === true ? {} : options.treeshake,
41
+ moduleSideEffects: false
42
+ } : false,
43
+ ...options
44
+ };
45
+ },
34
46
  outputOptions(options) {
35
47
  return {
36
48
  ...options,
37
- entryFileNames: "[name].ts"
49
+ entryFileNames(chunk) {
50
+ if (chunk.name.endsWith(".d")) return "[name].ts";
51
+ return "[name].d.ts";
52
+ }
38
53
  };
39
54
  },
40
55
  resolveId: {
@@ -237,41 +252,23 @@ function walk(ast, { enter, leave }) {
237
252
  return instance.visit(ast, null);
238
253
  }
239
254
 
240
- //#endregion
241
- //#region src/utils/ast.ts
242
- function getIdentifierRange(node, offset = 0) {
243
- if ("typeAnnotation" in node && node.typeAnnotation) return [node.start + offset, node.typeAnnotation.start + offset];
244
- return [node.start + offset, node.end + offset];
245
- }
246
-
247
- //#endregion
248
- //#region src/utils/magic-string.ts
249
- function overwriteOrAppend(s, range, replacement, suffix) {
250
- if (range[0] === range[1]) {
251
- s.appendLeft(range[0], ` ${replacement}`);
252
- return;
253
- }
254
- const original = s.slice(range[0], range[1]);
255
- if (original !== replacement) s.overwrite(range[0], range[1], replacement + (suffix || ""));
256
- }
257
-
258
255
  //#endregion
259
256
  //#region src/fake-js.ts
260
- const RE_TYPE = /\btype\b/;
261
- function createFakeJsPlugin({ dtsInput }) {
257
+ const generate = _generate.default || _generate;
258
+ function createFakeJsPlugin({ dtsInput, sourcemap }) {
262
259
  let symbolIdx = 0;
263
260
  let identifierIdx = 0;
264
261
  const symbolMap = new Map();
265
- const preserveMap = new Map();
262
+ const commentsMap = new Map();
266
263
  function getIdentifierIndex() {
267
264
  return identifierIdx++;
268
265
  }
269
- function register(info) {
266
+ function registerSymbol(info) {
270
267
  const symbolId = symbolIdx++;
271
268
  symbolMap.set(symbolId, info);
272
269
  return symbolId;
273
270
  }
274
- function retrieve(symbolId) {
271
+ function getSymbol(symbolId) {
275
272
  return symbolMap.get(symbolId);
276
273
  }
277
274
  return {
@@ -298,6 +295,7 @@ function createFakeJsPlugin({ dtsInput }) {
298
295
  if (options.format === "cjs" || options.format === "commonjs") throw new Error("[rolldown-plugin-dts] Cannot bundle dts files with `cjs` format.");
299
296
  return {
300
297
  ...options,
298
+ sourcemap: sourcemap ? true : options.sourcemap,
301
299
  entryFileNames: options.entryFileNames ?? (dtsInput ? "[name].ts" : void 0),
302
300
  chunkFileNames(chunk) {
303
301
  const original = (typeof options.chunkFileNames === "function" ? options.chunkFileNames(chunk) : options.chunkFileNames) || "[name]-[hash].js";
@@ -309,137 +307,183 @@ function createFakeJsPlugin({ dtsInput }) {
309
307
  transform: {
310
308
  filter: { id: RE_DTS },
311
309
  handler(code, id) {
312
- const { program, comments } = parseSync(id, code);
313
- const preserved = collectReferenceDirectives(comments);
314
- preserveMap.set(id, preserved);
315
- const s = new MagicStringAST(code);
316
- for (let node of program.body) {
317
- if (rewriteImportExport(s, node)) continue;
318
- const sideEffect = node.type === "TSModuleDeclaration" && node.kind !== "namespace";
319
- const stmt = node;
320
- const isDefaultExport = node.type === "ExportDefaultDeclaration";
321
- if ((node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration") && node.declaration) node = node.declaration;
322
- if (node.type === "VariableDeclaration" && node.declarations.length !== 1) throw new Error("Only one declaration is supported");
323
- if (node.type === "TSDeclareFunction" || node.type.endsWith("Declaration")) {
324
- const binding = node.type === "VariableDeclaration" ? node.declarations[0].id : node.id;
325
- const code$1 = s.sliceNode(node);
326
- const offset = node.start;
327
- let bindingRange;
328
- if (sideEffect) bindingRange = [0, 0];
329
- else if (binding) bindingRange = getIdentifierRange(binding, -offset);
330
- else if (isDefaultExport) {
331
- const idx = s.sliceNode(node).indexOf("function") + 8;
332
- bindingRange = [idx, idx];
333
- } else continue;
334
- const depsNodes = collectDependencies(s, node, getIdentifierIndex);
335
- const depsString = stringifyDependencies(s, depsNodes);
336
- const depsSymbols = depsNodes.map((dep) => [
337
- dep.start - offset,
338
- dep.end - offset,
339
- dep._suffix
340
- ]);
341
- const needDeclare = (node.type === "TSEnumDeclaration" || node.type === "ClassDeclaration" || node.type === "FunctionDeclaration" || node.type === "TSDeclareFunction" || node.type === "TSModuleDeclaration" || node.type === "VariableDeclaration") && !node.declare;
342
- const symbolId = register({
343
- code: code$1,
344
- binding: bindingRange,
345
- deps: depsSymbols,
346
- needDeclare,
347
- preserveName: sideEffect
348
- });
349
- const runtime = `[${symbolId}, ${depsString}${depsString && sideEffect ? ", " : ""}${sideEffect ? "sideEffect()" : ""}]`;
350
- const bindingName = sideEffect ? `_${identifierIdx++}` : binding ? s.sliceNode(binding) : "export_default";
351
- if (isDefaultExport) s.overwriteNode(stmt, `var ${bindingName} = ${runtime};export { ${bindingName} as default }`);
352
- else s.overwriteNode(node, `var ${bindingName} = ${runtime};`);
310
+ const file = parse(code, {
311
+ plugins: [["typescript", { dts: true }]],
312
+ sourceType: "module"
313
+ });
314
+ const { program, comments } = file;
315
+ if (comments) {
316
+ const directives = collectReferenceDirectives(comments);
317
+ commentsMap.set(id, directives);
318
+ }
319
+ const prependStmts = [];
320
+ const appendStmts = [];
321
+ const prepend = (stmt) => prependStmts.push(stmt);
322
+ for (const [i, stmt] of program.body.entries()) {
323
+ const setStmt = (node) => program.body[i] = inheritNode(stmt, node);
324
+ if (rewriteImportExport(stmt, setStmt)) continue;
325
+ const sideEffect = stmt.type === "TSModuleDeclaration" && stmt.kind !== "namespace";
326
+ const isDefaultExport = stmt.type === "ExportDefaultDeclaration";
327
+ const isDecl = isTypeOf(stmt, ["ExportNamedDeclaration", "ExportDefaultDeclaration"]) && stmt.declaration;
328
+ const decl = isDecl ? stmt.declaration : stmt;
329
+ const setDecl = isDecl ? (node) => stmt.declaration = inheritNode(stmt.declaration, node) : setStmt;
330
+ if (decl.type === "VariableDeclaration" && decl.declarations.length !== 1) throw new Error("Only one declaration is supported");
331
+ if (decl.type !== "TSDeclareFunction" && !isDeclarationType(decl)) continue;
332
+ if (isTypeOf(decl, [
333
+ "TSEnumDeclaration",
334
+ "ClassDeclaration",
335
+ "FunctionDeclaration",
336
+ "TSDeclareFunction",
337
+ "TSModuleDeclaration",
338
+ "VariableDeclaration"
339
+ ])) decl.declare = true;
340
+ let binding = decl.type === "VariableDeclaration" ? decl.declarations[0].id : "id" in decl ? decl.id : null;
341
+ if (!binding) {
342
+ binding = t.identifier("export_default");
343
+ decl.id = binding;
353
344
  }
345
+ binding = sideEffect ? t.identifier(`_${identifierIdx++}`) : binding;
346
+ const deps = collectDependencies(decl, getIdentifierIndex, prepend);
347
+ const elements = [
348
+ t.numericLiteral(0),
349
+ ...deps.map((dep) => t.arrowFunctionExpression([], dep)),
350
+ ...sideEffect ? [t.callExpression(t.identifier("sideEffect"), [])] : []
351
+ ];
352
+ const runtime = t.arrayExpression(elements);
353
+ const symbolId = registerSymbol({
354
+ decl,
355
+ deps,
356
+ binding
357
+ });
358
+ elements[0] = t.numericLiteral(symbolId);
359
+ const runtimeAssignment = {
360
+ type: "VariableDeclaration",
361
+ kind: "var",
362
+ declarations: [{
363
+ type: "VariableDeclarator",
364
+ id: {
365
+ ...binding,
366
+ typeAnnotation: null
367
+ },
368
+ init: runtime
369
+ }]
370
+ };
371
+ if (isDefaultExport) {
372
+ appendStmts.push(t.exportNamedDeclaration(null, [t.exportSpecifier(binding, t.identifier("default"))]));
373
+ setStmt(runtimeAssignment);
374
+ } else setDecl(runtimeAssignment);
354
375
  }
355
- if (!s.hasChanged()) return;
356
- const str = s.toString();
357
- return str;
376
+ program.body = [
377
+ ...prependStmts,
378
+ ...program.body,
379
+ ...appendStmts
380
+ ];
381
+ const result = generate(file, {
382
+ comments: true,
383
+ sourceMaps: sourcemap,
384
+ sourceFileName: id
385
+ });
386
+ return result;
358
387
  }
359
388
  },
360
389
  renderChunk(code, chunk) {
361
390
  if (!RE_DTS.test(chunk.fileName)) return;
362
- const { program } = parseSync(chunk.fileName, code);
363
- const s = new MagicStringAST(code);
364
- const comments = new Set();
365
- for (const id of chunk.moduleIds) {
366
- const preserveComments = preserveMap.get(id);
367
- if (preserveComments) {
368
- preserveComments.forEach((c) => comments.add(c));
369
- preserveMap.delete(id);
391
+ const file = parse(code, { sourceType: "module" });
392
+ const { program } = file;
393
+ if (program.body.length) {
394
+ const comments = new Set();
395
+ const commentsValue = new Set();
396
+ for (const id of chunk.moduleIds) {
397
+ const preserveComments = commentsMap.get(id);
398
+ if (preserveComments) {
399
+ preserveComments.forEach((c) => {
400
+ const id$1 = c.type + c.value;
401
+ if (commentsValue.has(id$1)) return;
402
+ commentsValue.add(id$1);
403
+ comments.add(c);
404
+ });
405
+ commentsMap.delete(id);
406
+ }
407
+ }
408
+ if (comments.size) {
409
+ program.body[0].leadingComments ||= [];
410
+ program.body[0].leadingComments.push(...comments);
370
411
  }
371
412
  }
372
- if (comments.size) s.prepend(`${[...comments].join("\n")}\n`);
373
- const removedNodes = patchTsNamespace(s, program.body);
374
- for (const node of program.body) {
375
- if (removedNodes.has(node)) continue;
376
- if (patchImportSource(s, node)) continue;
377
- if (node.type !== "VariableDeclaration" || node.declarations.length !== 1) continue;
413
+ program.body = patchTsNamespace(program.body);
414
+ program.body = program.body.map((node) => {
415
+ if (patchImportSource(node)) return node;
416
+ if (node.type !== "VariableDeclaration" || node.declarations.length !== 1) return node;
378
417
  const [decl] = node.declarations;
379
- if (decl.init?.type !== "ArrayExpression" || !decl.init.elements[0]) {
380
- s.removeNode(node);
381
- continue;
382
- }
383
- const [symbolIdNode, ...depsNodes] = decl.init.elements;
384
- if (symbolIdNode?.type !== "Literal" || typeof symbolIdNode.value !== "number") {
385
- s.removeNode(node);
386
- continue;
387
- }
418
+ if (decl.init?.type !== "ArrayExpression" || !decl.init.elements[0]) return null;
419
+ const [symbolIdNode, ...depsFns] = decl.init.elements;
420
+ if (symbolIdNode?.type !== "NumericLiteral") return null;
388
421
  const symbolId = symbolIdNode.value;
389
- const { code: code$1, binding, deps, needDeclare, preserveName } = retrieve(symbolId);
390
- const depsRaw = depsNodes.filter((node$1) => node$1?.type === "ArrowFunctionExpression").map((dep) => s.sliceNode(dep.body));
391
- const ss = new MagicStringAST(code$1);
392
- if (!preserveName) overwriteOrAppend(ss, binding, s.sliceNode(decl.id));
393
- for (const dep of deps) {
394
- const [start, end, suffix] = dep;
395
- overwriteOrAppend(ss, [start, end], depsRaw.shift(), suffix);
422
+ const original = getSymbol(symbolId);
423
+ const transformedBinding = {
424
+ ...decl.id,
425
+ typeAnnotation: original.binding.typeAnnotation
426
+ };
427
+ overwriteNode(original.binding, transformedBinding);
428
+ const transformedDeps = depsFns.filter((node$1) => node$1?.type === "ArrowFunctionExpression").map((node$1) => node$1.body);
429
+ if (original.deps.length) for (let i = 0; i < original.deps.length; i++) {
430
+ const originalDep = original.deps[i];
431
+ if (originalDep.replace) originalDep.replace(transformedDeps[i]);
432
+ else Object.assign(originalDep, transformedDeps[i]);
396
433
  }
397
- if (needDeclare) ss.prepend("declare ");
398
- s.overwriteNode(node, ss.toString());
434
+ return inheritNode(node, original.decl);
435
+ }).filter((node) => !!node);
436
+ if (program.body.length === 0) return "export { };";
437
+ const result = generate(file, {
438
+ comments: true,
439
+ sourceMaps: sourcemap,
440
+ sourceFileName: chunk.fileName
441
+ });
442
+ return result;
443
+ },
444
+ generateBundle(options, bundle) {
445
+ for (const chunk of Object.values(bundle)) {
446
+ if (chunk.type !== "asset" || !RE_DTS_MAP.test(chunk.fileName) || typeof chunk.source !== "string") continue;
447
+ const maps = JSON.parse(chunk.source);
448
+ maps.sourcesContent = null;
449
+ chunk.source = JSON.stringify(maps);
399
450
  }
400
- const str = s.toString();
401
- if (str.trim().length === 0) return "export { };";
402
- return str;
403
451
  }
404
452
  };
405
453
  }
406
454
  const REFERENCE_RE = /\/\s*<reference\s+(?:path|types)=/;
407
455
  function collectReferenceDirectives(comment) {
408
- return comment.filter((c) => REFERENCE_RE.test(c.value)).map((c) => `//${c.value}`);
456
+ return comment.filter((c) => REFERENCE_RE.test(c.value));
409
457
  }
410
- function collectDependencies(s, node, getIdentifierIndex) {
458
+ function collectDependencies(node, getIdentifierIndex, prepend) {
411
459
  const deps = new Set();
460
+ const seen = new Set();
412
461
  walk(node, { leave(node$1) {
413
462
  if (node$1.type === "ExportNamedDeclaration") {
414
- for (const specifier of node$1.specifiers) if (specifier.type === "ExportSpecifier") {
415
- let _suffix;
416
- if (specifier.local.start === specifier.exported.start && specifier.local.end === specifier.exported.end) _suffix = ` as ${s.sliceNode(specifier.local)}`;
417
- addDependency({
418
- ...specifier.local,
419
- _suffix
420
- });
421
- }
422
- } else if (node$1.type === "TSInterfaceDeclaration" && node$1.extends) for (const heritage of node$1.extends || []) addDependency(heritage.expression);
463
+ for (const specifier of node$1.specifiers) if (specifier.type === "ExportSpecifier") addDependency(specifier.local);
464
+ } else if (node$1.type === "TSInterfaceDeclaration" && node$1.extends) for (const heritage of node$1.extends || []) addDependency(TSEntityNameToRuntime(heritage.expression));
423
465
  else if (node$1.type === "ClassDeclaration") {
424
466
  if (node$1.superClass) addDependency(node$1.superClass);
425
- if (node$1.implements) for (const implement of node$1.implements) addDependency(implement.expression);
426
- } else if (node$1.type === "MethodDefinition" || node$1.type === "PropertyDefinition" || node$1.type === "TSPropertySignature") {
467
+ if (node$1.implements) for (const implement of node$1.implements) addDependency(TSEntityNameToRuntime(implement.expression));
468
+ } else if (isTypeOf(node$1, [
469
+ "ObjectMethod",
470
+ "ObjectProperty",
471
+ "ClassProperty",
472
+ "TSPropertySignature",
473
+ "TSDeclareMethod"
474
+ ])) {
427
475
  if (node$1.computed && isReferenceId(node$1.key)) addDependency(node$1.key);
428
476
  if ("value" in node$1 && isReferenceId(node$1.value)) addDependency(node$1.value);
429
- } else if (node$1.type === "TSTypeReference") addDependency(node$1.typeName);
477
+ } else if (node$1.type === "TSTypeReference") addDependency(TSEntityNameToRuntime(node$1.typeName));
430
478
  else if (node$1.type === "TSTypeQuery") {
431
- if (node$1.exprName.type !== "TSImportType") addDependency(node$1.exprName);
479
+ if (seen.has(node$1.exprName)) return;
480
+ if (node$1.exprName.type !== "TSImportType") addDependency(TSEntityNameToRuntime(node$1.exprName));
432
481
  } else if (node$1.type === "TSImportType") {
433
- if (node$1.argument.type !== "TSLiteralType" || node$1.argument.literal.type !== "Literal" || typeof node$1.argument.literal.value !== "string") return;
434
- const source = node$1.argument.literal.value;
435
- const imported = node$1.qualifier && resolveTSTypeName(node$1.qualifier);
436
- const local = importNamespace(s, source, imported && s.sliceNode(imported), getIdentifierIndex);
437
- addDependency({
438
- type: "Identifier",
439
- name: local,
440
- start: node$1.start,
441
- end: imported ? imported.end : node$1.end
442
- });
482
+ seen.add(node$1);
483
+ const source = node$1.argument;
484
+ const imported = node$1.qualifier;
485
+ const dep = importNamespace(node$1, imported, source, getIdentifierIndex, prepend);
486
+ addDependency(dep);
443
487
  }
444
488
  } });
445
489
  return Array.from(deps);
@@ -448,76 +492,151 @@ function collectDependencies(s, node, getIdentifierIndex) {
448
492
  deps.add(node$1);
449
493
  }
450
494
  }
451
- function resolveTSTypeName(node) {
495
+ function TSEntityNameToRuntime(node) {
496
+ if (node.type === "Identifier") return node;
497
+ const left = TSEntityNameToRuntime(node.left);
498
+ return Object.assign(node, t.memberExpression(left, node.right));
499
+ }
500
+ function getIdFromTSEntityName(node) {
452
501
  if (node.type === "Identifier") return node;
453
- return resolveTSTypeName(node.left);
502
+ return getIdFromTSEntityName(node.left);
454
503
  }
455
504
  function isReferenceId(node) {
456
505
  return !!node && (node.type === "Identifier" || node.type === "MemberExpression");
457
506
  }
458
- function stringifyDependencies(s, deps) {
459
- return deps.map((node) => `() => ${node.type === "Identifier" ? node.name : s.sliceNode(node)}`).join(", ");
460
- }
461
- function patchImportSource(s, node) {
462
- if ((node.type === "ImportDeclaration" || node.type === "ExportAllDeclaration" || node.type === "ExportNamedDeclaration") && node.source?.value && RE_DTS.test(node.source.value)) {
463
- s.overwriteNode(node.source, JSON.stringify(filename_dts_to(node.source.value, "js")));
507
+ function patchImportSource(node) {
508
+ if (isTypeOf(node, [
509
+ "ImportDeclaration",
510
+ "ExportAllDeclaration",
511
+ "ExportNamedDeclaration"
512
+ ]) && node.source?.value && RE_DTS.test(node.source.value)) {
513
+ node.source.value = filename_dts_to(node.source.value, "js");
464
514
  return true;
465
515
  }
466
516
  }
467
- function patchTsNamespace(s, nodes) {
517
+ function patchTsNamespace(nodes) {
468
518
  const emptyObjectAssignments = new Map();
469
519
  const removed = new Set();
470
- for (const node of nodes) {
471
- if (node.type === "VariableDeclaration" && node.declarations.length === 1 && node.declarations[0].init?.type === "ObjectExpression" && node.declarations[0].init.properties.length === 0) emptyObjectAssignments.set(s.sliceNode(node.declarations[0].id), node);
520
+ for (const [i, node] of nodes.entries()) {
521
+ if (node.type === "VariableDeclaration" && node.declarations.length === 1 && node.declarations[0].id.type === "Identifier" && node.declarations[0].init?.type === "ObjectExpression" && node.declarations[0].init.properties.length === 0) emptyObjectAssignments.set(node.declarations[0].id.name, node);
472
522
  if (node.type !== "ExpressionStatement" || node.expression.type !== "CallExpression" || node.expression.callee.type !== "Identifier" || !node.expression.callee.name.startsWith("__export")) continue;
473
523
  const [binding, exports] = node.expression.arguments;
474
- const bindingText = s.sliceNode(binding);
524
+ if (binding.type !== "Identifier") continue;
525
+ const bindingText = binding.name;
475
526
  if (emptyObjectAssignments.has(bindingText)) {
476
527
  const emptyNode = emptyObjectAssignments.get(bindingText);
477
- s.removeNode(emptyNode);
478
528
  emptyObjectAssignments.delete(bindingText);
479
529
  removed.add(emptyNode);
480
530
  }
481
- let code = `declare namespace ${bindingText} {
482
- export { `;
483
- for (const properties of exports.properties) {
484
- if (properties.type !== "Property") continue;
485
- const exported = s.sliceNode(properties.key);
486
- const local = s.sliceNode(properties.value.body);
487
- const suffix = exported !== local ? ` as ${exported}` : "";
488
- code += `${local}${suffix}, `;
489
- }
490
- code += `}\n}`;
491
- s.overwriteNode(node, code);
531
+ nodes[i] = {
532
+ type: "TSModuleDeclaration",
533
+ id: binding,
534
+ kind: "namespace",
535
+ declare: true,
536
+ body: {
537
+ type: "TSModuleBlock",
538
+ body: [{
539
+ type: "ExportNamedDeclaration",
540
+ specifiers: exports.properties.filter((property) => property.type === "ObjectProperty").map((property) => {
541
+ const local = property.value.body;
542
+ const exported = property.key;
543
+ return t.exportSpecifier(local, exported);
544
+ }),
545
+ source: null,
546
+ declaration: null
547
+ }]
548
+ }
549
+ };
492
550
  }
493
- return removed;
551
+ return nodes.filter((node) => !removed.has(node));
494
552
  }
495
- function rewriteImportExport(s, node) {
553
+ function rewriteImportExport(node, set) {
496
554
  if (node.type === "ImportDeclaration" || node.type === "ExportNamedDeclaration" && !node.declaration) {
497
- for (const specifier of node.specifiers) if (specifier.type === "ImportSpecifier" && specifier.importKind === "type" || specifier.type === "ExportSpecifier" && specifier.exportKind === "type") s.overwriteNode(specifier, s.sliceNode(specifier).replace(RE_TYPE, ""));
498
- const firstSpecifier = node.specifiers[0];
499
- const kind = node.type === "ImportDeclaration" ? node.importKind : node.exportKind;
500
- if (kind === "type" && firstSpecifier) s.overwrite(node.start, firstSpecifier.start, s.slice(node.start, firstSpecifier.start).replace(RE_TYPE, ""));
555
+ for (const specifier of node.specifiers) if (specifier.type === "ImportSpecifier") specifier.importKind = "value";
556
+ else if (specifier.type === "ExportSpecifier") specifier.exportKind = "value";
557
+ if (node.type === "ImportDeclaration") node.importKind = "value";
558
+ else if (node.type === "ExportNamedDeclaration") node.exportKind = "value";
501
559
  return true;
502
560
  } else if (node.type === "ExportAllDeclaration") {
503
- if (node.exportKind === "type") s.overwrite(node.start, node.source.start, s.slice(node.start, node.source.start).replace(RE_TYPE, ""));
561
+ node.exportKind = "value";
504
562
  return true;
505
563
  } else if (node.type === "TSImportEqualsDeclaration") {
506
- if (node.moduleReference.type === "TSExternalModuleReference") s.overwriteNode(node, `import ${s.sliceNode(node.id)} from ${s.sliceNode(node.moduleReference.expression)}`);
564
+ if (node.moduleReference.type === "TSExternalModuleReference") set({
565
+ type: "ImportDeclaration",
566
+ specifiers: [{
567
+ type: "ImportDefaultSpecifier",
568
+ local: node.id
569
+ }],
570
+ source: node.moduleReference.expression
571
+ });
507
572
  return true;
508
- } else if (node.type === "TSExportAssignment") {
509
- s.overwriteNode(node, `export { ${s.sliceNode(node.expression)} as default }`);
573
+ } else if (node.type === "TSExportAssignment" && node.expression.type === "Identifier") {
574
+ set({
575
+ type: "ExportNamedDeclaration",
576
+ specifiers: [{
577
+ type: "ExportSpecifier",
578
+ local: node.expression,
579
+ exported: {
580
+ type: "Identifier",
581
+ name: "default"
582
+ }
583
+ }]
584
+ });
510
585
  return true;
511
586
  } else if (node.type === "ExportDefaultDeclaration" && node.declaration.type === "Identifier") {
512
- s.overwriteNode(node, `export { ${s.sliceNode(node.declaration)} as default }`);
587
+ set({
588
+ type: "ExportNamedDeclaration",
589
+ specifiers: [{
590
+ type: "ExportSpecifier",
591
+ local: node.declaration,
592
+ exported: t.identifier("default")
593
+ }]
594
+ });
513
595
  return true;
514
596
  }
597
+ return false;
515
598
  }
516
- function importNamespace(s, source, imported, getIdentifierIndex) {
517
- const local = `_${getIdentifierIndex()}`;
518
- const specifiers = imported ? `{ ${imported} as ${local} }` : `* as ${local}`;
519
- s.prepend(`import ${specifiers} from ${JSON.stringify(source)};\n`);
520
- return local;
599
+ function importNamespace(node, imported, source, getIdentifierIndex, prepend) {
600
+ let local = t.identifier(`_${getIdentifierIndex()}`);
601
+ prepend(t.importDeclaration([t.importNamespaceSpecifier(local)], source));
602
+ if (imported) {
603
+ const importedLeft = getIdFromTSEntityName(imported);
604
+ overwriteNode(importedLeft, t.tsQualifiedName(local, { ...importedLeft }));
605
+ local = imported;
606
+ }
607
+ let replacement = node;
608
+ if (node.typeParameters) {
609
+ overwriteNode(node, t.tsTypeReference(local, node.typeParameters));
610
+ replacement = local;
611
+ } else overwriteNode(node, local);
612
+ const dep = {
613
+ ...TSEntityNameToRuntime(local),
614
+ replace(newNode) {
615
+ overwriteNode(replacement, newNode);
616
+ }
617
+ };
618
+ return dep;
619
+ }
620
+ function inheritNode(oldValue, newValue) {
621
+ return {
622
+ ...newValue,
623
+ leadingComments: oldValue.leadingComments,
624
+ innerComments: oldValue.innerComments,
625
+ trailingComments: oldValue.trailingComments
626
+ };
627
+ }
628
+ function overwriteNode(node, newNode) {
629
+ const preserve = [
630
+ "leadingComments",
631
+ "innerComments",
632
+ "trailingComments"
633
+ ];
634
+ for (const key of Object.keys(node)) {
635
+ if (preserve.includes(key)) continue;
636
+ delete node[key];
637
+ }
638
+ Object.assign(node, newNode, { ...node });
639
+ return node;
521
640
  }
522
641
 
523
642
  //#endregion
@@ -622,28 +741,8 @@ function getTsModule(dtsMap, tsId) {
622
741
  //#endregion
623
742
  //#region src/generate.ts
624
743
  const meta = { dtsFile: true };
625
- function createGeneratePlugin({ tsconfig, compilerOptions, isolatedDeclarations, resolve = false, emitDtsOnly = false }) {
744
+ function createGeneratePlugin({ tsconfig, compilerOptions = {}, isolatedDeclarations, resolve = false, emitDtsOnly = false }) {
626
745
  const dtsMap = new Map();
627
- function resolveOptions(cwd) {
628
- if (tsconfig === true || tsconfig == null) {
629
- const { config, path: path$1 } = getTsconfig(cwd) || {};
630
- tsconfig = path$1;
631
- compilerOptions = {
632
- ...config?.compilerOptions,
633
- ...compilerOptions
634
- };
635
- } else if (typeof tsconfig === "string") {
636
- tsconfig = path.resolve(cwd || process.cwd(), tsconfig);
637
- const config = parseTsconfig(tsconfig);
638
- compilerOptions = {
639
- ...config.compilerOptions,
640
- ...compilerOptions
641
- };
642
- }
643
- if (isolatedDeclarations == null) isolatedDeclarations = !!compilerOptions?.isolatedDeclarations;
644
- if (isolatedDeclarations === true) isolatedDeclarations = {};
645
- if (isolatedDeclarations && isolatedDeclarations.stripInternal == null) isolatedDeclarations.stripInternal = !!compilerOptions?.stripInternal;
646
- }
647
746
  /**
648
747
  * A map of input id to output file name
649
748
  *
@@ -654,14 +753,12 @@ function createGeneratePlugin({ tsconfig, compilerOptions, isolatedDeclarations,
654
753
  * ])
655
754
  */
656
755
  const inputAliasMap = new Map();
657
- let resolver;
658
756
  let programs = [];
757
+ const resolver = createResolver({ tsconfig: tsconfig ? tsconfig : void 0 });
758
+ if (!isolatedDeclarations) initTs();
659
759
  return {
660
760
  name: "rolldown-plugin-dts:generate",
661
761
  async buildStart(options) {
662
- resolveOptions(options.cwd);
663
- resolver = createResolver({ tsconfig: tsconfig ? tsconfig : void 0 });
664
- if (!isolatedDeclarations) initTs();
665
762
  if (!Array.isArray(options.input)) for (const [name, id] of Object.entries(options.input)) {
666
763
  let resolved = await this.resolve(id, void 0, { skipSelf: true });
667
764
  resolved ||= await this.resolve(`./${id}`, void 0, { skipSelf: true });
@@ -775,8 +872,9 @@ function createGeneratePlugin({ tsconfig, compilerOptions, isolatedDeclarations,
775
872
  if (!dtsMap.has(dtsId)) return;
776
873
  const { code, id, isEntry } = dtsMap.get(dtsId);
777
874
  let dtsCode;
875
+ let map;
778
876
  if (isolatedDeclarations) {
779
- const result = isolatedDeclaration(id, code, isolatedDeclarations === true ? {} : isolatedDeclarations);
877
+ const result = isolatedDeclaration(id, code, isolatedDeclarations);
780
878
  if (result.errors.length) {
781
879
  const [error] = result.errors;
782
880
  return this.error({
@@ -785,6 +883,7 @@ function createGeneratePlugin({ tsconfig, compilerOptions, isolatedDeclarations,
785
883
  });
786
884
  }
787
885
  dtsCode = result.code;
886
+ if (result.map) map = result.map;
788
887
  } else {
789
888
  const module = createOrGetTsModule(programs, compilerOptions, id, isEntry, dtsMap);
790
889
  const result = tscEmit(module);
@@ -794,12 +893,13 @@ function createGeneratePlugin({ tsconfig, compilerOptions, isolatedDeclarations,
794
893
  if (!dtsCode) return this.error(new Error(`Failed to generate dts for ${id}`));
795
894
  return {
796
895
  code: dtsCode,
797
- moduleSideEffects: false
896
+ moduleSideEffects: false,
897
+ map
798
898
  };
799
899
  }
800
900
  },
801
901
  generateBundle: emitDtsOnly ? (options, bundle) => {
802
- for (const fileName of Object.keys(bundle)) if (!RE_DTS.test(fileName)) delete bundle[fileName];
902
+ for (const fileName of Object.keys(bundle)) if (bundle[fileName].type === "chunk" && !RE_DTS.test(fileName) && !RE_DTS_MAP.test(fileName)) delete bundle[fileName];
803
903
  } : void 0,
804
904
  buildEnd() {
805
905
  programs = [];
@@ -810,12 +910,48 @@ function createGeneratePlugin({ tsconfig, compilerOptions, isolatedDeclarations,
810
910
  //#endregion
811
911
  //#region src/index.ts
812
912
  function dts(options = {}) {
913
+ const resolved = resolveOptions(options);
813
914
  const plugins = [];
814
915
  if (options.dtsInput) plugins.push(createDtsInputPlugin());
815
- else plugins.push(createGeneratePlugin(options));
816
- plugins.push(createFakeJsPlugin(options));
916
+ else plugins.push(createGeneratePlugin(resolved));
917
+ plugins.push(createFakeJsPlugin(resolved));
817
918
  return plugins;
818
919
  }
920
+ function resolveOptions({ cwd = process.cwd(), tsconfig, compilerOptions = {}, isolatedDeclarations, sourcemap, dtsInput = false, emitDtsOnly = false, resolve = false }) {
921
+ if (tsconfig === true || tsconfig == null) {
922
+ const { config, path: path$1 } = getTsconfig(cwd) || {};
923
+ tsconfig = path$1;
924
+ compilerOptions = {
925
+ ...config?.compilerOptions,
926
+ ...compilerOptions
927
+ };
928
+ } else if (typeof tsconfig === "string") {
929
+ tsconfig = path.resolve(cwd || process.cwd(), tsconfig);
930
+ const config = parseTsconfig(tsconfig);
931
+ compilerOptions = {
932
+ ...config.compilerOptions,
933
+ ...compilerOptions
934
+ };
935
+ } else tsconfig = void 0;
936
+ sourcemap ??= !!compilerOptions.declarationMap;
937
+ compilerOptions.declarationMap = sourcemap;
938
+ if (isolatedDeclarations == null) isolatedDeclarations = !!compilerOptions?.isolatedDeclarations;
939
+ if (isolatedDeclarations === true) isolatedDeclarations = {};
940
+ if (isolatedDeclarations) {
941
+ isolatedDeclarations.stripInternal ??= !!compilerOptions?.stripInternal;
942
+ isolatedDeclarations.sourcemap = !!compilerOptions.declarationMap;
943
+ }
944
+ return {
945
+ cwd,
946
+ tsconfig,
947
+ compilerOptions,
948
+ isolatedDeclarations,
949
+ sourcemap,
950
+ dtsInput,
951
+ emitDtsOnly,
952
+ resolve
953
+ };
954
+ }
819
955
 
820
956
  //#endregion
821
- export { createFakeJsPlugin, createGeneratePlugin, dts };
957
+ export { createFakeJsPlugin, createGeneratePlugin, dts, resolveOptions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rolldown-plugin-dts",
3
- "version": "0.8.5",
3
+ "version": "0.9.0",
4
4
  "description": "A Rolldown plugin to bundle dts files",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -37,28 +37,32 @@
37
37
  }
38
38
  },
39
39
  "dependencies": {
40
+ "@babel/generator": "^7.27.0",
41
+ "@babel/parser": "^7.27.0",
42
+ "@babel/types": "^7.27.0",
43
+ "ast-kit": "^1.4.3",
40
44
  "debug": "^4.4.0",
41
45
  "dts-resolver": "^1.0.1",
42
46
  "get-tsconfig": "^4.10.0",
43
- "magic-string-ast": "^0.9.1",
44
- "oxc-parser": "^0.66.0",
45
47
  "oxc-transform": "^0.66.0"
46
48
  },
47
49
  "devDependencies": {
48
50
  "@sxzz/eslint-config": "^6.1.2",
49
51
  "@sxzz/prettier-config": "^2.2.1",
50
52
  "@sxzz/test-utils": "^0.5.5",
53
+ "@types/babel__generator": "^7.27.0",
51
54
  "@types/debug": "^4.1.12",
52
55
  "@types/diff": "^7.0.2",
53
- "@types/node": "^22.14.1",
56
+ "@types/node": "^22.15.2",
54
57
  "bumpp": "^10.1.0",
55
58
  "diff": "^7.0.0",
56
59
  "eslint": "^9.25.1",
57
60
  "estree-walker": "^3.0.3",
58
61
  "prettier": "^3.5.3",
59
- "rolldown": "1.0.0-beta.7-commit.c2596d3",
62
+ "rolldown": "1.0.0-beta.8-commit.6aca0ce",
60
63
  "rollup-plugin-dts": "^6.2.1",
61
- "tsdown": "^0.9.6",
64
+ "tinyglobby": "^0.2.13",
65
+ "tsdown": "^0.9.8",
62
66
  "tsx": "^4.19.3",
63
67
  "typescript": "^5.8.3",
64
68
  "vitest": "^3.1.2"