dtsroll 1.5.0 → 1.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 +120 -103
- package/dist/cli.mjs +27 -11
- package/dist/{index-DfxmCmBK.mjs → index-r9RZgCg7.mjs} +193 -39
- package/dist/index.d.ts +34 -1
- package/dist/index.mjs +2 -1
- package/dist/vite.d.ts +7 -0
- package/dist/vite.mjs +18 -9
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,152 +1,160 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
|
|
2
|
+
<img width="200" src="./.github/logo.webp">
|
|
3
3
|
</p>
|
|
4
|
+
<h2 align="center">dtsroll</h2>
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
dtsroll
|
|
7
|
-
</h2>
|
|
6
|
+
Are you publishing a TypeScript project where consumers encounter type-checking errors like:
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
```
|
|
9
|
+
Cannot find module 'some-package' or its corresponding type declarations.
|
|
10
|
+
```
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
When you compile with `tsc`, the emitted declaration files (`.d.ts` files) preserve imports exactly as written. So if your published types import from a `devDependency` or a private package (e.g. an internal monorepo package), those imports cannot be resolved by the consumer.
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
```ts
|
|
15
|
+
// dist/index.d.ts (generated by tsc)
|
|
16
|
+
import type { SomeType } from 'my-private-dependency' // ❌ consumers can't resolve this
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
export declare function myUtility(): SomeType
|
|
19
|
+
```
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
If you can't move the dependency to `dependencies`, or you just want its types pulled directly into your published declarations, _dtsroll_ is for you.
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
## What is dtsroll?
|
|
20
24
|
|
|
21
|
-
-
|
|
25
|
+
_dtsroll_ is a TypeScript declaration (`.d.ts`) file bundler. It's zero-config and reads your `package.json` to determine how your types should be bundled.
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
### What dtsroll does
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
<img width="600" src="./.github/screenshot.webp">
|
|
27
|
-
</p>
|
|
29
|
+
_dtsroll_ runs *after your build when `.d.ts` files have been emitted*, and works in-place to bundle them to their entry points.
|
|
28
30
|
|
|
31
|
+
Since packages declared in `devDependencies` are not installed for the consumer, _dtsroll_ assumes any imports referencing them should be bundled, as they would otherwise be unresolvable.
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
```
|
|
32
|
-
npm install --save-dev dtsroll
|
|
33
|
-
```
|
|
33
|
+
The result is a single, clean `.d.ts` output that works for consumers without extra installs.
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
```ts
|
|
36
|
+
// dist/index.d.ts (after dtsroll)
|
|
37
|
+
type SomeType = {
|
|
38
|
+
value: string
|
|
39
|
+
}
|
|
36
40
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
- If using Vite, use a plugin like [vite-plugin-dts](https://www.npmjs.com/package/vite-plugin-dts)
|
|
41
|
+
export declare function myUtility(): SomeType
|
|
42
|
+
```
|
|
40
43
|
|
|
41
|
-
|
|
44
|
+
### Features
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
- **Zero config** — Automatically finds entry points from `package.json`.
|
|
47
|
+
- **Fixes missing-type errors** — Inlines types from `devDependencies` so consumers don't need them installed.
|
|
48
|
+
- **Tree-shaken output** — Unused types are removed to keep files small.
|
|
49
|
+
- **In-place** — Designed to run directly on your `dist` folder after compilation.
|
|
46
50
|
|
|
47
|
-
>
|
|
48
|
-
|
|
49
|
-
>
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
<p align="center">
|
|
52
|
+
<img width="600" src="./.github/screenshot.webp">
|
|
53
|
+
</p>
|
|
54
|
+
|
|
55
|
+
## Install
|
|
52
56
|
|
|
53
|
-
|
|
57
|
+
```bash
|
|
58
|
+
npm install --save-dev dtsroll
|
|
59
|
+
```
|
|
54
60
|
|
|
55
|
-
|
|
56
|
-
dtsroll dist/index.d.ts
|
|
57
|
-
```
|
|
61
|
+
## Quick start
|
|
58
62
|
|
|
59
|
-
###
|
|
63
|
+
### 1. Configure `package.json`
|
|
64
|
+
|
|
65
|
+
Point your `types` or `exports` to the final `.d.ts` file you want to publish.
|
|
66
|
+
|
|
67
|
+
```jsonc
|
|
68
|
+
{
|
|
69
|
+
"name": "my-package",
|
|
70
|
+
"exports": {
|
|
71
|
+
"types": "./dist/index.d.ts", // dtsroll targets this
|
|
72
|
+
"default": "./dist/index.js",
|
|
73
|
+
},
|
|
74
|
+
"scripts": {
|
|
75
|
+
"build": "tsc && dtsroll",
|
|
76
|
+
},
|
|
77
|
+
}
|
|
78
|
+
```
|
|
60
79
|
|
|
61
|
-
|
|
80
|
+
### 2. Build
|
|
62
81
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
{
|
|
66
|
-
"name": "my-package",
|
|
67
|
-
"exports": {
|
|
68
|
-
+ "types": "./dist/index.d.ts",
|
|
69
|
-
"default": "./dist/index.js"
|
|
70
|
-
},
|
|
71
|
-
"scripts": {
|
|
72
|
-
+ "build": "tsc && dtsroll"
|
|
73
|
-
}
|
|
74
|
-
}
|
|
82
|
+
```bash
|
|
83
|
+
npm run build
|
|
75
84
|
```
|
|
76
85
|
|
|
77
|
-
|
|
86
|
+
That's it.
|
|
78
87
|
|
|
79
|
-
|
|
88
|
+
> [!WARNING]
|
|
89
|
+
> _dtsroll_ modifies files in-place—bundled source files are removed and entry files are overwritten with bundled output.
|
|
90
|
+
> Use `--dry-run` first to see what it would change:
|
|
91
|
+
>
|
|
92
|
+
> ```bash
|
|
93
|
+
> dtsroll --dry-run
|
|
94
|
+
> ```
|
|
80
95
|
|
|
81
|
-
|
|
96
|
+
## Behavior
|
|
82
97
|
|
|
83
|
-
|
|
98
|
+
### Automatic configuration
|
|
84
99
|
|
|
85
|
-
|
|
100
|
+
By default, _dtsroll_ reads your `package.json` to determine which imports should be bundled and which should remain external. The recommended setup is to run _dtsroll_ without any configuration and let it infer the correct behavior based on your dependency declarations.
|
|
86
101
|
|
|
87
|
-
|
|
88
|
-
|
|
102
|
+
| Dependency type | Action | Reason |
|
|
103
|
+
| ---------------------- | ----------- | ----------------------------- |
|
|
104
|
+
| `devDependencies` | Bundle | Consumers don't install these |
|
|
105
|
+
| `dependencies` | Externalize | Consumers already have them |
|
|
106
|
+
| `optionalDependencies` | Externalize | Consumers already have them |
|
|
107
|
+
| `peerDependencies` | Externalize | Provided by the consumer |
|
|
89
108
|
|
|
90
|
-
|
|
109
|
+
If you have a `@types/*` package in `devDependencies` but the corresponding runtime package in `dependencies`, _dtsroll_ will recommend moving the types package to `dependencies`, as this can otherwise result in missing types for consumers.
|
|
91
110
|
|
|
92
|
-
|
|
111
|
+
### Manual configuration
|
|
93
112
|
|
|
94
|
-
|
|
113
|
+
If your project doesn't have a `package.json` file, you can still manually specify the input files (which entry files to collapse the `imports` into), and which packages to externalize.
|
|
95
114
|
|
|
96
|
-
###
|
|
97
|
-
```sh
|
|
98
|
-
dtsroll [-flags] [...entry dts files]
|
|
99
|
-
```
|
|
115
|
+
### Subpath imports
|
|
100
116
|
|
|
101
|
-
|
|
117
|
+
> [!WARNING]
|
|
118
|
+
> Currently, _dtsroll_ mistakenly resolves and bundles [subpath imports](https://nodejs.org/api/packages.html#subpath-imports). Subpath imports are intended to be dynamic aliases controlled by the consumer. In a future breaking release, _dtsroll_ will likely externalize them to preserve this behavior.
|
|
102
119
|
|
|
103
|
-
|
|
104
|
-
Display usage instructions.
|
|
120
|
+
## Usage
|
|
105
121
|
|
|
106
|
-
|
|
107
|
-
Simulate the bundling process without modifying the disk and logs what would happen.
|
|
122
|
+
_dtsroll_ can be used in several ways.
|
|
108
123
|
|
|
109
|
-
###
|
|
110
|
-
If there is no `package.json` file, you can specify package names to exclude from the bundle.
|
|
124
|
+
### CLI usage
|
|
111
125
|
|
|
112
|
-
|
|
113
|
-
|
|
126
|
+
```bash
|
|
127
|
+
dtsroll [flags] [...entry .d.ts files]
|
|
128
|
+
```
|
|
114
129
|
|
|
115
|
-
|
|
116
|
-
Provide resolution conditions to target specific entry points in dependencies, similar to Node’s [`--conditions`](https://nodejs.org/api/cli.html#-c-condition---conditionscondition).
|
|
130
|
+
If no entry files are provided, _dtsroll_ reads `package.json` to determine them.
|
|
117
131
|
|
|
118
|
-
|
|
119
|
-
```ts
|
|
120
|
-
import { dtsroll } from 'dtsroll'
|
|
132
|
+
#### Flags
|
|
121
133
|
|
|
122
|
-
|
|
134
|
+
| Flag | Alias | Description |
|
|
135
|
+
| -------------- | ----- | ------------------------------------------------- |
|
|
136
|
+
| `--dry-run` | `-d` | Show what would be bundled without writing files |
|
|
137
|
+
| `--sourcemap` | `-s` | Generate source maps (`.d.ts.map` files) |
|
|
138
|
+
| `--conditions` | `-C` | Resolution conditions for [subpath exports](https://nodejs.org/api/packages.html#subpath-exports) (e.g. `production`) |
|
|
139
|
+
| `--external` | `-e` | *(Only when no `package.json`)* Packages to externalize |
|
|
123
140
|
|
|
124
|
-
|
|
125
|
-
* CWD to find the package.json in
|
|
126
|
-
* @default process.cwd()
|
|
127
|
-
*/
|
|
128
|
-
cwd?: string
|
|
141
|
+
#### Why use `--sourcemap`?
|
|
129
142
|
|
|
130
|
-
|
|
131
|
-
* Defaults to auto-detecting d.ts files from package.json
|
|
132
|
-
*/
|
|
133
|
-
inputs?: string[]
|
|
143
|
+
Without source maps, "Go to Definition" in VS Code lands you in bundled `.d.ts` files—often a flattened wall of generated types that's hard to navigate.
|
|
134
144
|
|
|
135
|
-
|
|
136
|
-
* Only used if there's no package.json
|
|
137
|
-
* Defaults to auto-detecting dependencies from package.json
|
|
138
|
-
*/
|
|
139
|
-
external?: string[]
|
|
145
|
+
With `--sourcemap`, _dtsroll_ generates `.d.ts.map` files that map positions in the bundled output back to your original source files. This lets VS Code jump directly to the actual TypeScript implementation instead of the generated declarations.
|
|
140
146
|
|
|
141
|
-
|
|
147
|
+
This is especially useful for:
|
|
148
|
+
- **Monorepos** — Navigate seamlessly across packages to real source
|
|
149
|
+
- **Library authors** — Give consumers a better DX when exploring your types
|
|
150
|
+
- **Anyone debugging types** — Understand types at their origin, not the emitted output
|
|
142
151
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
```
|
|
152
|
+
> [!NOTE]
|
|
153
|
+
> For source navigation to work, the original `.ts` source files must be available (either shipped with your package or present locally). If they're not, VS Code falls back to the `.d.ts` file.
|
|
146
154
|
|
|
147
|
-
|
|
155
|
+
### Vite plugin
|
|
148
156
|
|
|
149
|
-
|
|
157
|
+
If you use `vite-plugin-dts`, _dtsroll_ will automatically bundle the emitted types immediately after generation:
|
|
150
158
|
|
|
151
159
|
```ts
|
|
152
160
|
import { defineConfig } from 'vitest/config'
|
|
@@ -154,16 +162,25 @@ import dts from 'vite-plugin-dts'
|
|
|
154
162
|
import { dtsroll } from 'dtsroll/vite'
|
|
155
163
|
|
|
156
164
|
export default defineConfig({
|
|
157
|
-
// ...
|
|
158
165
|
plugins: [
|
|
159
|
-
// ...
|
|
160
166
|
dts(),
|
|
161
167
|
dtsroll()
|
|
162
168
|
]
|
|
163
169
|
})
|
|
164
170
|
```
|
|
165
171
|
|
|
172
|
+
### Node API
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
import { dtsroll } from 'dtsroll'
|
|
176
|
+
|
|
177
|
+
await dtsroll({
|
|
178
|
+
cwd: process.cwd(),
|
|
179
|
+
dryRun: false,
|
|
180
|
+
sourcemap: true // generates .d.ts.map files
|
|
181
|
+
})
|
|
182
|
+
```
|
|
183
|
+
|
|
166
184
|
## Related
|
|
167
185
|
|
|
168
|
-
|
|
169
|
-
For package bundling (along with dts bundling), check out [pkgroll](https://github.com/privatenumber/pkgroll).
|
|
186
|
+
- [pkgroll](https://github.com/privatenumber/pkgroll) — Zero-config JS + DTS bundler
|
package/dist/cli.mjs
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { cli } from 'cleye';
|
|
3
|
-
import { b as bgYellow, a as black, d as dtsroll, l as logOutput } from './index-
|
|
3
|
+
import { b as bgYellow, a as black, d as dtsroll, l as logOutput, D as DtsrollBuildError } from './index-r9RZgCg7.mjs';
|
|
4
4
|
import 'node:path';
|
|
5
5
|
import 'node:fs/promises';
|
|
6
6
|
import 'rollup';
|
|
7
7
|
import 'rollup-plugin-dts';
|
|
8
8
|
import '@rollup/plugin-node-resolve';
|
|
9
9
|
import 'node:fs';
|
|
10
|
+
import 'convert-source-map';
|
|
10
11
|
import 'empathic/find';
|
|
11
12
|
import 'resolve-pkg-maps';
|
|
12
13
|
import 'byte-size';
|
|
13
14
|
|
|
14
15
|
var name = "dtsroll";
|
|
15
|
-
var version = "1.
|
|
16
|
+
var version = "1.7.0";
|
|
16
17
|
var description = "Bundle dts files";
|
|
17
18
|
|
|
18
19
|
const argv = cli({
|
|
@@ -21,6 +22,7 @@ const argv = cli({
|
|
|
21
22
|
help: {
|
|
22
23
|
description
|
|
23
24
|
},
|
|
25
|
+
strictFlags: true,
|
|
24
26
|
parameters: ["[input files...]"],
|
|
25
27
|
flags: {
|
|
26
28
|
conditions: {
|
|
@@ -37,32 +39,46 @@ const argv = cli({
|
|
|
37
39
|
type: [String],
|
|
38
40
|
alias: "e",
|
|
39
41
|
description: "Dependency to externalize"
|
|
42
|
+
},
|
|
43
|
+
sourcemap: {
|
|
44
|
+
type: Boolean,
|
|
45
|
+
alias: "s",
|
|
46
|
+
description: "Generate sourcemaps"
|
|
40
47
|
}
|
|
41
|
-
// sourcemap: {
|
|
42
|
-
// type: Boolean,
|
|
43
|
-
// description: 'Generate sourcemaps',
|
|
44
|
-
// },
|
|
45
48
|
}
|
|
46
49
|
});
|
|
47
50
|
const { flags } = argv;
|
|
48
|
-
|
|
49
|
-
if (dryMode) {
|
|
51
|
+
if (flags.dryRun) {
|
|
50
52
|
console.log(bgYellow(black(" Dry run - No files will be written ")));
|
|
51
53
|
}
|
|
52
54
|
dtsroll({
|
|
53
55
|
inputs: argv._.inputFiles,
|
|
54
56
|
external: flags.external,
|
|
55
57
|
conditions: flags.conditions,
|
|
56
|
-
dryRun: flags.dryRun
|
|
58
|
+
dryRun: flags.dryRun,
|
|
59
|
+
sourcemap: flags.sourcemap
|
|
57
60
|
}).then(
|
|
58
61
|
(output) => {
|
|
59
62
|
if ("error" in output) {
|
|
60
63
|
process.exitCode = 1;
|
|
61
64
|
}
|
|
62
65
|
logOutput(output);
|
|
63
|
-
}
|
|
66
|
+
}
|
|
67
|
+
).catch(
|
|
64
68
|
(error) => {
|
|
65
|
-
|
|
69
|
+
let errorMessage = "\nFailed to build";
|
|
70
|
+
if (error instanceof DtsrollBuildError) {
|
|
71
|
+
errorMessage += `
|
|
72
|
+
File: ${error.id}`;
|
|
73
|
+
if (error.importChain.length > 1) {
|
|
74
|
+
errorMessage += "\n\n Import chain:\n ";
|
|
75
|
+
errorMessage += error.importChain.join("\n \u2192 ");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
errorMessage += `
|
|
79
|
+
|
|
80
|
+
${error instanceof Error ? error.message : String(error)}`;
|
|
81
|
+
console.error(errorMessage);
|
|
66
82
|
process.exitCode = 1;
|
|
67
83
|
}
|
|
68
84
|
);
|
|
@@ -4,6 +4,7 @@ import { rollup } from 'rollup';
|
|
|
4
4
|
import { dts } from 'rollup-plugin-dts';
|
|
5
5
|
import nodeResolve from '@rollup/plugin-node-resolve';
|
|
6
6
|
import fs$1 from 'node:fs';
|
|
7
|
+
import convert from 'convert-source-map';
|
|
7
8
|
import { up } from 'empathic/find';
|
|
8
9
|
import { resolveImports } from 'resolve-pkg-maps';
|
|
9
10
|
import byteSize from 'byte-size';
|
|
@@ -72,7 +73,13 @@ const bgYellow = kolorist(43, 49);
|
|
|
72
73
|
const cwd = process.cwd();
|
|
73
74
|
|
|
74
75
|
const isPath = (filePath) => filePath[0] === "." || path.isAbsolute(filePath);
|
|
75
|
-
const normalizePath = (filepath) => filepath.replaceAll("\\", "/");
|
|
76
|
+
const normalizePath$1 = (filepath) => filepath.replaceAll("\\", "/");
|
|
77
|
+
const getDisplayPath = (fullPath) => {
|
|
78
|
+
const relativePath = path.relative(cwd, fullPath);
|
|
79
|
+
return normalizePath$1(
|
|
80
|
+
relativePath.length < fullPath.length ? relativePath : fullPath
|
|
81
|
+
);
|
|
82
|
+
};
|
|
76
83
|
|
|
77
84
|
const warningSignUnicode = "\u26A0";
|
|
78
85
|
const warningPrefix = yellow("Warning:");
|
|
@@ -84,10 +91,7 @@ const logOutput = (dtsOutput) => {
|
|
|
84
91
|
\u{1F4E5} Entry points${isCliInput ? "" : " in package.json"}`));
|
|
85
92
|
console.log(
|
|
86
93
|
inputs.map(([inputFile, inputSource, error]) => {
|
|
87
|
-
const
|
|
88
|
-
const logPath2 = normalizePath(
|
|
89
|
-
relativeInputFile.length < inputFile.length ? relativeInputFile : inputFile
|
|
90
|
-
);
|
|
94
|
+
const logPath2 = getDisplayPath(inputFile);
|
|
91
95
|
if (error) {
|
|
92
96
|
return ` ${lightYellow(`${warningSignUnicode} ${logPath2} ${dim(error)}`)}`;
|
|
93
97
|
}
|
|
@@ -107,10 +111,7 @@ const logOutput = (dtsOutput) => {
|
|
|
107
111
|
size,
|
|
108
112
|
externals
|
|
109
113
|
} = dtsOutput;
|
|
110
|
-
const
|
|
111
|
-
const logPath = `${normalizePath(
|
|
112
|
-
outputDirectoryRelative.length < outputDirectory.length ? outputDirectoryRelative : outputDirectory
|
|
113
|
-
)}/`;
|
|
114
|
+
const logPath = `${getDisplayPath(outputDirectory)}/`;
|
|
114
115
|
const logChunk = ({
|
|
115
116
|
file,
|
|
116
117
|
indent,
|
|
@@ -124,10 +125,7 @@ const logOutput = (dtsOutput) => {
|
|
|
124
125
|
${moduleIds.sort().map((moduleId, index) => {
|
|
125
126
|
const isLast = index === moduleIds.length - 1;
|
|
126
127
|
const prefix = `${indent} ${isLast ? "\u2514\u2500 " : "\u251C\u2500 "}`;
|
|
127
|
-
const
|
|
128
|
-
const logModuleId = normalizePath(
|
|
129
|
-
relativeModuleId.length < moduleId.length ? relativeModuleId : moduleId
|
|
130
|
-
);
|
|
128
|
+
const logModuleId = getDisplayPath(moduleId);
|
|
131
129
|
const bareSpecifier = moduleToPackage[moduleId];
|
|
132
130
|
if (bareSpecifier) {
|
|
133
131
|
return `${prefix}${dim(`${magenta(bareSpecifier)} (${logModuleId})`)}`;
|
|
@@ -177,6 +175,17 @@ ${moduleIds.sort().map((moduleId, index) => {
|
|
|
177
175
|
}
|
|
178
176
|
};
|
|
179
177
|
|
|
178
|
+
class DtsrollBuildError extends Error {
|
|
179
|
+
id;
|
|
180
|
+
importChain;
|
|
181
|
+
constructor(message, id, importChain) {
|
|
182
|
+
super(message);
|
|
183
|
+
this.name = "DtsrollBuildError";
|
|
184
|
+
this.id = id;
|
|
185
|
+
this.importChain = importChain;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
180
189
|
const dtsExtensions = [".d.ts", ".d.cts", ".d.mts"];
|
|
181
190
|
const isDts = (fileName) => dtsExtensions.some((extension) => fileName.endsWith(extension));
|
|
182
191
|
|
|
@@ -269,6 +278,7 @@ const getPackageName = (id) => {
|
|
|
269
278
|
return id.slice(0, indexOfSlash);
|
|
270
279
|
};
|
|
271
280
|
|
|
281
|
+
const normalizePath = (filePath) => filePath.replaceAll("\\", "/");
|
|
272
282
|
const getAllFiles = async (directoryPath, dontShortenPath) => {
|
|
273
283
|
const directoryFiles = await fs.readdir(directoryPath, { withFileTypes: true });
|
|
274
284
|
const fileTree = await Promise.all(
|
|
@@ -276,9 +286,9 @@ const getAllFiles = async (directoryPath, dontShortenPath) => {
|
|
|
276
286
|
const filePath = path.join(directoryPath, entry.name);
|
|
277
287
|
if (entry.isDirectory()) {
|
|
278
288
|
const files = await getAllFiles(filePath, true);
|
|
279
|
-
return dontShortenPath ? files : files.map((file) => `./${path.relative(directoryPath, file)}`);
|
|
289
|
+
return dontShortenPath ? files : files.map((file) => `./${normalizePath(path.relative(directoryPath, file))}`);
|
|
280
290
|
}
|
|
281
|
-
return dontShortenPath ? filePath : `./${path.relative(directoryPath, filePath)}`;
|
|
291
|
+
return dontShortenPath ? filePath : `./${normalizePath(path.relative(directoryPath, filePath))}`;
|
|
282
292
|
})
|
|
283
293
|
);
|
|
284
294
|
return fileTree.flat();
|
|
@@ -473,6 +483,129 @@ const createExternalizePlugin = (configuredExternals) => {
|
|
|
473
483
|
};
|
|
474
484
|
};
|
|
475
485
|
|
|
486
|
+
const createImportChainPlugin = () => {
|
|
487
|
+
const importerMap = /* @__PURE__ */ new Map();
|
|
488
|
+
const plugin = {
|
|
489
|
+
name: "import-chain-tracker",
|
|
490
|
+
buildStart: () => {
|
|
491
|
+
importerMap.clear();
|
|
492
|
+
},
|
|
493
|
+
async resolveId(source, importer) {
|
|
494
|
+
if (!importer) {
|
|
495
|
+
return null;
|
|
496
|
+
}
|
|
497
|
+
const resolved = await this.resolve(source, importer, { skipSelf: true });
|
|
498
|
+
if (resolved && !resolved.external && !importerMap.has(resolved.id)) {
|
|
499
|
+
importerMap.set(resolved.id, importer);
|
|
500
|
+
}
|
|
501
|
+
return null;
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
const getImportChain = (errorFileId) => {
|
|
505
|
+
const chain = [];
|
|
506
|
+
let current = errorFileId;
|
|
507
|
+
while (current) {
|
|
508
|
+
chain.unshift(current);
|
|
509
|
+
current = importerMap.get(current);
|
|
510
|
+
}
|
|
511
|
+
return chain;
|
|
512
|
+
};
|
|
513
|
+
return {
|
|
514
|
+
plugin,
|
|
515
|
+
getImportChain
|
|
516
|
+
};
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
const tryReadFile = async (filePath) => {
|
|
520
|
+
try {
|
|
521
|
+
return await fs$1.promises.readFile(filePath, "utf8");
|
|
522
|
+
} catch {
|
|
523
|
+
return null;
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
const loadSourceMap = async (codePath, code) => {
|
|
527
|
+
const adjacentMapPath = `${codePath}.map`;
|
|
528
|
+
const adjacentMapContent = await tryReadFile(adjacentMapPath);
|
|
529
|
+
if (adjacentMapContent) {
|
|
530
|
+
try {
|
|
531
|
+
const converter = convert.fromJSON(adjacentMapContent);
|
|
532
|
+
return {
|
|
533
|
+
map: converter.toObject(),
|
|
534
|
+
mapPath: adjacentMapPath
|
|
535
|
+
};
|
|
536
|
+
} catch {
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
try {
|
|
540
|
+
const inlineConverter = convert.fromSource(code);
|
|
541
|
+
if (inlineConverter) {
|
|
542
|
+
return {
|
|
543
|
+
map: inlineConverter.toObject(),
|
|
544
|
+
mapPath: codePath
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
} catch {
|
|
548
|
+
}
|
|
549
|
+
try {
|
|
550
|
+
const regex = new RegExp(convert.mapFileCommentRegex.source);
|
|
551
|
+
const commentMatch = regex.exec(code);
|
|
552
|
+
const referencedPath = commentMatch?.[1] ?? commentMatch?.[2];
|
|
553
|
+
if (!referencedPath) {
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
const mapFilePath = path.join(path.dirname(codePath), referencedPath);
|
|
557
|
+
const mapContent = await tryReadFile(mapFilePath);
|
|
558
|
+
if (!mapContent) {
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
const converter = convert.fromJSON(mapContent);
|
|
562
|
+
return {
|
|
563
|
+
map: converter.toObject(),
|
|
564
|
+
mapPath: mapFilePath
|
|
565
|
+
};
|
|
566
|
+
} catch {
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
const loadInputSourcemapsPlugin = () => ({
|
|
570
|
+
name: "load-input-sourcemaps",
|
|
571
|
+
async load(id) {
|
|
572
|
+
const isDts = dtsExtensions.some((extension) => id.endsWith(extension));
|
|
573
|
+
if (!isDts) {
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
const code = await tryReadFile(id);
|
|
577
|
+
if (!code) {
|
|
578
|
+
return null;
|
|
579
|
+
}
|
|
580
|
+
const result = await loadSourceMap(id, code);
|
|
581
|
+
if (!result) {
|
|
582
|
+
return { code };
|
|
583
|
+
}
|
|
584
|
+
const { map: inputMap, mapPath } = result;
|
|
585
|
+
const sourceRoot = path.resolve(path.dirname(mapPath), inputMap.sourceRoot ?? ".");
|
|
586
|
+
const sources = inputMap.sources.map(
|
|
587
|
+
(source) => path.isAbsolute(source) ? source : path.resolve(sourceRoot, source)
|
|
588
|
+
);
|
|
589
|
+
const sourcesContentRaw = await Promise.all(
|
|
590
|
+
sources.map(async (source, index) => inputMap.sourcesContent?.[index] ?? tryReadFile(source))
|
|
591
|
+
);
|
|
592
|
+
const sourcesContent = sourcesContentRaw.filter(
|
|
593
|
+
(content) => content !== null
|
|
594
|
+
);
|
|
595
|
+
return {
|
|
596
|
+
code,
|
|
597
|
+
map: {
|
|
598
|
+
version: inputMap.version,
|
|
599
|
+
names: inputMap.names,
|
|
600
|
+
sources,
|
|
601
|
+
mappings: inputMap.mappings,
|
|
602
|
+
...sourcesContent.length > 0 ? { sourcesContent } : {},
|
|
603
|
+
...inputMap.file ? { file: inputMap.file } : {}
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
});
|
|
608
|
+
|
|
476
609
|
const nodeModules = `${path.sep}node_modules${path.sep}`;
|
|
477
610
|
const removeBundledModulesPlugin = (outputDirectory, sizeRef) => {
|
|
478
611
|
let deleteFiles = [];
|
|
@@ -490,14 +623,17 @@ const removeBundledModulesPlugin = (outputDirectory, sizeRef) => {
|
|
|
490
623
|
async generateBundle(options, bundle) {
|
|
491
624
|
const modules = Object.values(bundle);
|
|
492
625
|
const bundledFiles = Array.from(new Set(modules.flatMap(({ moduleIds }) => moduleIds)));
|
|
493
|
-
|
|
494
|
-
|
|
626
|
+
let totalSize = 0;
|
|
627
|
+
for (const moduleId of bundledFiles) {
|
|
628
|
+
const moduleInfo = this.getModuleInfo(moduleId);
|
|
629
|
+
const size = moduleInfo?.meta?.size;
|
|
630
|
+
if (typeof size === "number") {
|
|
631
|
+
totalSize += size;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
495
634
|
sizeRef.value = totalSize;
|
|
496
635
|
const outputFiles = new Set(modules.map(({ fileName }) => path.join(options.dir, fileName)));
|
|
497
|
-
deleteFiles = bundledFiles.filter((moduleId) => (
|
|
498
|
-
// To avoid deleting files from symlinked dependencies
|
|
499
|
-
moduleId.startsWith(outputDirectory) && !moduleId.includes(nodeModules) && !outputFiles.has(moduleId)
|
|
500
|
-
));
|
|
636
|
+
deleteFiles = bundledFiles.filter((moduleId) => moduleId && moduleId.startsWith(outputDirectory) && !moduleId.includes(nodeModules) && !outputFiles.has(moduleId));
|
|
501
637
|
},
|
|
502
638
|
writeBundle: async () => {
|
|
503
639
|
await Promise.all(
|
|
@@ -508,7 +644,7 @@ const removeBundledModulesPlugin = (outputDirectory, sizeRef) => {
|
|
|
508
644
|
};
|
|
509
645
|
|
|
510
646
|
const packageJsonCache = /* @__PURE__ */ new Map();
|
|
511
|
-
const findPackageJsonUp = (cwd) => {
|
|
647
|
+
const findPackageJsonUp = async (cwd) => {
|
|
512
648
|
const packageJsonPath = up("package.json", { cwd });
|
|
513
649
|
if (!packageJsonPath) {
|
|
514
650
|
return void 0;
|
|
@@ -517,7 +653,7 @@ const findPackageJsonUp = (cwd) => {
|
|
|
517
653
|
let packageJson = packageJsonCache.get(packageRoot);
|
|
518
654
|
if (!packageJson) {
|
|
519
655
|
try {
|
|
520
|
-
const content = fs
|
|
656
|
+
const content = await fs.readFile(packageJsonPath, "utf8");
|
|
521
657
|
packageJson = JSON.parse(content);
|
|
522
658
|
packageJsonCache.set(packageRoot, packageJson);
|
|
523
659
|
} catch {
|
|
@@ -537,7 +673,7 @@ const resolveSubpathImportsPlugin = () => ({
|
|
|
537
673
|
if (id[0] !== "#" || !importer) {
|
|
538
674
|
return null;
|
|
539
675
|
}
|
|
540
|
-
const result = findPackageJsonUp(path.dirname(importer));
|
|
676
|
+
const result = await findPackageJsonUp(path.dirname(importer));
|
|
541
677
|
if (!result) {
|
|
542
678
|
return null;
|
|
543
679
|
}
|
|
@@ -565,25 +701,29 @@ const createInputMap = (input, outputDirectory) => Object.fromEntries(
|
|
|
565
701
|
inputFile
|
|
566
702
|
])
|
|
567
703
|
);
|
|
568
|
-
const build = async (input, outputDirectory, externals, mode, conditions) => {
|
|
704
|
+
const build = async (input, outputDirectory, externals, mode, conditions, sourcemap) => {
|
|
569
705
|
const {
|
|
570
706
|
externalizePlugin,
|
|
571
707
|
externalized,
|
|
572
708
|
getPackageEntryPoint
|
|
573
709
|
} = createExternalizePlugin(externals);
|
|
710
|
+
const { plugin: importChainPlugin, getImportChain } = createImportChainPlugin();
|
|
574
711
|
const sizeRef = {};
|
|
575
712
|
const rollupConfig = {
|
|
576
713
|
input: createInputMap(input, outputDirectory),
|
|
577
714
|
output: {
|
|
578
|
-
|
|
715
|
+
sourcemap,
|
|
579
716
|
dir: outputDirectory,
|
|
580
717
|
entryFileNames: "[name]",
|
|
581
718
|
chunkFileNames: "_dtsroll-chunks/[hash]-[name].ts"
|
|
582
719
|
},
|
|
583
720
|
plugins: [
|
|
721
|
+
importChainPlugin,
|
|
584
722
|
externalizePlugin,
|
|
585
723
|
removeBundledModulesPlugin(outputDirectory, sizeRef),
|
|
586
724
|
resolveSubpathImportsPlugin(),
|
|
725
|
+
// Load existing .d.ts.map files to chain sourcemaps back to original .ts sources
|
|
726
|
+
sourcemap && loadInputSourcemapsPlugin(),
|
|
587
727
|
nodeResolve({
|
|
588
728
|
extensions: [".ts", ...dtsExtensions],
|
|
589
729
|
exportConditions: conditions
|
|
@@ -600,15 +740,26 @@ const build = async (input, outputDirectory, externals, mode, conditions) => {
|
|
|
600
740
|
})
|
|
601
741
|
]
|
|
602
742
|
};
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
743
|
+
try {
|
|
744
|
+
const rollupBuild = await rollup(rollupConfig);
|
|
745
|
+
const built = await rollupBuild[mode](rollupConfig.output);
|
|
746
|
+
await rollupBuild.close();
|
|
747
|
+
return {
|
|
748
|
+
built,
|
|
749
|
+
externalized,
|
|
750
|
+
getPackageEntryPoint,
|
|
751
|
+
sourceSize: sizeRef.value ?? 0
|
|
752
|
+
};
|
|
753
|
+
} catch (error) {
|
|
754
|
+
if (error instanceof Error && "id" in error && typeof error.id === "string") {
|
|
755
|
+
throw new DtsrollBuildError(
|
|
756
|
+
error.message,
|
|
757
|
+
error.id,
|
|
758
|
+
getImportChain(error.id)
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
throw error;
|
|
762
|
+
}
|
|
612
763
|
};
|
|
613
764
|
|
|
614
765
|
const dtsroll = async ({
|
|
@@ -616,7 +767,8 @@ const dtsroll = async ({
|
|
|
616
767
|
inputs,
|
|
617
768
|
external,
|
|
618
769
|
conditions,
|
|
619
|
-
dryRun
|
|
770
|
+
dryRun,
|
|
771
|
+
sourcemap
|
|
620
772
|
} = {}) => {
|
|
621
773
|
const pkgJson = await getPackageJson(cwd);
|
|
622
774
|
const externals = pkgJson ? pkgJson.getExternals() : /* @__PURE__ */ new Map();
|
|
@@ -651,13 +803,15 @@ const dtsroll = async ({
|
|
|
651
803
|
outputDirectory,
|
|
652
804
|
externals,
|
|
653
805
|
dryRun ? "generate" : "write",
|
|
654
|
-
conditions
|
|
806
|
+
conditions,
|
|
807
|
+
sourcemap
|
|
655
808
|
);
|
|
656
809
|
let outputSize = 0;
|
|
657
810
|
const outputEntries = [];
|
|
658
811
|
const outputChunks = [];
|
|
659
812
|
const moduleImports = /* @__PURE__ */ new Set();
|
|
660
|
-
|
|
813
|
+
const chunks = built.output.filter((file) => file.type === "chunk");
|
|
814
|
+
for (const file of chunks) {
|
|
661
815
|
const size = Buffer.byteLength(file.code);
|
|
662
816
|
outputSize += size;
|
|
663
817
|
const moduleToPackage = Object.fromEntries(
|
|
@@ -702,4 +856,4 @@ const dtsroll = async ({
|
|
|
702
856
|
};
|
|
703
857
|
};
|
|
704
858
|
|
|
705
|
-
export { black as a, bgYellow as b, dtsroll as d, logOutput as l };
|
|
859
|
+
export { DtsrollBuildError as D, black as a, bgYellow as b, dtsroll as d, logOutput as l };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,19 +1,36 @@
|
|
|
1
1
|
import { OutputChunk } from 'rollup';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Extended output chunk with additional metadata.
|
|
5
|
+
*/
|
|
3
6
|
type Output = OutputChunk & {
|
|
7
|
+
/** Size of the output file in bytes. */
|
|
4
8
|
size: number;
|
|
9
|
+
/** Map of module IDs to their package names. */
|
|
5
10
|
moduleToPackage: Record<string, string | undefined>;
|
|
6
11
|
};
|
|
12
|
+
/**
|
|
13
|
+
* List of externalized packages with metadata.
|
|
14
|
+
* Each entry is [packageName, reason, warning?].
|
|
15
|
+
*/
|
|
7
16
|
type Externals = [
|
|
8
17
|
packageName: string,
|
|
9
18
|
reason?: string,
|
|
10
19
|
warning?: string
|
|
11
20
|
][];
|
|
21
|
+
/**
|
|
22
|
+
* Validated input file with source info and optional error.
|
|
23
|
+
* Tuple format: [inputPath, inputSource, error?].
|
|
24
|
+
*/
|
|
12
25
|
type ValidatedInput = [
|
|
13
26
|
inputPath: string,
|
|
14
27
|
inputSource: string | undefined,
|
|
15
28
|
error?: string
|
|
16
29
|
];
|
|
30
|
+
/**
|
|
31
|
+
* Output from the dtsroll build process.
|
|
32
|
+
* Returns either an error state or successful build results.
|
|
33
|
+
*/
|
|
17
34
|
type DtsrollOutput = {
|
|
18
35
|
inputs: ValidatedInput[];
|
|
19
36
|
error: string;
|
|
@@ -31,14 +48,30 @@ type DtsrollOutput = {
|
|
|
31
48
|
externals: Externals;
|
|
32
49
|
};
|
|
33
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Configuration options for dtsroll.
|
|
53
|
+
*/
|
|
34
54
|
type Options = {
|
|
55
|
+
/** Working directory. Defaults to process.cwd(). */
|
|
35
56
|
cwd?: string;
|
|
57
|
+
/** Input .d.ts files to bundle. If not provided, auto-detects from package.json. */
|
|
36
58
|
inputs?: string[];
|
|
59
|
+
/** Packages to externalize (only used when no package.json is present). */
|
|
37
60
|
external?: string[];
|
|
61
|
+
/** Export conditions for module resolution. */
|
|
38
62
|
conditions?: string[];
|
|
63
|
+
/** If true, generates output without writing files. */
|
|
39
64
|
dryRun?: boolean;
|
|
65
|
+
/** If true, generates source maps (.d.ts.map files). */
|
|
66
|
+
sourcemap?: boolean;
|
|
40
67
|
};
|
|
41
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Bundle TypeScript declaration files using Rollup.
|
|
70
|
+
*
|
|
71
|
+
* @param options - Configuration options
|
|
72
|
+
* @returns Build output including bundled files, sizes, and externalized packages
|
|
73
|
+
*/
|
|
74
|
+
declare const dtsroll: ({ cwd, inputs, external, conditions, dryRun, sourcemap, }?: Options) => Promise<DtsrollOutput>;
|
|
42
75
|
|
|
43
76
|
export { dtsroll };
|
|
44
77
|
export type { DtsrollOutput, Options };
|
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import 'node:path';
|
|
3
|
-
export { d as dtsroll } from './index-
|
|
3
|
+
export { d as dtsroll } from './index-r9RZgCg7.mjs';
|
|
4
4
|
import 'node:fs/promises';
|
|
5
5
|
import 'rollup';
|
|
6
6
|
import 'rollup-plugin-dts';
|
|
7
7
|
import '@rollup/plugin-node-resolve';
|
|
8
8
|
import 'node:fs';
|
|
9
|
+
import 'convert-source-map';
|
|
9
10
|
import 'empathic/find';
|
|
10
11
|
import 'resolve-pkg-maps';
|
|
11
12
|
import 'byte-size';
|
package/dist/vite.d.ts
CHANGED
|
@@ -2,6 +2,13 @@ import { Plugin } from 'vite';
|
|
|
2
2
|
import { Options } from './index.js';
|
|
3
3
|
import 'rollup';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Vite plugin for bundling TypeScript declaration files.
|
|
7
|
+
* Runs after vite-plugin-dts in the writeBundle hook.
|
|
8
|
+
*
|
|
9
|
+
* @param options - Configuration options (same as dtsroll function)
|
|
10
|
+
* @returns Vite plugin instance
|
|
11
|
+
*/
|
|
5
12
|
declare const dtsrollPlugin: (options?: Options) => Plugin;
|
|
6
13
|
|
|
7
14
|
export { dtsrollPlugin as dtsroll };
|
package/dist/vite.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { d as dtsroll, l as logOutput } from './index-
|
|
2
|
+
import { d as dtsroll, l as logOutput } from './index-r9RZgCg7.mjs';
|
|
3
3
|
import 'node:path';
|
|
4
4
|
import 'node:fs/promises';
|
|
5
5
|
import 'rollup';
|
|
6
6
|
import 'rollup-plugin-dts';
|
|
7
7
|
import '@rollup/plugin-node-resolve';
|
|
8
8
|
import 'node:fs';
|
|
9
|
+
import 'convert-source-map';
|
|
9
10
|
import 'empathic/find';
|
|
10
11
|
import 'resolve-pkg-maps';
|
|
11
12
|
import 'byte-size';
|
|
@@ -29,14 +30,22 @@ const dtsrollPlugin = (options) => {
|
|
|
29
30
|
if (built) {
|
|
30
31
|
return;
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
try {
|
|
34
|
+
const output = await dtsroll({
|
|
35
|
+
cwd,
|
|
36
|
+
...options
|
|
37
|
+
});
|
|
38
|
+
built = true;
|
|
39
|
+
if (!noLog) {
|
|
40
|
+
logOutput(output);
|
|
41
|
+
console.log();
|
|
42
|
+
}
|
|
43
|
+
} catch (error) {
|
|
44
|
+
built = true;
|
|
45
|
+
throw new Error(
|
|
46
|
+
`dtsroll failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
47
|
+
{ cause: error }
|
|
48
|
+
);
|
|
40
49
|
}
|
|
41
50
|
}
|
|
42
51
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dtsroll",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Bundle dts files",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bundle",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
41
41
|
"byte-size": "^9.0.1",
|
|
42
42
|
"cleye": "^2.2.1",
|
|
43
|
+
"convert-source-map": "^2.0.0",
|
|
43
44
|
"empathic": "^2.0.0",
|
|
44
45
|
"resolve-pkg-maps": "^1.0.0",
|
|
45
46
|
"rollup": "^4.55.1",
|