rolldown-plugin-dts 0.5.2 → 0.7.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
@@ -29,7 +29,7 @@ You can find a real demo in [here](./rolldown.config.ts).
29
29
 
30
30
  ## Options
31
31
 
32
- ````ts
32
+ ```ts
33
33
  interface Options {
34
34
  /**
35
35
  * When entries are `.d.ts` files (instead of `.ts` files), this option should be set to `true`.
@@ -47,44 +47,32 @@ interface Options {
47
47
 
48
48
  /**
49
49
  * The `compilerOptions` for the TypeScript compiler.
50
+ * The default value will be inferred from the `tsconfig.json` file.
50
51
  *
51
52
  * @see https://www.typescriptlang.org/docs/handbook/compiler-options.html
52
53
  */
53
- compilerOptions?: CompilerOptions
54
+ compilerOptions?: TsConfigJson.CompilerOptions
54
55
  /**
55
56
  * When `true`, the plugin will generate `.d.ts` files using `oxc-transform`,
56
57
  * which is blazingly faster than `typescript` compiler.
57
58
  *
58
- * This option is enabled when `isolatedDeclaration` in `tsconfig.json` is set to `true`.
59
+ * This option is enabled when `isolatedDeclaration` in `compilerOptions` is set to `true`.
59
60
  */
60
61
  isolatedDeclaration?: boolean | Omit<IsolatedDeclarationsOptions, 'sourcemap'>
61
- /**
62
- * dts file name alias `{ [filename]: path }`
63
- *
64
- * @example
65
- * ```ts
66
- * inputAlias: {
67
- * 'foo.d.ts': 'foo/index.d.ts',
68
- * }
69
- */
70
- inputAlias?: Record<string, string>
71
62
 
72
63
  /** Resolve external types used in dts files from `node_modules` */
73
64
  resolve?: boolean | (string | RegExp)[]
74
65
  }
75
- ````
66
+ ```
76
67
 
77
- ## ⚠️ Caveats
68
+ ## Differences from `rollup-plugin-dts`
78
69
 
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
+ ### Isolated Declarations
81
71
 
82
- - Namespaces are not supported yet.
83
- - `export * as ns from './ns'`
84
- - `import * as ns from './ns'` and then `export { ns }`
85
- - `type ns = import('./ns')`
72
+ The plugin leverages Oxc's `isolatedDeclarations` to generate `.d.ts` files when `isolatedDeclaration` is enabled,
73
+ offering significantly faster performance compared to the `typescript` compiler.
86
74
 
87
- ## Differences from `rollup-plugin-dts`
75
+ ### Single Build for ESM
88
76
 
89
77
  `rolldown-plugin-dts` generates separate chunks for `.d.ts` files, enabling both source code (`.js`)
90
78
  and type definition files (`.d.ts`) to be produced in a single build process.
package/dist/index.d.ts CHANGED
@@ -1,13 +1,13 @@
1
+ import { TsConfigJson } from "get-tsconfig";
1
2
  import { IsolatedDeclarationsOptions } from "oxc-transform";
2
3
  import { Plugin } from "rolldown";
3
- import { CompilerOptions } from "typescript";
4
4
 
5
5
  //#region src/fake-js.d.ts
6
6
  declare function createFakeJsPlugin({ dtsInput }: Pick<Options, "dtsInput">): Plugin;
7
7
 
8
8
  //#endregion
9
9
  //#region src/generate.d.ts
10
- declare function createGeneratePlugin({ compilerOptions, isolatedDeclaration, inputAlias, resolve, emitDtsOnly }: Pick<Options, "isolatedDeclaration" | "inputAlias" | "resolve" | "emitDtsOnly" | "compilerOptions">): Plugin;
10
+ declare function createGeneratePlugin({ compilerOptions, isolatedDeclaration, resolve, emitDtsOnly }: Pick<Options, "isolatedDeclaration" | "resolve" | "emitDtsOnly" | "compilerOptions">): Plugin;
11
11
 
12
12
  //#endregion
13
13
  //#region src/index.d.ts
@@ -26,27 +26,18 @@ interface Options {
26
26
  emitDtsOnly?: boolean;
27
27
  /**
28
28
  * The `compilerOptions` for the TypeScript compiler.
29
+ * The default value will be inferred from the `tsconfig.json` file.
29
30
  *
30
31
  * @see https://www.typescriptlang.org/docs/handbook/compiler-options.html
31
32
  */
32
- compilerOptions?: CompilerOptions;
33
+ compilerOptions?: TsConfigJson.CompilerOptions;
33
34
  /**
34
35
  * When `true`, the plugin will generate `.d.ts` files using `oxc-transform`,
35
36
  * which is blazingly faster than `typescript` compiler.
36
37
  *
37
- * This option is enabled when `isolatedDeclaration` in `tsconfig.json` is set to `true`.
38
+ * This option is enabled when `isolatedDeclaration` in `compilerOptions` is set to `true`.
38
39
  */
39
40
  isolatedDeclaration?: boolean | Omit<IsolatedDeclarationsOptions, "sourcemap">;
40
- /**
41
- * dts file name alias `{ [filename]: path }`
42
- *
43
- * @example
44
- * ```ts
45
- * inputAlias: {
46
- * 'foo.d.ts': 'foo/index.d.ts',
47
- * }
48
- */
49
- inputAlias?: Record<string, string>;
50
41
  /** Resolve external types used in dts files from `node_modules` */
