rolldown-plugin-dts 0.12.2 → 0.13.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.
package/README.md CHANGED
@@ -32,60 +32,87 @@ You can find an example in [here](./rolldown.config.ts).
32
32
  ## Options
33
33
 
34
34
  ```ts
35
- interface Options {
35
+ export interface Options {
36
36
  /**
37
- * The directory where the the plugin will look for the `tsconfig.json` file.
37
+ * The directory in which the plugin will search for the `tsconfig.json` file.
38
38
  */
39
39
  cwd?: string
40
40
 
41
41
  /**
42
- * When entries are `.d.ts` files (instead of `.ts` files), this option should be set to `true`.
42
+ * Set to `true` if your entry files are `.d.ts` files instead of `.ts` files.
43
43
  *
44
- * If enabled, the plugin will skip generating a `.d.ts` file for the entry point.
44
+ * When enabled, the plugin will skip generating a `.d.ts` file for the entry point.
45
45
  */
46
46
  dtsInput?: boolean
47
47
 
48
48
  /**
49
- * When `true`, the plugin will only emit `.d.ts` files and remove all other chunks.
49
+ * If `true`, the plugin will emit only `.d.ts` files and remove all other output chunks.
50
50
  *
51
- * This feature is particularly beneficial when you need to generate `d.ts` files for the CommonJS format as part of a separate build process.
51
+ * This is especially useful when generating `.d.ts` files for the CommonJS format as part of a separate build step.
52
52
  */
53
53
  emitDtsOnly?: boolean
54
54
 
55
55
  /**
56
56
  * The path to the `tsconfig.json` file.
57
57
  *
58
- * When set to `false`, the plugin will ignore any `tsconfig.json` file.
59
- * However, `compilerOptions` can still be specified directly in the options.
58
+ * If set to `false`, the plugin will ignore any `tsconfig.json` file.
59
+ * You can still specify `compilerOptions` directly in the options.
60
60
  *
61
- * @default `tsconfig.json`
61
+ * @default 'tsconfig.json'
62
62
  */
63
63
  tsconfig?: string | boolean
64
64
 
65
65
  /**
66
- * The `compilerOptions` for the TypeScript compiler.
66
+ * Pass a raw `tsconfig.json` object directly to the plugin.
67
67
  *
68
- * @see https://www.typescriptlang.org/docs/handbook/compiler-options.html
68
+ * @see https://www.typescriptlang.org/tsconfig
69
+ */
70
+ tsconfigRaw?: Omit<TsConfigJson, 'compilerOptions'>
71
+
72
+ /**
73
+ * Override the `compilerOptions` specified in `tsconfig.json`.
74
+ *
75
+ * @see https://www.typescriptlang.org/tsconfig/#compilerOptions
69
76
  */
70
77
  compilerOptions?: TsConfigJson.CompilerOptions
71
78
 
72
79
  /**
73
- * When `true`, the plugin will generate `.d.ts` files using Oxc,
74
- * which is blazingly faster than `typescript` compiler.
80
+ * If `true`, the plugin will generate `.d.ts` files using Oxc,
81
+ * which is significantly faster than the TypeScript compiler.
75
82
  *
76
- * This option is enabled when `isolatedDeclarations` in `compilerOptions` is set to `true`.
83
+ * This option is automatically enabled when `isolatedDeclarations` in `compilerOptions` is set to `true`.
77
84
  */
78
85
  isolatedDeclarations?:
79
86
  | boolean
80
87
  | Omit<IsolatedDeclarationsOptions, 'sourcemap'>
81
88
 
82
89
  /**
83
- * When `true`, the plugin will generate declaration maps for `.d.ts` files.
90
+ * If `true`, the plugin will generate declaration maps (`.d.ts.map`) for `.d.ts` files.
84
91
  */
85
92
  sourcemap?: boolean
86
93
 
87
- /** Resolve external types used in dts files from `node_modules` */
94
+ /**
95
+ * Resolve external types used in `.d.ts` files from `node_modules`.
96
+ */
88
97
  resolve?: boolean | (string | RegExp)[]
98
+
99
+ /**
100
+ * If `true`, the plugin will generate `.d.ts` files using `vue-tsc`.
101
+ */
102
+ vue?: boolean
103
+
104
+ /**
105
+ * If `true`, the plugin will launch a separate process for `tsc` or `vue-tsc`.
106
+ * This enables processing multiple projects in parallel.
107
+ */
108
+ parallel?: boolean
109
+
110
+ /**
111
+ * If `true`, the plugin will prepare all files listed in `tsconfig.json` for `tsc` or `vue-tsc`.
112
+ *
113
+ * This is especially useful when you have a single `tsconfig.json` for multiple projects in a monorepo.
114
+ */
115
+ eager?: boolean
89
116
  }
90
117
  ```
