rolldown-plugin-dts 0.3.0 → 0.5.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
@@ -38,8 +38,26 @@ interface Options {
38
38
  */
39
39
  dtsInput?: boolean
40
40
 
41
- isolatedDeclaration?: Omit<IsolatedDeclarationsOptions, 'sourcemap'>
41
+ /**
42
+ * When `true`, the plugin will only emit `.d.ts` files and remove all other chunks.
43
+ *
44
+ * This feature is particularly beneficial when you need to generate `d.ts` files for the CommonJS format as part of a separate build process.
45
+ */
46
+ emitDtsOnly?: boolean
42
47
 
48
+ /**
49
+ * The `compilerOptions` for the TypeScript compiler.
50
+ *
51
+ * @see https://www.typescriptlang.org/docs/handbook/compiler-options.html
52
+ */
53
+ compilerOptions?: CompilerOptions
54
+ /**
55
+ * When `true`, the plugin will generate `.d.ts` files using `oxc-transform`,
56
+ * which is blazingly faster than `typescript` compiler.
57
+ *
58
+ * This option is enabled when `isolatedDeclaration` in `tsconfig.json` is set to `true`.
59
+ */
60
+ isolatedDeclaration?: boolean | Omit<IsolatedDeclarationsOptions, 'sourcemap'>
43
61
  /**
44
62
  * dts file name alias `{ [filename]: path }`
45
63
  *
@@ -56,16 +74,26 @@ interface Options {
56
74
  }
57
75
  ````
58
76
 
59
- ## Caveats
77
+ ## ⚠️ Caveats
60
78
 
61
- - The plugin uses Oxc's `isolatedDeclarations` to generate `.d.ts` files,
62
- which means you need to set `isolatedDeclarations: true` in your `tsconfig.json` and ensure there are no errors.
79
+ - The plugin leverages Oxc's `isolatedDeclarations` to generate `.d.ts` files when `isolatedDeclaration` is enabled,
80
+ offering significantly faster performance compared to the `typescript` compiler.
63
81
 
64
82
  - Namespaces are not supported yet.
65
83
  - `export * as ns from './ns'`
66
84
  - `import * as ns from './ns'` and then `export { ns }`
67
85
  - `type ns = import('./ns')`
68
86
 
87
+ ## Differences from `rollup-plugin-dts`
88
+
89
+ `rolldown-plugin-dts` generates separate chunks for `.d.ts` files, enabling both source code (`.js`)
90
+ and type definition files (`.d.ts`) to be produced in a single build process.
91
+
92
+ However, this functionality is limited to ESM output format. Consequently,
93
+ **two** distinct build processes are required for CommonJS source code (`.cjs`)
94
+ and its corresponding type definition files (`.d.cts`).
95
+ In such cases, the `emitDtsOnly` option can be particularly helpful.
96
+
69
97
  ## Credits
70
98
 
71
99
  The project is inspired by [rollup-plugin-dts](https://github.com/Swatinem/rollup-plugin-dts)
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { IsolatedDeclarationsOptions } from "oxc-transform";
2
+ import { CompilerOptions } from "typescript";
2
3
  import { Plugin } from "rolldown";
3
4
 
4
5
  //#region src/fake-js.d.ts
@@ -6,7 +7,7 @@ declare function createFakeJsPlugin({ dtsInput }: Pick<Options, "dtsInput">): Pl
6
7
 
7
8
  //#endregion
8
9
  //#region src/generate.d.ts
9
- declare function createGeneratePlugin({ isolatedDeclaration, inputAlias, resolve }: Pick<Options, "isolatedDeclaration" | "inputAlias" | "resolve">): Plugin;
10
+ declare function createGeneratePlugin({ compilerOptions, isolatedDeclaration, inputAlias, resolve, emitDtsOnly }: Pick<Options, "isolatedDeclaration" | "inputAlias" | "resolve" | "emitDtsOnly" | "compilerOptions">): Plugin;
10
11
 
11
12
  //#endregion
12
13
  //#region src/index.d.ts
@@ -17,7 +18,25 @@ interface Options {
17
18
  * If enabled, the plugin will skip generating a `.d.ts` file for the entry point.
18
19
  */
19
20
  dtsInput?: boolean;
20
- isolatedDeclaration?: Omit<IsolatedDeclarationsOptions, "sourcemap">;
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 `compilerOptions` for the TypeScript compiler.
29
+ *
30
+ * @see https://www.typescriptlang.org/docs/handbook/compiler-options.html
31
+ */
32
+ compilerOptions?: CompilerOptions;
33
+ /**
34
+ * When `true`, the plugin will generate `.d.ts` files using `oxc-transform`,
35
+ * which is blazingly faster than `typescript` compiler.
36
+ *
37
+ * This option is enabled when `isolatedDeclaration` in `tsconfig.json` is set to `true`.
38
+ */
39
+ isolatedDeclaration?: boolean | Omit<IsolatedDeclarationsOptions, "sourcemap">;
21
40
  /**
22
41
  * dts file name alias `{ [filename]: path }`
23
42
  *
package/dist/index.js CHANGED
@@ -1,8 +1,11 @@
1
1
  import { MagicStringAST } from "magic-string-ast";
2
2
  import { parseAsync } from "oxc-parser";
3
- import path, { basename } from "node:path";
3
+ import path, { basename, extname } from "node:path";
4
4
  import { createResolver } from "dts-resolver";
5
+ import { getTsconfig } from "get-tsconfig";
5
6
  import { isolatedDeclaration } from "oxc-transform";
7
+ import * as ts$1 from "typescript";
8
+ import * as ts from "typescript";
6
9
 
7
10
  //#region node_modules/.pnpm/estree-walker@3.0.3/node_modules/estree-walker/src/walker.js
8
11
  var WalkerBase = class {
@@ -433,19 +436,119 @@ function importNamespace(s, source, imported, getIdentifierIndex) {
433
436
  return local;
434
437
  }
435
438
 
439
+ //#endregion
440
+ //#region src/utils/tsc.ts
441
+ const defaultCompilerOptions = {
442
+ declaration: true,
443
+ noEmit: false,
444
+ emitDeclarationOnly: true,
445
+ noEmitOnError: true,
446
+ checkJs: false,
447
+ declarationMap: false,
448
+ skipLibCheck: true,
449
+ preserveSymlinks: true,
450
+ target: ts$1.ScriptTarget.ESNext,
451
+ resolveJsonModule: true
452
+ };
453
+ const formatHost = {
454
+ getCurrentDirectory: () => ts$1.sys.getCurrentDirectory(),
455
+ getNewLine: () => ts$1.sys.newLine,
456
+ getCanonicalFileName: ts$1.sys.useCaseSensitiveFileNames ? (f) => f : (f) => f.toLowerCase()
457
+ };
458
+ function createOrGetTsModule(programs, compilerOptions, id, code, isEntry) {
459
+ const tsProgram = programs.find(({ program }) => {
460
+ if (isEntry) return program.getRootFileNames().includes(id);
461
+ return program.getSourceFile(id);
462
+ });
463
+ if (tsProgram) {
464
+ const sourceFile = tsProgram.program.getSourceFile(id);
465
+ if (sourceFile) return {
466
+ program: tsProgram,
467
+ file: sourceFile
468
+ };
469
+ }
470
+ const module = createTsProgram(compilerOptions, id, code);
471
+ programs.push(module.program);
472
+ return module;
473
+ }
474
+ function createTsProgram(compilerOptions, id, code) {
475
+ const files = new Map([[id, code]]);
476
+ const options = {
477
+ ...defaultCompilerOptions,
478
+ ...loadTsconfig(id),
479
+ ...compilerOptions
480
+ };
481
+ const host = ts$1.createCompilerHost(options, true);
482
+ const { readFile: _readFile, fileExists: _fileExists } = host;
483
+ host.fileExists = (fileName) => {
484
+ if (files.has(fileName)) return true;
485
+ return _fileExists(fileName);
486
+ };
487
+ host.readFile = (fileName) => {
488
+ if (files.has(fileName)) return files.get(fileName);
489
+ return _readFile(fileName);
490
+ };
491
+ const program = ts$1.createProgram([id], {
492
+ ...compilerOptions,
493
+ moduleResolution: ts$1.ModuleResolutionKind.Node10,
494
+ declaration: true,
495
+ emitDeclarationOnly: true,
496
+ outDir: void 0,
497
+ declarationDir: void 0
498
+ }, host);
499
+ const sourceFile = program.getSourceFile(id);
500
+ if (!sourceFile) throw new Error(`Source file not found: ${id}`);
501
+ return {
502
+ program: {
503
+ program,
504
+ files
505
+ },
506
+ file: sourceFile
507
+ };
508
+ }
509
+ const tsconfigCache = new Map();
510
+ function loadTsconfig(id) {
511
+ const configPath = ts$1.findConfigFile(path.dirname(id), ts$1.sys.fileExists);
512
+ if (!configPath) return {};
513
+ if (tsconfigCache.has(configPath)) return tsconfigCache.get(configPath);
514
+ const { config, error } = ts$1.readConfigFile(configPath, ts$1.sys.readFile);
515
+ if (error) throw ts$1.formatDiagnostic(error, formatHost);
516
+ const configContents = ts$1.parseJsonConfigFileContent(config, ts$1.sys, path.dirname(configPath));
517
+ if (configContents.errors.length) throw ts$1.formatDiagnostics(configContents.errors, formatHost);
518
+ tsconfigCache.set(configPath, configContents.options);
519
+ return configContents.options;
520
+ }
521
+
436
522
  //#endregion
437
523
  //#region src/generate.ts
438
524
  const meta = { dtsFile: true };
439
- function createGeneratePlugin({ isolatedDeclaration: isolatedDeclaration$1, inputAlias = {}, resolve = false }) {
525
+ function createGeneratePlugin({ compilerOptions, isolatedDeclaration: isolatedDeclaration$1, inputAlias, resolve = false, emitDtsOnly = false }) {
440
526
  const dtsMap = new Map();
441
- const inputAliasMap = new Map(Object.entries(inputAlias));
527
+ const inputAliasMap = new Map(inputAlias && Object.entries(inputAlias));
442
528
  const resolver = createResolver();
529
+ let programs = [];
443
530
  let inputOption;
444
531
  return {
445
532
  name: "rolldown-plugin-dts:generate",
533
+ buildStart(options) {
534
+ if (isolatedDeclaration$1 == null) {
535
+ const { config } = getTsconfig(options.cwd) || {};
536
+ if (config?.compilerOptions?.isolatedDeclarations) isolatedDeclaration$1 = { stripInternal: !!config?.compilerOptions.stripInternal };
537
+ }
538
+ },
446
539
  options({ input }) {
447
540
  if (isPlainObject(input)) inputOption = { ...input };
448
541
  },
542
+ outputOptions(options) {
543
+ return {
544
+ ...options,
545
+ entryFileNames(chunk) {
546
+ const original = (typeof options.entryFileNames === "function" ? options.entryFileNames(chunk) : options.entryFileNames) || "[name].js";
547
+ if (chunk.name.endsWith(".d")) return original.replace(RE_JS, ".$1ts");
548
+ return original;
549
+ }
550
+ };
551
+ },
449
552
  transform: {
450
553
  order: "pre",
451
554
  filter: { id: {
@@ -453,20 +556,44 @@ function createGeneratePlugin({ isolatedDeclaration: isolatedDeclaration$1, inpu
453
556
  exclude: [RE_DTS, RE_NODE_MODULES]
454
557
  } },
455
558
  handler(code, id) {
456
- const { code: dtsCode, errors } = isolatedDeclaration(id, code, isolatedDeclaration$1);
457
- if (errors.length) return this.error(errors[0]);
458
- const dtsId = filename_ts_to_dts(id);
459
- dtsMap.set(dtsId, dtsCode);
559
+ let dtsCode;
460
560
  const mod = this.getModuleInfo(id);
461
- if (mod?.isEntry) {
462
- let fileName = basename(dtsId);
463
- if (inputAliasMap.has(fileName)) fileName = inputAliasMap.get(fileName);
464
- else if (inputAliasMap.has(dtsId)) fileName = inputAliasMap.get(dtsId);
561
+ const isEntry = mod?.isEntry;
562
+ if (isolatedDeclaration$1) {
563
+ const result = isolatedDeclaration(id, code, isolatedDeclaration$1 === true ? {} : isolatedDeclaration$1);
564
+ if (result.errors.length) return this.error(result.errors[0]);
565
+ dtsCode = result.code;
566
+ } else {
567
+ const { program: { program }, file } = createOrGetTsModule(programs, compilerOptions, id, code, isEntry);
568
+ const { emitSkipped, diagnostics } = program.emit(
569
+ file,
570
+ (_, code$1) => {
571
+ dtsCode = code$1;
572
+ },
573
+ void 0,
574
+ true,
575
+ void 0,
576
+ // @ts-expect-error private API: forceDtsEmit
577
+ true
578
+ );
579
+ if (emitSkipped && diagnostics.length) return this.error(ts.formatDiagnostics(diagnostics, formatHost));
580
+ }
581
+ if (!dtsCode) return this.error(new Error(`Failed to generate dts for ${id}`));
582
+ const dtsId = filename_ts_to_dts(id);
583
+ dtsMap.set(dtsId, {
584
+ code: dtsCode,
585
+ src: id
586
+ });
587
+ if (isEntry) {
588
+ let name = basename(dtsId, extname(dtsId));
589
+ if (inputAliasMap.has(name)) name = inputAliasMap.get(name);
590
+ else if (inputAliasMap.has(dtsId)) name = inputAliasMap.get(dtsId);
465
591
  this.emitFile({
466
592
  type: "chunk",
467
593
  id: dtsId,
468
- fileName
594
+ name
469
595
  });
596
+ if (emitDtsOnly) return "//";
470
597
  }
471
598
  }
472
599
  },
@@ -523,10 +650,16 @@ function createGeneratePlugin({ isolatedDeclaration: isolatedDeclaration$1, inpu
523
650
  } },
524
651
  handler(id) {
525
652
  if (dtsMap.has(id)) return {
526
- code: dtsMap.get(id),
653
+ code: dtsMap.get(id).code,
527
654
  moduleSideEffects: false
528
655
  };
529
656
  }
657
+ },
658
+ generateBundle: emitDtsOnly ? (options, bundle) => {
659
+ for (const fileName of Object.keys(bundle)) if (!RE_DTS.test(fileName)) delete bundle[fileName];
660
+ } : void 0,
661
+ buildEnd() {
662
+ programs = [];
530
663
  }
531
664
  };
532
665
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rolldown-plugin-dts",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "A Rolldown plugin to bundle dts files",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -28,10 +28,17 @@
28
28
  "access": "public"
29
29
  },
30
30
  "peerDependencies": {
31
- "rolldown": "^1.0.0-beta.7"
31
+ "rolldown": "^1.0.0-beta.7",
32
+ "typescript": "^5.0.0"
33
+ },
34
+ "peerDependenciesMeta": {
35
+ "typescript": {
36
+ "optional": true
37
+ }
32
38
  },
33
39
  "dependencies": {
34
40
  "dts-resolver": "^0.1.0",
41
+ "get-tsconfig": "^4.10.0",
35
42
  "magic-string-ast": "^0.9.1",
36
43
  "oxc-parser": "^0.62.0",
37
44
  "oxc-transform": "^0.62.0"