51
42
  resolve?: boolean | (string | RegExp)[];
52
43
  }
package/dist/index.js CHANGED
@@ -1,10 +1,12 @@
1
1
  import { MagicStringAST } from "magic-string-ast";
2
2
  import { parseSync } from "oxc-parser";
3
- import path, { basename, extname } from "node:path";
3
+ import path from "node:path";
4
+ import process from "node:process";
4
5
  import { createResolver } from "dts-resolver";
5
6
  import { getTsconfig } from "get-tsconfig";
6
7
  import { isolatedDeclaration } from "oxc-transform";
7
8
  import { createRequire } from "node:module";
9
+ import Debug from "debug";
8
10
 
9
11
  //#region node_modules/.pnpm/estree-walker@3.0.3/node_modules/estree-walker/src/walker.js
10
12
  var WalkerBase = class {
@@ -256,7 +258,6 @@ function createFakeJsPlugin({ dtsInput }) {
256
258
  preserveMap.set(id, preserved);
257
259
  const s = new MagicStringAST(code);
258
260
  for (let node of program.body) {
259
- if (node.type === "ExportAllDeclaration" && node.exported && isRelative(node.source.value)) throw new Error("`export * as foo from './...'` is not supported");
260
261
  if (rewriteImportExport(s, node)) continue;
261
262
  const sideEffect = node.type === "TSModuleDeclaration" && node.kind !== "namespace";
262
263
  const stmt = node;
@@ -315,17 +316,19 @@ function createFakeJsPlugin({ dtsInput }) {
315
316
  }
316
317
  }
317
318
  if (comments.size) s.prepend(`${[...comments].join("\n")}\n`);
319
+ const removedNodes = patchTsNamespace(s, program.body);
318
320
  for (const node of program.body) {
321
+ if (removedNodes.has(node)) continue;
319
322
  if (patchImportSource(s, node)) continue;
320
323
  if (node.type !== "VariableDeclaration" || node.declarations.length !== 1) continue;
321
324
  const [decl] = node.declarations;
322
325
  if (decl.init?.type !== "ArrayExpression" || !decl.init.elements[0]) {
323
- patchVariableDeclarator(s, node, decl);
326
+ s.removeNode(node);
324
327
  continue;
325
328
  }
326
329
  const [symbolIdNode, ...depsNodes] = decl.init.elements;
327
330
  if (symbolIdNode?.type !== "Literal" || typeof symbolIdNode.value !== "number") {
328
- patchVariableDeclarator(s, node, decl);
331
+ s.removeNode(node);
329
332
  continue;
330
333
  }
331
334
  const symbolId = symbolIdNode.value;
@@ -342,7 +345,7 @@ function createFakeJsPlugin({ dtsInput }) {
342
345
  s.overwriteNode(node, ss.toString());
343
346
  }
344
347
  const str = s.toString();
345
- if (str.trim().length === 0) return "export {}";
348
+ if (str.trim().length === 0) return "export { };";
346
349
  return str;
347
350
  }
348
351
  };
@@ -374,15 +377,14 @@ function collectDependencies(s, node, getIdentifierIndex) {
374
377
  else if (node$1.type === "TSTypeQuery") addDependency(node$1.exprName);
375
378
  else if (node$1.type === "TSImportType") {
376
379
  if (node$1.argument.type !== "TSLiteralType" || node$1.argument.literal.type !== "Literal" || typeof node$1.argument.literal.value !== "string") return;
377
- if (!node$1.qualifier) throw new Error("Import namespace is not supported");
378
380
  const source = node$1.argument.literal.value;
379
- const imported = s.sliceNode(node$1.qualifier);
381
+ const imported = node$1.qualifier && s.sliceNode(node$1.qualifier);
380
382
  const local = importNamespace(s, source, imported, getIdentifierIndex);
381
383
  addDependency({
382
384
  type: "Identifier",
383
385
  name: local,
384
386
  start: node$1.start + (node$1.isTypeOf ? 7 : 0),
385
- end: node$1.qualifier.end
387
+ end: node$1.qualifier ? node$1.qualifier.end : node$1.end
386
388
  });
387
389
  }
388
390
  } });