91
118
 
package/dist/index.d.ts CHANGED
@@ -11,81 +11,106 @@ declare function createFakeJsPlugin({
11
11
  //#endregion
12
12
  //#region src/generate.d.ts
13
13
  declare function createGeneratePlugin({
14
- compilerOptions,
14
+ tsconfigRaw,
15
+ tsconfigDir,
15
16
  isolatedDeclarations,
16
17
  emitDtsOnly,
17
- vue
18
- }: Pick<OptionsResolved, "compilerOptions" | "isolatedDeclarations" | "emitDtsOnly" | "vue">): Plugin;
18
+ vue,
19
+ parallel,
20
+ eager
21
+ }: Pick<OptionsResolved, "tsconfigRaw" | "tsconfigDir" | "isolatedDeclarations" | "emitDtsOnly" | "vue" | "parallel" | "eager">): Plugin;
19
22
 
20
23
  //#endregion
21
24
  //#region src/index.d.ts
22
25
  interface Options {
23
26
  /**
24
- * The directory where the the plugin will look for the `tsconfig.json` file.
27
+ * The directory in which the plugin will search for the `tsconfig.json` file.
25
28
  */
26
29
  cwd?: string;
27
30
  /**
28
- * When entries are `.d.ts` files (instead of `.ts` files), this option should be set to `true`.
31
+ * Set to `true` if your entry files are `.d.ts` files instead of `.ts` files.
29
32
  *
30
- * If enabled, the plugin will skip generating a `.d.ts` file for the entry point.
33
+ * When enabled, the plugin will skip generating a `.d.ts` file for the entry point.
31
34
  */
32
35
  dtsInput?: boolean;
33
36
  /**
34
- * When `true`, the plugin will only emit `.d.ts` files and remove all other chunks.
37
+ * If `true`, the plugin will emit only `.d.ts` files and remove all other output chunks.
35
38
  *
36
- * This feature is particularly beneficial when you need to generate `d.ts` files for the CommonJS format as part of a separate build process.
39
+ * This is especially useful when generating `.d.ts` files for the CommonJS format as part of a separate build step.
37
40
  */
38
41
  emitDtsOnly?: boolean;
39
42
  /**
40
43
  * The path to the `tsconfig.json` file.
41
44
  *
42
- * When set to `false`, the plugin will ignore any `tsconfig.json` file.
43
- * However, `compilerOptions` can still be specified directly in the options.
45
+ * If set to `false`, the plugin will ignore any `tsconfig.json` file.
46
+ * You can still specify `compilerOptions` directly in the options.
44
47
  *
45
- * @default `tsconfig.json`
48
+ * @default 'tsconfig.json'
46
49
  */
47
50
  tsconfig?: string | boolean;
48
51
  /**
49
- * The `compilerOptions` for the TypeScript compiler.
52
+ * Pass a raw `tsconfig.json` object directly to the plugin.
53
+ *
54
+ * @see https://www.typescriptlang.org/tsconfig
55
+ */
56
+ tsconfigRaw?: Omit<TsConfigJson, "compilerOptions">;
57
+ /**
58
+ * Override the `compilerOptions` specified in `tsconfig.json`.
50
59
  *
51
- * @see https://www.typescriptlang.org/docs/handbook/compiler-options.html
60
+ * @see https://www.typescriptlang.org/tsconfig/#compilerOptions
52
61
  */
53
62
  compilerOptions?: TsConfigJson.CompilerOptions;
54
63
  /**
55
- * When `true`, the plugin will generate `.d.ts` files using Oxc,
56
- * which is blazingly faster than `typescript` compiler.
64
+ * If `true`, the plugin will generate `.d.ts` files using Oxc,
65
+ * which is significantly faster than the TypeScript compiler.
57
66
  *
58
- * This option is enabled when `isolatedDeclarations` in `compilerOptions` is set to `true`.
67
+ * This option is automatically enabled when `isolatedDeclarations` in `compilerOptions` is set to `true`.
59
68
  */
60
69
  isolatedDeclarations?: boolean | Omit<IsolatedDeclarationsOptions, "sourcemap">;
61
70
  /**
62
- * When `true`, the plugin will generate declaration maps for `.d.ts` files.
71
+ * If `true`, the plugin will generate declaration maps (`.d.ts.map`) for `.d.ts` files.
63
72
  */
64
73
  sourcemap?: boolean;
65
- /** Resolve external types used in dts files from `node_modules` */
74
+ /**
75
+ * Resolve external types used in `.d.ts` files from `node_modules`.
76
+ */
66
77
  resolve?: boolean | (string | RegExp)[];
67
78
  /**
68
- * When `true`, the plugin will generate `.d.ts` via `vue-tsc`.
79
+ * If `true`, the plugin will generate `.d.ts` files using `vue-tsc`.
69
80
  */
70
81
  vue?: boolean;
82
+ /**
83
+ * If `true`, the plugin will launch a separate process for `tsc` or `vue-tsc`.
84
+ * This enables processing multiple projects in parallel.
85
+ */
86
+ parallel?: boolean;
87
+ /**
88
+ * If `true`, the plugin will prepare all files listed in `tsconfig.json` for `tsc` or `vue-tsc`.
89
+ *
90
+ * This is especially useful when you have a single `tsconfig.json` for multiple projects in a monorepo.
91
+ */
92
+ eager?: boolean;
71
93
  }
