rolldown-plugin-dts 0.4.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
@@ -45,8 +45,19 @@ interface Options {
45
45
  */
46
46
  emitDtsOnly?: boolean
47
47
 
48
- isolatedDeclaration?: Omit<IsolatedDeclarationsOptions, 'sourcemap'>
49
-
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'>
50
61
  /**
51
62
  * dts file name alias `{ [filename]: path }`
52
63
  *
@@ -65,14 +76,24 @@ interface Options {
65
76
 
66
77
  ## ⚠️ Caveats
67
78
 
68
- - The plugin uses Oxc's `isolatedDeclarations` to generate `.d.ts` files,
69
- 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.
70
81
 
71
82
  - Namespaces are not supported yet.
72
83
  - `export * as ns from './ns'`
73
84
  - `import * as ns from './ns'` and then `export { ns }`
74
85
  - `type ns = import('./ns')`
75
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
+
76
97
  ## Credits
77
98
 
78
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, emitDtsOnly }: Pick<Options, "isolatedDeclaration" | "inputAlias" | "resolve" | "emitDtsOnly">): 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
@@ -23,7 +24,19 @@ interface Options {
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.
24
25
  */
25
26
  emitDtsOnly?: boolean;
26
- isolatedDeclaration?: Omit<IsolatedDeclarationsOptions, "sourcemap">;
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">;
27
40
  /**
28
41
  * dts file name alias `{ [filename]: path }`
29
42
  *
package/dist/index.js CHANGED
@@ -2,7 +2,10 @@ import { MagicStringAST } from "magic-string-ast";
2
2
  import { parseAsync } from "oxc-parser";
3
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,16 +436,106 @@ 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, emitDtsOnly = false }) {
525
+ function createGeneratePlugin({ compilerOptions, isolatedDeclaration: isolatedDeclaration$1, inputAlias, resolve = false, emitDtsOnly = false }) {
440
526
  const dtsMap = new Map();
441
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
  },
@@ -463,15 +556,35 @@ function createGeneratePlugin({ isolatedDeclaration: isolatedDeclaration$1, inpu
463
556
  exclude: [RE_DTS, RE_NODE_MODULES]
464
557
  } },
465
558
  handler(code, id) {
466
- const { code: dtsCode, errors } = isolatedDeclaration(id, code, isolatedDeclaration$1);
467
- if (errors.length) return this.error(errors[0]);
559
+ let dtsCode;
560
+ const mod = this.getModuleInfo(id);
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}`));
468
582
  const dtsId = filename_ts_to_dts(id);
469
583
  dtsMap.set(dtsId, {
470
584
  code: dtsCode,
471
585
  src: id
472
586
  });
473
- const mod = this.getModuleInfo(id);
474
- if (mod?.isEntry) {
587
+ if (isEntry) {
475
588
  let name = basename(dtsId, extname(dtsId));
476
589
  if (inputAliasMap.has(name)) name = inputAliasMap.get(name);
477
590
  else if (inputAliasMap.has(dtsId)) name = inputAliasMap.get(dtsId);
@@ -544,7 +657,10 @@ function createGeneratePlugin({ isolatedDeclaration: isolatedDeclaration$1, inpu
544
657
  },
545
658
  generateBundle: emitDtsOnly ? (options, bundle) => {
546
659
  for (const fileName of Object.keys(bundle)) if (!RE_DTS.test(fileName)) delete bundle[fileName];
547
- } : void 0
660
+ } : void 0,
661
+ buildEnd() {
662
+ programs = [];
663
+ }
548
664
  };
549
665
  }
550
666
  function isPlainObject(data) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rolldown-plugin-dts",
3
- "version": "0.4.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"