@@ -398,16 +400,40 @@ function isReferenceId(node) {
398
400
  function stringifyDependencies(s, deps) {
399
401
  return deps.map((node) => `() => ${node.type === "Identifier" ? node.name : s.sliceNode(node)}`).join(", ");
400
402
  }
401
- function patchVariableDeclarator(s, node, decl) {
402
- if (decl.init && !decl.id.typeAnnotation) s.overwriteNode(node, `type ${s.sliceNode(decl.id)} = ${s.sliceNode(decl.init)}`);
403
- else if (!node.declare) s.prependLeft(node.start, "declare ");
404
- }
405
403
  function patchImportSource(s, node) {
406
404
  if ((node.type === "ImportDeclaration" || node.type === "ExportAllDeclaration" || node.type === "ExportNamedDeclaration") && node.source?.value && RE_DTS.test(node.source.value)) {
407
405
  s.overwriteNode(node.source, JSON.stringify(filename_dts_to(node.source.value, "js")));
408
406
  return true;
409
407
  }
410
408
  }
409
+ function patchTsNamespace(s, nodes) {
410
+ const emptyObjectAssignments = new Map();
411
+ const removed = new Set();
412
+ for (const node of nodes) {
413
+ 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);
414
+ if (node.type !== "ExpressionStatement" || node.expression.type !== "CallExpression" || node.expression.callee.type !== "Identifier" || !node.expression.callee.name.startsWith("__export")) continue;
415
+ const [binding, exports] = node.expression.arguments;
416
+ const bindingText = s.sliceNode(binding);
417
+ if (emptyObjectAssignments.has(bindingText)) {
418
+ const emptyNode = emptyObjectAssignments.get(bindingText);
419
+ s.removeNode(emptyNode);
420
+ emptyObjectAssignments.delete(bindingText);
421
+ removed.add(emptyNode);
422
+ }
423
+ let code = `declare namespace ${bindingText} {
424
+ export { `;
425
+ for (const properties of exports.properties) {
426
+ if (properties.type !== "Property") continue;
427
+ const exported = s.sliceNode(properties.key);
428
+ const local = s.sliceNode(properties.value.body);
429
+ const suffix = exported !== local ? ` as ${exported}` : "";
430
+ code += `${local}${suffix}, `;
431
+ }
432
+ code += `}\n}`;
433
+ s.overwriteNode(node, code);
434
+ }
435
+ return removed;
436
+ }
411
437
  function rewriteImportExport(s, node) {
412
438
  if (node.type === "ImportDeclaration" || node.type === "ExportNamedDeclaration" && !node.declaration) {
413
439
  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, ""));