72
94
  type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U;
73
- type OptionsResolved = Overwrite<Required<Options>, {
95
+ type OptionsResolved = Overwrite<Required<Omit<Options, "compilerOptions">>, {
74
96
  tsconfig: string | undefined;
75
97
  isolatedDeclarations: IsolatedDeclarationsOptions | false;
98
+ tsconfigRaw: TsConfigJson;
99
+ tsconfigDir: string;
76
100
  }>;
77
101
  declare function dts(options?: Options): Plugin[];
78
102
  declare function resolveOptions({
79
103
  cwd,
80
104
  tsconfig,
81
105
  compilerOptions,
106
+ tsconfigRaw: overriddenTsconfigRaw,
82
107
  isolatedDeclarations,
83
108
  sourcemap,
84
109
  dtsInput,
85
110
  emitDtsOnly,
86
111
  resolve,
87
- vue
88
- }: Options): OptionsResolved;
89
-
90
- //#endregion
112
+ vue,
113
+ parallel,
114
+ eager
115
+ }: Options): OptionsResolved; //#endregion
91
116
  export { Options, OptionsResolved, createFakeJsPlugin, createGeneratePlugin, dts, resolveOptions };
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
- import { createRequire } from "node:module";
2
1
  import path from "node:path";
3
2
  import process from "node:process";
4
3
  import Debug from "debug";
@@ -7,6 +6,8 @@ import _generate from "@babel/generator";
7
6
  import { parse } from "@babel/parser";
8
7
  import * as t from "@babel/types";
9
8
  import { isDeclarationType, isTypeOf } from "ast-kit";
9
+ import { fork } from "node:child_process";
10
+ import { createBirpc } from "birpc";
10
11
  import { ResolverFactory, isolatedDeclaration } from "rolldown/experimental";
11
12
  import { createResolver } from "dts-resolver";
12
13
 
@@ -297,7 +298,6 @@ function createFakeJsPlugin({ dtsInput, sourcemap }) {
297
298
  const isDecl = isTypeOf(stmt, ["ExportNamedDeclaration", "ExportDefaultDeclaration"]) && stmt.declaration;
298
299
  const decl = isDecl ? stmt.declaration : stmt;
299
300
  const setDecl = isDecl ? (node) => stmt.declaration = node : setStmt;
300
- if (decl.type === "VariableDeclaration" && decl.declarations.length !== 1) throw new Error("Only one declaration is supported");
301
301
  if (decl.type !== "TSDeclareFunction" && !isDeclarationType(decl)) continue;
302
302
  if (isTypeOf(decl, [
303
303
  "TSEnumDeclaration",
@@ -307,12 +307,17 @@ function createFakeJsPlugin({ dtsInput, sourcemap }) {
307
307
  "TSModuleDeclaration",
308
308
  "VariableDeclaration"
309
309
  ])) decl.declare = true;
310
- let binding = decl.type === "VariableDeclaration" ? decl.declarations[0].id : "id" in decl ? decl.id : null;
311
- if (!binding) {
312
- binding = t.identifier("export_default");
310
+ const bindings = [];
311
+ if (decl.type === "VariableDeclaration") bindings.push(...decl.declarations.map((decl$1) => decl$1.id));
312
+ else if ("id" in decl && decl.id) {
313
+ let binding = decl.id;
314
+ binding = sideEffect ? t.identifier(`_${identifierIdx++}`) : binding;
315
+ bindings.push(binding);
316
+ } else {
317
+ const binding = t.identifier("export_default");
318
+ bindings.push(binding);
313
319
  decl.id = binding;
314
320
  }
315
- binding = sideEffect ? t.identifier(`_${identifierIdx++}`) : binding;
316
321
  const deps = collectDependencies(decl, namespaceStmts);
317
322
  const elements = [
318
323
  t.numericLiteral(0),
@@ -328,7 +333,7 @@ function createFakeJsPlugin({ dtsInput, sourcemap }) {
328
333
  const symbolId = registerSymbol({
329
334
  decl,
330
335
  deps,
331
- binding
336
+ bindings
332
337
  });
333
338
  elements[0] = t.numericLiteral(symbolId);
334
339
  const runtimeAssignment = {
@@ -337,14 +342,20 @@ function createFakeJsPlugin({ dtsInput, sourcemap }) {
337
342
  declarations: [{
338
343
  type: "VariableDeclarator",
339
344
  id: {
340
- ...binding,
345
+ ...bindings[0],
341
346
  typeAnnotation: null
342
347
  },
343
348
  init: runtime
344
- }]
349
+ }, ...bindings.slice(1).map((binding) => ({
350
+ type: "VariableDeclarator",
351
+ id: {
352
+ ...binding,
353
+ typeAnnotation: null
354
+ }
355
+ }))]
345
356
  };
346
357
  if (isDefaultExport) {
347
- appendStmts.push(t.exportNamedDeclaration(null, [t.exportSpecifier(binding, t.identifier("default"))]));
358
+ appendStmts.push(t.exportNamedDeclaration(null, [t.exportSpecifier(bindings[0], t.identifier("default"))]));
348
359
  setStmt(runtimeAssignment);
349
360
  } else setDecl(runtimeAssignment);
350
361
  }
@@ -367,18 +378,20 @@ function createFakeJsPlugin({ dtsInput, sourcemap }) {
367
378
  program.body = patchTsNamespace(program.body);
368
379
  program.body = program.body.map((node) => {
369
380
  if (patchImportSource(node)) return node;
370
- if (node.type !== "VariableDeclaration" || node.declarations.length !== 1) return node;
381
+ if (node.type !== "VariableDeclaration") return node;
371
382
  const [decl] = node.declarations;
372
383
  if (decl.init?.type !== "ArrayExpression" || !decl.init.elements[0]) return null;
373
384
  const [symbolIdNode, ...depsFns] = decl.init.elements;
374
385
  if (symbolIdNode?.type !== "NumericLiteral") return null;
375
386
  const symbolId = symbolIdNode.value;
376
387
  const original = getSymbol(symbolId);
377
- const transformedBinding = {
378
- ...decl.id,
379
- typeAnnotation: original.binding.typeAnnotation
380
- };
381
- overwriteNode(original.binding, transformedBinding);
388
+ for (const [i, decl$1] of node.declarations.entries()) {
389
+ const transformedBinding = {
390
+ ...decl$1.id,
391
+ typeAnnotation: original.bindings[i].typeAnnotation
392
+ };
393
+ overwriteNode(original.bindings[i], transformedBinding);
394
+ }
382
395
  const transformedDeps = depsFns.filter((node$1) => node$1?.type === "ArrowFunctionExpression").map((node$1) => node$1.body);
383
396
  if (original.deps.length) for (let i = 0; i < original.deps.length; i++) {
384
397
  const originalDep = original.deps[i];
@@ -616,153 +629,11 @@ function inheritNodeComments(oldNode, newNode) {
616
629
  }
617
630
  }
618
631
 
619
- //#endregion
620
- //#region src/utils/vue.ts
621
- const debug$3 = Debug("rolldown-plugin-dts:vue");
622
- let createVueProgram;
623
- const require = createRequire(import.meta.url);
624
- function loadVueLanguageTools() {
625
- try {
626
- const vueTscPath = require.resolve("vue-tsc");
627
- const { proxyCreateProgram } = require(require.resolve("@volar/typescript", { paths: [vueTscPath] }));
628
- const vue = require(require.resolve("@vue/language-core", { paths: [vueTscPath] }));
629
- return {
630
- proxyCreateProgram,
631
- vue
632
- };
633
- } catch (error) {
634
- debug$3("vue language tools not found", error);
635
- throw new Error("Failed to load vue language tools. Please manually install vue-tsc.");
636
- }
637
- }
638
- function createVueProgramFactory() {
639
- if (createVueProgram) return createVueProgram;
640
- debug$3("loading vue language tools");
641
- const { proxyCreateProgram, vue } = loadVueLanguageTools();
642
- return createVueProgram = proxyCreateProgram(ts, ts.createProgram, (ts$1, options) => {
643
- const { configFilePath } = options.options;
644
- const vueOptions = typeof configFilePath === "string" ? vue.createParsedCommandLine(ts$1, ts$1.sys, configFilePath.replaceAll("\\", "/")).vueOptions : vue.getDefaultCompilerOptions();
645
- const vueLanguagePlugin = vue.createVueLanguagePlugin(ts$1, options.options, vueOptions, (id) => id);
646
- return { languagePlugins: [vueLanguagePlugin] };
647
- });
648
- }
649
-
650
- //#endregion
651
- //#region src/utils/tsc.ts
652
- const debug$2 = Debug("rolldown-plugin-dts:tsc");
653
- let ts;
654
- let formatHost;
655
- function initTs() {
656
- debug$2("loading typescript");
657
- const require$1 = createRequire(import.meta.url);
658
- ts = require$1("typescript");
659
- formatHost = {
660
- getCurrentDirectory: () => ts.sys.getCurrentDirectory(),
661
- getNewLine: () => ts.sys.newLine,
662
- getCanonicalFileName: ts.sys.useCaseSensitiveFileNames ? (f) => f : (f) => f.toLowerCase()
663
- };
664
- debug$2(`loaded typescript: ${ts.version}`);
665
- }
666
- const defaultCompilerOptions = {
667
- declaration: true,
668
- noEmit: false,
669
- emitDeclarationOnly: true,
670
- noEmitOnError: true,
671
- checkJs: false,
672
- declarationMap: false,
673
- skipLibCheck: true,
674
- target: 99,
675
- resolveJsonModule: true
676
- };
677
- function createOrGetTsModule(programs, compilerOptions, id, isEntry, dtsMap, vue) {
678
- const program = programs.find((program$1) => {
679
- if (isEntry) return program$1.getRootFileNames().includes(id);
680
- return program$1.getSourceFile(id);
681
- });
682
- if (program) {
683
- const sourceFile = program.getSourceFile(id);
684
- if (sourceFile) return {
685
- program,
686
- file: sourceFile
687
- };
688
- }
689
- debug$2(`create program for module: ${id}`);
690
- const module = createTsProgram(compilerOptions, dtsMap, id, vue);
691
- debug$2(`created program for module: ${id}`);
692
- programs.push(module.program);
693
- return module;
694
- }
695
- function createTsProgram(compilerOptions, dtsMap, id, vue) {
696
- const overrideCompilerOptions = ts.convertCompilerOptionsFromJson(compilerOptions, ".").options;
697
- const options = {
698
- ...defaultCompilerOptions,
699
- ...overrideCompilerOptions
700
- };
701
- const host = ts.createCompilerHost(options, true);
702
- const { readFile: _readFile, fileExists: _fileExists } = host;
703
- host.fileExists = (fileName) => {
704
- const module = getTsModule(dtsMap, fileName);
705
- if (module) return true;
706
- if (debug$2.enabled && !RE_NODE_MODULES.test(fileName)) debug$2(`file exists from fs: ${fileName}`);
707
- return _fileExists(fileName);
708
- };
709
- host.readFile = (fileName) => {
710
- const module = getTsModule(dtsMap, fileName);
711
- if (module) return module.code;
712
- if (debug$2.enabled && !RE_NODE_MODULES.test(fileName)) debug$2(`read file from fs: ${fileName}`);
713
- return _readFile(fileName);
714
- };
715
- const entries = [...new Set([...Array.from(dtsMap.values()).filter((v) => v.isEntry).map((v) => v.id), id])];
716
- const createProgram = vue ? createVueProgramFactory() : ts.createProgram;
717
- const program = createProgram({
718
- rootNames: entries,
719
- options,
720
- host
721
- });
722
- const sourceFile = program.getSourceFile(id);
723
- if (!sourceFile) throw new Error(`Source file not found: ${id}`);
724
- return {
725
- program,
726
- file: sourceFile
727
- };
728
- }
729
- function tscEmit(module) {
730
- const { program, file } = module;
731
- let dtsCode;
732
- let map;
733
- const { emitSkipped, diagnostics } = program.emit(
734
- file,
735
- (fileName, code) => {
736
- if (fileName.endsWith(".map")) {
737
- debug$2(`emit dts sourcemap: ${fileName}`);
738
- map = JSON.parse(code);
739
- } else {
740
- debug$2(`emit dts: ${fileName}`);
741
- dtsCode = code;
742
- }
743
- },
744
- void 0,
745
- true,
746
- void 0,
747
- // @ts-expect-error private API: forceDtsEmit
748
- true
749
- );
750
- if (emitSkipped && diagnostics.length) return { error: ts.formatDiagnostics(diagnostics, formatHost) };
751
- return {
752
- code: dtsCode,
753
- map
754
- };
755
- }
756
- function getTsModule(dtsMap, tsId) {
757
- const module = Array.from(dtsMap.values()).find((dts$1) => dts$1.id === tsId);
758
- if (!module) return;
759
- return module;
760
- }
761
-
762
632
  //#endregion
763
633
  //#region src/generate.ts
764
634
  const debug$1 = Debug("rolldown-plugin-dts:generate");
765
- function createGeneratePlugin({ compilerOptions = {}, isolatedDeclarations, emitDtsOnly = false, vue }) {
635
+ const WORKER_URL = "./utils/tsc-worker.js";
636
+ function createGeneratePlugin({ tsconfigRaw, tsconfigDir, isolatedDeclarations, emitDtsOnly, vue, parallel, eager }) {
766
637
  const dtsMap = new Map();
767
638
  /**
768
639
  * A map of input id to output file name
@@ -774,14 +645,20 @@ function createGeneratePlugin({ compilerOptions = {}, isolatedDeclarations, emit
774
645
  * ])
775
646
  */
776
647
  const inputAliasMap = new Map();
777
- let programs = [];
778
- if (vue || !isolatedDeclarations) {
779
- initTs();
780
- if (vue) createVueProgramFactory();
648
+ let childProcess;
649
+ let rpc;
650
+ let tscEmit;
651
+ if (parallel) {
652
+ childProcess = fork(new URL(WORKER_URL, import.meta.url), { stdio: "inherit" });
653
+ rpc = createBirpc({}, {
654
+ post: (data) => childProcess.send(data),
655
+ on: (fn) => childProcess.on("message", fn)
656
+ });
781
657
  }
782
658
  return {
783
659
  name: "rolldown-plugin-dts:generate",
784
660
  async buildStart(options) {
661
+ if (!parallel && (!isolatedDeclarations || vue)) ({tscEmit} = await import("./tsc-CeRgkVKp.js"));
785
662
  if (!Array.isArray(options.input)) for (const [name, id] of Object.entries(options.input)) {
786
663
  debug$1("resolving input alias %s -> %s", name, id);
787
664
  let resolved = await this.resolve(id);
@@ -839,7 +716,7 @@ function createGeneratePlugin({ compilerOptions = {}, isolatedDeclarations, emit
839
716
  include: [RE_DTS],
840
717
  exclude: [RE_NODE_MODULES]
841
718
  } },
842
- handler(dtsId) {
719
+ async handler(dtsId) {
843
720
  if (!dtsMap.has(dtsId)) return;
844
721
  const { code, id, isEntry } = dtsMap.get(dtsId);
845
722
  let dtsCode;
@@ -860,8 +737,18 @@ function createGeneratePlugin({ compilerOptions = {}, isolatedDeclarations, emit
860
737
  map.sourcesContent = void 0;
861
738
  }
862
739
  } else {
863
- const module = createOrGetTsModule(programs, compilerOptions, id, isEntry, dtsMap, vue);
864
- const result = tscEmit(module);
740
+ const entries = eager ? void 0 : Array.from(dtsMap.values()).filter((v) => v.isEntry).map((v) => v.id);
741
+ const options = {
742
+ tsconfigRaw,
743
+ tsconfigDir,
744
+ entries,
745
+ id,
746
+ isEntry,
747
+ vue
748
+ };
749
+ let result;
750
+ if (parallel) result = await rpc.tscEmit(options);
751
+ else result = tscEmit(options);
865
752
  if (result.error) return this.error(result.error);
866
753
  dtsCode = result.code;
867
754
  map = result.map;
@@ -877,7 +764,7 @@ function createGeneratePlugin({ compilerOptions = {}, isolatedDeclarations, emit
877
764
  for (const fileName of Object.keys(bundle)) if (bundle[fileName].type === "chunk" && !RE_DTS.test(fileName) && !RE_DTS_MAP.test(fileName)) delete bundle[fileName];
878
765
  } : void 0,
879
766
  buildEnd() {
880
- programs = [];
767
+ childProcess?.kill();
881
768
  }
882
769
  };
883
770
  }
@@ -942,24 +829,28 @@ function dts(options = {}) {
942
829
  plugins.push(createDtsResolvePlugin(resolved), createFakeJsPlugin(resolved));
943
830
  return plugins;
944
831
  }
945
- function resolveOptions({ cwd = process.cwd(), tsconfig, compilerOptions = {}, isolatedDeclarations, sourcemap, dtsInput = false, emitDtsOnly = false, resolve = false, vue = false }) {
832
+ function resolveOptions({ cwd = process.cwd(), tsconfig, compilerOptions = {}, tsconfigRaw: overriddenTsconfigRaw = {}, isolatedDeclarations, sourcemap, dtsInput = false, emitDtsOnly = false, resolve = false, vue = false, parallel = false, eager = false }) {
833
+ let resolvedTsconfig;
946
834
  if (tsconfig === true || tsconfig == null) {
947
835
  const { config, path: path$1 } = getTsconfig(cwd) || {};
948
836
  tsconfig = path$1;
949
- compilerOptions = {
950
- ...config?.compilerOptions,
951
- ...compilerOptions
952
- };
837
+ resolvedTsconfig = config;
953
838
  } else if (typeof tsconfig === "string") {
954
839
  tsconfig = path.resolve(cwd || process.cwd(), tsconfig);
955
- const config = parseTsconfig(tsconfig);
956
- compilerOptions = {
957
- ...config.compilerOptions,
958
- ...compilerOptions
959
- };
840
+ resolvedTsconfig = parseTsconfig(tsconfig);
960
841
  } else tsconfig = void 0;
842
+ compilerOptions = {
843
+ ...resolvedTsconfig?.compilerOptions,
844
+ ...compilerOptions
845
+ };
961
846
  sourcemap ??= !!compilerOptions.declarationMap;
962
847
  compilerOptions.declarationMap = sourcemap;
848
+ const tsconfigRaw = {
849
+ ...resolvedTsconfig,
850
+ ...overriddenTsconfigRaw,
851
+ compilerOptions
852
+ };
853
+ const tsconfigDir = tsconfig ? path.dirname(tsconfig) : cwd;
963
854
  if (isolatedDeclarations == null) isolatedDeclarations = !!compilerOptions?.isolatedDeclarations;
964
855
  if (isolatedDeclarations === true) isolatedDeclarations = {};
965
856
  if (isolatedDeclarations) {
@@ -969,13 +860,16 @@ function resolveOptions({ cwd = process.cwd(), tsconfig, compilerOptions = {}, i
969
860
  return {
970
861
  cwd,
971
862
  tsconfig,
972
- compilerOptions,
863
+ tsconfigDir,
864
+ tsconfigRaw,
973
865
  isolatedDeclarations,
974
866
  sourcemap,
975
867
  dtsInput,
976
868
  emitDtsOnly,
977
869
  resolve,
978
- vue
870
+ vue,
871
+ parallel,
872
+ eager
979
873
  };
980
874
  }
981
875
 
@@ -0,0 +1,3 @@
1
+ import { tscEmit } from "./tsc-H_wSbW_C.js";
2
+
3
+ export { tscEmit };
@@ -0,0 +1,128 @@
1
+ import { createRequire } from "node:module";
2
+ import Debug from "debug";
3
+ import ts from "typescript";
4
+
5
+ //#region src/utils/vue.ts
6
+ const debug$1 = Debug("rolldown-plugin-dts:vue");
7
+ let createVueProgram;
8
+ const require = createRequire(import.meta.url);
9
+ function loadVueLanguageTools() {
10
+ try {
11
+ const vueTscPath = require.resolve("vue-tsc");
12
+ const { proxyCreateProgram } = require(require.resolve("@volar/typescript", { paths: [vueTscPath] }));
13
+ const vue = require(require.resolve("@vue/language-core", { paths: [vueTscPath] }));
14
+ return {
15
+ proxyCreateProgram,
16
+ vue
17
+ };
18
+ } catch (error) {
19
+ debug$1("vue language tools not found", error);
20
+ throw new Error("Failed to load vue language tools. Please manually install vue-tsc.");
21
+ }
22
+ }
23
+ function createVueProgramFactory(ts$1) {
24
+ if (createVueProgram) return createVueProgram;
25
+ debug$1("loading vue language tools");
26
+ const { proxyCreateProgram, vue } = loadVueLanguageTools();
27
+ return createVueProgram = proxyCreateProgram(ts$1, ts$1.createProgram, (ts$2, options) => {
28
+ const { configFilePath } = options.options;
29
+ const vueOptions = typeof configFilePath === "string" ? vue.createParsedCommandLine(ts$2, ts$2.sys, configFilePath.replaceAll("\\", "/")).vueOptions : vue.getDefaultCompilerOptions();
30
+ const vueLanguagePlugin = vue.createVueLanguagePlugin(ts$2, options.options, vueOptions, (id) => id);
31
+ return { languagePlugins: [vueLanguagePlugin] };
32
+ });
33
+ }
34
+
35
+ //#endregion
36
+ //#region src/utils/tsc.ts
37
+ const debug = Debug("rolldown-plugin-dts:tsc");
38
+ debug(`loaded typescript: ${ts.version}`);
39
+ const programs = [];
40
+ const formatHost = {
41
+ getCurrentDirectory: () => ts.sys.getCurrentDirectory(),
42
+ getNewLine: () => ts.sys.newLine,
43
+ getCanonicalFileName: ts.sys.useCaseSensitiveFileNames ? (f) => f : (f) => f.toLowerCase()
44
+ };
45
+ const defaultCompilerOptions = {
46
+ declaration: true,
47
+ noEmit: false,
48
+ emitDeclarationOnly: true,
49
+ noEmitOnError: true,
50
+ checkJs: false,
51
+ declarationMap: false,
52
+ skipLibCheck: true,
53
+ target: 99,
54
+ resolveJsonModule: true,
55
+ moduleResolution: ts.ModuleResolutionKind.Bundler
56
+ };
57
+ function createOrGetTsModule(options) {
58
+ const { id, isEntry } = options;
59
+ const program = programs.find((program$1) => {
60
+ if (isEntry) return program$1.getRootFileNames().includes(id);
61
+ return program$1.getSourceFile(id);
62
+ });
63
+ if (program) {
64
+ const sourceFile = program.getSourceFile(id);
65
+ if (sourceFile) return {
66
+ program,
67
+ file: sourceFile
68
+ };
69
+ }
70
+ debug(`create program for module: ${id}`);
71
+ const module = createTsProgram(options);
72
+ debug(`created program for module: ${id}`);
73
+ programs.push(module.program);
74
+ return module;
75
+ }
76
+ function createTsProgram({ entries, id, tsconfigRaw, tsconfigDir, vue }) {
77
+ const parsedCmd = ts.parseJsonConfigFileContent(tsconfigRaw, ts.sys, tsconfigDir);
78
+ const compilerOptions = {
79
+ ...defaultCompilerOptions,
80
+ ...parsedCmd.options
81
+ };
82
+ const rootNames = entries ? [...new Set([id, ...entries])] : parsedCmd.fileNames;
83
+ const host = ts.createCompilerHost(compilerOptions, true);
84
+ const createProgram = vue ? createVueProgramFactory(ts) : ts.createProgram;
85
+ const program = createProgram({
86
+ rootNames,
87
+ options: compilerOptions,
88
+ host,
89
+ projectReferences: parsedCmd.projectReferences
90
+ });
91
+ const sourceFile = program.getSourceFile(id);
92
+ if (!sourceFile) throw new Error(`Source file not found: ${id}`);
93
+ return {
94
+ program,
95
+ file: sourceFile
96
+ };
97
+ }
98
+ function tscEmit(tscOptions) {
99
+ const module = createOrGetTsModule(tscOptions);
100
+ const { program, file } = module;
101
+ let dtsCode;
102
+ let map;
103
+ const { emitSkipped, diagnostics } = program.emit(
104
+ file,
105
+ (fileName, code) => {
106
+ if (fileName.endsWith(".map")) {
107
+ debug(`emit dts sourcemap: ${fileName}`);
108
+ map = JSON.parse(code);
109
+ } else {
110
+ debug(`emit dts: ${fileName}`);
111
+ dtsCode = code;
112
+ }
113
+ },
114
+ void 0,
115
+ true,
116
+ void 0,
117
+ // @ts-expect-error private API: forceDtsEmit
118
+ true
119
+ );
120
+ if (emitSkipped && diagnostics.length) return { error: ts.formatDiagnostics(diagnostics, formatHost) };
121
+ return {
122
+ code: dtsCode,
123
+ map
124
+ };
125
+ }
126
+
127
+ //#endregion
128
+ export { tscEmit };
@@ -0,0 +1,27 @@
1
+ import { TsConfigJson } from "get-tsconfig";
2
+ import ts from "typescript";
3
+
4
+ //#region src/utils/tsc.d.ts
5
+
6
+ interface TscOptions {
7
+ tsconfigRaw: TsConfigJson;
8
+ tsconfigDir: string;
9
+ entries?: string[];
10
+ id: string;
11
+ isEntry: boolean;
12
+ vue?: boolean;
13
+ }
14
+ interface TscResult {
15
+ code?: string;
16
+ map?: any;
17
+ error?: string;
18
+ }
19
+ declare function tscEmit(tscOptions: TscOptions): TscResult; //#endregion
20
+ //#region src/utils/tsc-worker.d.ts
21
+ declare const functions: {
22
+ tscEmit: typeof tscEmit;
23
+ };
24
+ type TscFunctions = typeof functions;
25
+
26
+ //#endregion
27
+ export { TscFunctions };
@@ -0,0 +1,12 @@
1
+ import { tscEmit } from "../tsc-H_wSbW_C.js";
2
+ import process from "node:process";
3
+ import { createBirpc } from "birpc";
4
+
5
+ //#region src/utils/tsc-worker.ts
6
+ const functions = { tscEmit };
7
+ createBirpc(functions, {
8
+ post: (data) => process.send(data),
9
+ on: (fn) => process.on("message", fn)
10
+ });
11
+
12
+ //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rolldown-plugin-dts",
3
- "version": "0.12.2",
3
+ "version": "0.13.0",
4
4
  "description": "A Rolldown plugin to bundle dts files",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -45,6 +45,7 @@
45
45
  "@babel/parser": "^7.27.2",
46
46
  "@babel/types": "^7.27.1",
47
47
  "ast-kit": "^2.0.0",
48
+ "birpc": "^2.3.0",
48
49
  "debug": "^4.4.1",
49
50
  "dts-resolver": "^2.0.1",
50
51
  "get-tsconfig": "^4.10.0"