@@ -422,7 +448,7 @@ function rewriteImportExport(s, node) {
422
448
  if (node.moduleReference.type === "TSExternalModuleReference") s.overwriteNode(node, `import ${s.sliceNode(node.id)} from ${s.sliceNode(node.moduleReference.expression)}`);
423
449
  return true;
424
450
  } else if (node.type === "TSExportAssignment") {
425
- s.overwriteNode(node, `export default ${s.sliceNode(node.expression)}`);
451
+ s.overwriteNode(node, `export { ${s.sliceNode(node.expression)} as default }`);
426
452
  return true;
427
453
  } else if (node.type === "ExportDefaultDeclaration" && node.declaration.type === "Identifier") {
428
454
  s.overwriteNode(node, `export { ${s.sliceNode(node.declaration)} as default }`);
@@ -431,15 +457,18 @@ function rewriteImportExport(s, node) {
431
457
  }
432
458
  function importNamespace(s, source, imported, getIdentifierIndex) {
433
459
  const local = `_${getIdentifierIndex()}`;
434
- s.prepend(`import { ${imported} as ${local} } from ${JSON.stringify(source)};\n`);
460
+ const specifiers = imported ? `{ ${imported} as ${local} }` : `* as ${local}`;
461
+ s.prepend(`import ${specifiers} from ${JSON.stringify(source)};\n`);
435
462
  return local;
436
463
  }
437
464
 
438
465
  //#endregion
439
466
  //#region src/utils/tsc.ts
467
+ const debug = Debug("rolldown-plugin-dts:tsc");
440
468
  let ts;
441
469
  let formatHost;
442
470
  function initTs() {
471
+ debug("loading typescript");
443
472
  const require = createRequire(import.meta.url);
444
473
  ts = require("typescript");
445
474
  formatHost = {
@@ -447,6 +476,7 @@ function initTs() {
447
476
  getNewLine: () => ts.sys.newLine,
448
477
  getCanonicalFileName: ts.sys.useCaseSensitiveFileNames ? (f) => f : (f) => f.toLowerCase()
449
478
  };
479
+ debug(`loaded typescript: ${ts.version}`);
450
480
  }
451
481
  const defaultCompilerOptions = {
452
482
  declaration: true,
@@ -472,16 +502,18 @@ function createOrGetTsModule(programs, compilerOptions, id, code, isEntry) {
472
502
  file: sourceFile
473
503
  };
474
504
  }
505
+ debug(`create program for module: ${id}`);
475
506
  const module = createTsProgram(compilerOptions, id, code);
507
+ debug(`created program for module: ${id}`);
476
508
  programs.push(module.program);
477
509
  return module;
478
510
  }
479
511
  function createTsProgram(compilerOptions, id, code) {
480
512
  const files = new Map([[id, code]]);
513
+ const overrideCompilerOptions = ts.convertCompilerOptionsFromJson(compilerOptions, ".").options;
481
514
  const options = {
482
515
  ...defaultCompilerOptions,
483
- ...loadTsconfig(id),
484
- ...compilerOptions
516
+ ...overrideCompilerOptions
485
517
  };
486
518
  const host = ts.createCompilerHost(options, true);
487
519
  const { readFile: _readFile, fileExists: _fileExists } = host;
@@ -493,14 +525,7 @@ function createTsProgram(compilerOptions, id, code) {
493
525
  if (files.has(fileName)) return files.get(fileName);
494
526
  return _readFile(fileName);
495
527
  };
496
- const program = ts.createProgram([id], {
497
- ...compilerOptions,
498
- moduleResolution: ts.ModuleResolutionKind.Node10,
499
- declaration: true,
500
- emitDeclarationOnly: true,
501
- outDir: void 0,
502
- declarationDir: void 0
503
- }, host);
528
+ const program = ts.createProgram([id], options, host);
504
529
  const sourceFile = program.getSourceFile(id);
505
530
  if (!sourceFile) throw new Error(`Source file not found: ${id}`);
506
531
  return {
@@ -511,39 +536,60 @@ function createTsProgram(compilerOptions, id, code) {
511
536
  file: sourceFile
512
537
  };
513
538
  }
514
- const tsconfigCache = new Map();
515
- function loadTsconfig(id) {
516
- const configPath = ts.findConfigFile(path.dirname(id), ts.sys.fileExists);
517
- if (!configPath) return {};
518
- if (tsconfigCache.has(configPath)) return tsconfigCache.get(configPath);
519
- const { config, error } = ts.readConfigFile(configPath, ts.sys.readFile);
520
- if (error) throw ts.formatDiagnostic(error, formatHost);
521
- const configContents = ts.parseJsonConfigFileContent(config, ts.sys, path.dirname(configPath));
522
- if (configContents.errors.length) throw ts.formatDiagnostics(configContents.errors, formatHost);
523
- tsconfigCache.set(configPath, configContents.options);
524
- return configContents.options;
539
+ function tscEmit(module) {
540
+ const { program: { program }, file } = module;
541
+ let dtsCode;
542
+ const { emitSkipped, diagnostics } = program.emit(
543
+ file,
544
+ (_, code) => {
545
+ debug(`emit dts: ${file.fileName}`);
546
+ dtsCode = code;
547
+ },
548
+ void 0,
549
+ true,
550
+ void 0,
551
+ // @ts-expect-error private API: forceDtsEmit
552
+ true
553
+ );
554
+ if (emitSkipped && diagnostics.length) return { error: ts.formatDiagnostics(diagnostics, formatHost) };
555
+ return { code: dtsCode };
525
556
  }
526
557
 
527
558
  //#endregion
528
559
  //#region src/generate.ts
529
560
  const meta = { dtsFile: true };
530
- function createGeneratePlugin({ compilerOptions, isolatedDeclaration: isolatedDeclaration$1, inputAlias, resolve = false, emitDtsOnly = false }) {
561
+ function createGeneratePlugin({ compilerOptions, isolatedDeclaration: isolatedDeclaration$1, resolve = false, emitDtsOnly = false }) {
531
562
  const dtsMap = new Map();
532
- const inputAliasMap = new Map(inputAlias && Object.entries(inputAlias));
563
+ /**
564
+ * A map of input id to output file name
565
+ *
566
+ * @example
567
+ *
568
+ * inputAlias = new Map([
569
+ * ['/absolute/path/to/src/source_file.ts', 'dist/foo/index'],
570
+ * ])
571
+ */
572
+ const inputAliasMap = new Map();
533
573
  const resolver = createResolver();
534
574
  let programs = [];
535
- let inputOption;
536
575
  return {
537
576
  name: "rolldown-plugin-dts:generate",
538
577
  buildStart(options) {
539
- if (isolatedDeclaration$1 == null) {
578
+ if (!compilerOptions) {
540
579
  const { config } = getTsconfig(options.cwd) || {};
541
- if (config?.compilerOptions?.isolatedDeclarations) isolatedDeclaration$1 = { stripInternal: !!config?.compilerOptions.stripInternal };
580
+ compilerOptions = config?.compilerOptions;
542
581
  }
582
+ if (isolatedDeclaration$1 == null) isolatedDeclaration$1 = !!compilerOptions?.isolatedDeclarations;
583
+ if (isolatedDeclaration$1 === true) isolatedDeclaration$1 = {};
584
+ if (isolatedDeclaration$1 && isolatedDeclaration$1.stripInternal == null) isolatedDeclaration$1.stripInternal = !!compilerOptions?.stripInternal;
543
585
  if (!isolatedDeclaration$1) initTs();
544
- },
545
- options({ input }) {
546
- if (isPlainObject(input)) inputOption = { ...input };
586
+ if (!Array.isArray(options.input)) {
587
+ const cwd = options.cwd || process.cwd();
588
+ for (const [fileName, inputFilePath] of Object.entries(options.input)) {
589
+ const id = path.resolve(cwd, inputFilePath);
590
+ inputAliasMap.set(id, fileName);
591
+ }
592
+ }
547
593
  },
548
594
  outputOptions(options) {
549
595
  return {
@@ -567,22 +613,19 @@ function createGeneratePlugin({ compilerOptions, isolatedDeclaration: isolatedDe
567
613
  const isEntry = mod?.isEntry;
568
614
  if (isolatedDeclaration$1) {
569
615
  const result = isolatedDeclaration(id, code, isolatedDeclaration$1 === true ? {} : isolatedDeclaration$1);
570
- if (result.errors.length) return this.error(result.errors[0]);
616
+ if (result.errors.length) {
617
+ const [error] = result.errors;
618
+ return this.error({
619
+ message: error.message,
620
+ frame: error.codeframe
621
+ });
622
+ }
571
623
  dtsCode = result.code;
572
624
  } else {
573
- const { program: { program }, file } = createOrGetTsModule(programs, compilerOptions, id, code, isEntry);
574
- const { emitSkipped, diagnostics } = program.emit(
575
- file,
576
- (_, code$1) => {
577
- dtsCode = code$1;
578
- },
579
- void 0,
580
- true,
581
- void 0,
582
- // @ts-expect-error private API: forceDtsEmit
583
- true
584
- );
585
- if (emitSkipped && diagnostics.length) return this.error(ts.formatDiagnostics(diagnostics, formatHost));
625
+ const module = createOrGetTsModule(programs, compilerOptions, id, code, isEntry);
626
+ const result = tscEmit(module);
627
+ if (result.error) return this.error(result.error);
628
+ dtsCode = result.code;
586
629
  }
587
630
  if (!dtsCode) return this.error(new Error(`Failed to generate dts for ${id}`));
588
631
  const dtsId = filename_ts_to_dts(id);
@@ -591,19 +634,17 @@ function createGeneratePlugin({ compilerOptions, isolatedDeclaration: isolatedDe
591
634
  src: id
592
635
  });
593
636
  if (isEntry) {
594
- let name = basename(dtsId, extname(dtsId));
595
- if (inputAliasMap.has(name)) name = inputAliasMap.get(name);
596
- else if (inputAliasMap.has(dtsId)) name = inputAliasMap.get(dtsId);
637
+ const name = inputAliasMap.get(id);
597
638
  this.emitFile({
598
639
  type: "chunk",
599
640
  id: dtsId,
600
- name
641
+ name: name ? `${name}.d` : void 0
601
642
  });
602
643
  if (emitDtsOnly) return "//";
603
644
  }
604
645
  }
605
646
  },
606
- async resolveId(id, importer, extraOptions) {
647
+ async resolveId(id, importer) {
607
648
  if (dtsMap.has(id)) return {
608
649
  id,
609
650
  meta
@@ -637,16 +678,6 @@ function createGeneratePlugin({ compilerOptions, isolatedDeclaration: isolatedDe
637
678
  id: dtsId,
638
679
  meta
639
680
  };
640
- } else if (extraOptions.isEntry && inputOption) {
641
- const resolution = await this.resolve(id, importer, extraOptions);
642
- if (!resolution) return;
643
- const dtsId = filename_ts_to_dts(resolution.id);
644
- if (inputAliasMap.has(dtsId)) return resolution;
645
- for (const [name, entry] of Object.entries(inputOption)) if (entry === id) {
646
- inputAliasMap.set(dtsId, `${name}.d.ts`);
647
- break;
648
- }
649
- return resolution;
650
681
  }
651
682
  },
652
683
  load: {
@@ -669,11 +700,6 @@ function createGeneratePlugin({ compilerOptions, isolatedDeclaration: isolatedDe
669
700
  }
670
701
  };
671
702
  }
672
- function isPlainObject(data) {
673
- if (typeof data !== "object" || data === null) return false;
674
- const proto = Object.getPrototypeOf(data);
675
- return proto === null || proto === Object.prototype;
676
- }
677
703
 
678
704
  //#endregion
679
705
  //#region src/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rolldown-plugin-dts",
3
- "version": "0.5.2",
3
+ "version": "0.7.0",
4
4
  "description": "A Rolldown plugin to bundle dts files",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -37,6 +37,7 @@
37
37
  }
38
38
  },
39
39
  "dependencies": {
40
+ "debug": "^4.4.0",
40
41
  "dts-resolver": "^0.1.0",
41
42
  "get-tsconfig": "^4.10.0",
42
43
  "magic-string-ast": "^0.9.1",
@@ -47,6 +48,7 @@
47
48
  "@sxzz/eslint-config": "^6.1.1",
48
49
  "@sxzz/prettier-config": "^2.2.1",
49
50
  "@sxzz/test-utils": "^0.5.4",
51
+ "@types/debug": "^4.1.12",
50
52
  "@types/diff": "^7.0.2",
51
53
  "@types/node": "^22.14.0",
52
54
  "bumpp": "^10.1.0",