webpack-plugin-dtsx 0.9.10
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/LICENSE.md +21 -0
- package/README.md +249 -0
- package/dist/index.d.ts +56 -0
- package/dist/index.js +312 -0
- package/package.json +57 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Open Web Foundation
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# webpack-plugin-dtsx
|
|
2
|
+
|
|
3
|
+
A webpack plugin for automatic TypeScript declaration file generation using dtsx.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add webpack-plugin-dtsx -d
|
|
9
|
+
# or
|
|
10
|
+
npm install webpack-plugin-dtsx --save-dev
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
// webpack.config.js
|
|
17
|
+
const { DtsxWebpackPlugin } = require('webpack-plugin-dtsx')
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
entry: './src/index.ts',
|
|
21
|
+
output: {
|
|
22
|
+
path: path.resolve(__dirname, 'dist'),
|
|
23
|
+
filename: 'bundle.js',
|
|
24
|
+
},
|
|
25
|
+
plugins: [
|
|
26
|
+
new DtsxWebpackPlugin({
|
|
27
|
+
// Options
|
|
28
|
+
}),
|
|
29
|
+
],
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### ESM Usage
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
// webpack.config.mjs
|
|
37
|
+
import { DtsxWebpackPlugin } from 'webpack-plugin-dtsx'
|
|
38
|
+
|
|
39
|
+
export default {
|
|
40
|
+
entry: './src/index.ts',
|
|
41
|
+
output: {
|
|
42
|
+
path: new URL('./dist', import.meta.url).pathname,
|
|
43
|
+
filename: 'bundle.js',
|
|
44
|
+
},
|
|
45
|
+
plugins: [
|
|
46
|
+
new DtsxWebpackPlugin(),
|
|
47
|
+
],
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Options
|
|
52
|
+
|
|
53
|
+
| Option | Type | Default | Description |
|
|
54
|
+
|--------|------|---------|-------------|
|
|
55
|
+
| `trigger` | `'emit' \| 'afterEmit' \| 'done'` | `'afterEmit'` | When to generate declarations |
|
|
56
|
+
| `entryPointsOnly` | `boolean` | `true` | Only generate for entry points |
|
|
57
|
+
| `declarationDir` | `string` | webpack output path | Output directory for declarations |
|
|
58
|
+
| `bundle` | `boolean` | `false` | Bundle all declarations into one file |
|
|
59
|
+
| `bundleOutput` | `string` | `'index.d.ts'` | Bundled output filename |
|
|
60
|
+
| `exclude` | `(string \| RegExp)[]` | `[]` | Patterns to exclude |
|
|
61
|
+
| `include` | `(string \| RegExp)[]` | `[]` | Patterns to include |
|
|
62
|
+
| `emitOnError` | `boolean` | `false` | Emit even with compilation errors |
|
|
63
|
+
| `skipUnchanged` | `boolean` | `true` | Skip if no TS files changed (watch mode) |
|
|
64
|
+
|
|
65
|
+
## Examples
|
|
66
|
+
|
|
67
|
+
### Basic Usage
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
const { DtsxWebpackPlugin } = require('webpack-plugin-dtsx')
|
|
71
|
+
|
|
72
|
+
module.exports = {
|
|
73
|
+
// ...
|
|
74
|
+
plugins: [
|
|
75
|
+
new DtsxWebpackPlugin(),
|
|
76
|
+
],
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### With Bundled Declarations
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
const { DtsxWebpackPlugin } = require('webpack-plugin-dtsx')
|
|
84
|
+
|
|
85
|
+
module.exports = {
|
|
86
|
+
// ...
|
|
87
|
+
plugins: [
|
|
88
|
+
new DtsxWebpackPlugin({
|
|
89
|
+
bundle: true,
|
|
90
|
+
bundleOutput: 'types.d.ts',
|
|
91
|
+
}),
|
|
92
|
+
],
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Custom Output Directory
|
|
97
|
+
|
|
98
|
+
```javascript
|
|
99
|
+
const { DtsxWebpackPlugin } = require('webpack-plugin-dtsx')
|
|
100
|
+
|
|
101
|
+
module.exports = {
|
|
102
|
+
// ...
|
|
103
|
+
plugins: [
|
|
104
|
+
new DtsxWebpackPlugin({
|
|
105
|
+
declarationDir: 'types', // Outputs to dist/types/
|
|
106
|
+
}),
|
|
107
|
+
],
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Generate on Different Phases
|
|
112
|
+
|
|
113
|
+
```javascript
|
|
114
|
+
const { DtsxWebpackPlugin } = require('webpack-plugin-dtsx')
|
|
115
|
+
|
|
116
|
+
module.exports = {
|
|
117
|
+
// ...
|
|
118
|
+
plugins: [
|
|
119
|
+
new DtsxWebpackPlugin({
|
|
120
|
+
// 'emit' - During asset emission
|
|
121
|
+
// 'afterEmit' - After assets are written (default)
|
|
122
|
+
// 'done' - When compilation is complete
|
|
123
|
+
trigger: 'done',
|
|
124
|
+
}),
|
|
125
|
+
],
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### With Callbacks
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
const { DtsxWebpackPlugin } = require('webpack-plugin-dtsx')
|
|
133
|
+
|
|
134
|
+
module.exports = {
|
|
135
|
+
// ...
|
|
136
|
+
plugins: [
|
|
137
|
+
new DtsxWebpackPlugin({
|
|
138
|
+
onStart: () => {
|
|
139
|
+
console.log('Starting declaration generation...')
|
|
140
|
+
},
|
|
141
|
+
onSuccess: (stats) => {
|
|
142
|
+
console.log(`Generated ${stats.totalFiles} files in ${stats.totalTime}ms`)
|
|
143
|
+
},
|
|
144
|
+
onError: (error) => {
|
|
145
|
+
console.error('Failed to generate declarations:', error.message)
|
|
146
|
+
},
|
|
147
|
+
}),
|
|
148
|
+
],
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Filter Files
|
|
153
|
+
|
|
154
|
+
```javascript
|
|
155
|
+
const { DtsxWebpackPlugin } = require('webpack-plugin-dtsx')
|
|
156
|
+
|
|
157
|
+
module.exports = {
|
|
158
|
+
// ...
|
|
159
|
+
plugins: [
|
|
160
|
+
new DtsxWebpackPlugin({
|
|
161
|
+
include: [/src\/lib/],
|
|
162
|
+
exclude: ['test', /\.spec\.ts$/],
|
|
163
|
+
}),
|
|
164
|
+
],
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Process All TypeScript Files
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
const { DtsxWebpackPlugin } = require('webpack-plugin-dtsx')
|
|
172
|
+
|
|
173
|
+
module.exports = {
|
|
174
|
+
// ...
|
|
175
|
+
plugins: [
|
|
176
|
+
new DtsxWebpackPlugin({
|
|
177
|
+
entryPointsOnly: false, // Process all TS files in compilation
|
|
178
|
+
}),
|
|
179
|
+
],
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Additional Plugins
|
|
184
|
+
|
|
185
|
+
### Type Checking Only
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
const { dtsxCheck } = require('webpack-plugin-dtsx')
|
|
189
|
+
|
|
190
|
+
module.exports = {
|
|
191
|
+
plugins: [dtsxCheck()],
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Watch for Declaration Changes
|
|
196
|
+
|
|
197
|
+
```javascript
|
|
198
|
+
const { dtsxWatch } = require('webpack-plugin-dtsx')
|
|
199
|
+
|
|
200
|
+
module.exports = {
|
|
201
|
+
plugins: [
|
|
202
|
+
dtsxWatch({
|
|
203
|
+
onDeclarationChange: (file) => {
|
|
204
|
+
console.log(`Declaration changed: ${file}`)
|
|
205
|
+
},
|
|
206
|
+
}),
|
|
207
|
+
],
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Factory Function
|
|
212
|
+
|
|
213
|
+
You can also use the factory function:
|
|
214
|
+
|
|
215
|
+
```javascript
|
|
216
|
+
const { dtsx } = require('webpack-plugin-dtsx')
|
|
217
|
+
|
|
218
|
+
module.exports = {
|
|
219
|
+
plugins: [
|
|
220
|
+
dtsx({
|
|
221
|
+
bundle: true,
|
|
222
|
+
}),
|
|
223
|
+
],
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Webpack 4 vs 5
|
|
228
|
+
|
|
229
|
+
This plugin supports both webpack 4 and webpack 5. The API is the same for both versions.
|
|
230
|
+
|
|
231
|
+
## TypeScript Configuration
|
|
232
|
+
|
|
233
|
+
The plugin automatically detects your `tsconfig.json`. You can also specify a custom path:
|
|
234
|
+
|
|
235
|
+
```javascript
|
|
236
|
+
new DtsxWebpackPlugin({
|
|
237
|
+
tsconfigPath: './tsconfig.build.json',
|
|
238
|
+
})
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Performance Tips
|
|
242
|
+
|
|
243
|
+
1. **Use `entryPointsOnly: true`** (default) for faster builds
|
|
244
|
+
2. **Enable `skipUnchanged`** (default) in watch mode
|
|
245
|
+
3. **Use `trigger: 'done'`** if you don't need declarations during emit
|
|
246
|
+
|
|
247
|
+
## License
|
|
248
|
+
|
|
249
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Compiler } from 'webpack';
|
|
2
|
+
import type { DtsGenerationOption, GenerationStats } from '@stacksjs/dtsx';
|
|
3
|
+
// Re-export types
|
|
4
|
+
export type { DtsGenerationOption, GenerationStats };
|
|
5
|
+
/**
|
|
6
|
+
* Factory function for creating the plugin
|
|
7
|
+
*/
|
|
8
|
+
export declare function dtsx(options?: DtsxWebpackOptions): DtsxWebpackPlugin;
|
|
9
|
+
/**
|
|
10
|
+
* Factory function for check plugin
|
|
11
|
+
*/
|
|
12
|
+
export declare function dtsxCheck(): DtsxCheckPlugin;
|
|
13
|
+
/**
|
|
14
|
+
* Factory function for watch plugin
|
|
15
|
+
*/
|
|
16
|
+
export declare function dtsxWatch(options?: { onDeclarationChange?: (file: string) => void }): DtsxWatchPlugin;
|
|
17
|
+
/**
|
|
18
|
+
* Plugin configuration options
|
|
19
|
+
*/
|
|
20
|
+
export declare interface DtsxWebpackOptions extends Omit<Partial<DtsGenerationOption>, 'exclude' | 'include'> {
|
|
21
|
+
trigger?: 'emit' | 'afterEmit' | 'done'
|
|
22
|
+
entryPointsOnly?: boolean
|
|
23
|
+
declarationDir?: string
|
|
24
|
+
bundle?: boolean
|
|
25
|
+
bundleOutput?: string
|
|
26
|
+
exclude?: (string | RegExp)[]
|
|
27
|
+
include?: (string | RegExp)[]
|
|
28
|
+
emitOnError?: boolean
|
|
29
|
+
declarationMap?: boolean
|
|
30
|
+
skipUnchanged?: boolean
|
|
31
|
+
onSuccess?: (stats: GenerationStats) => void | Promise<void>
|
|
32
|
+
onError?: (error: Error) => void | Promise<void>
|
|
33
|
+
onStart?: () => void | Promise<void>
|
|
34
|
+
onProgress?: (current: number, total: number, file: string) => void
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Webpack plugin for dtsx declaration generation
|
|
38
|
+
*/
|
|
39
|
+
export declare class DtsxWebpackPlugin {
|
|
40
|
+
constructor(options?: DtsxWebpackOptions);
|
|
41
|
+
apply(compiler: Compiler): void;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Create a minimal plugin that only validates types
|
|
45
|
+
*/
|
|
46
|
+
export declare class DtsxCheckPlugin {
|
|
47
|
+
apply(compiler: Compiler): void;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create a plugin that watches for .d.ts changes
|
|
51
|
+
*/
|
|
52
|
+
export declare class DtsxWatchPlugin {
|
|
53
|
+
constructor(options?: { onDeclarationChange?: (file: string) => void });
|
|
54
|
+
apply(compiler: Compiler): void;
|
|
55
|
+
}
|
|
56
|
+
export default DtsxWebpackPlugin;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { generate } from "@stacksjs/dtsx";
|
|
3
|
+
import { resolve, relative, join, dirname } from "node:path";
|
|
4
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from "node:fs";
|
|
5
|
+
var PLUGIN_NAME = "DtsxWebpackPlugin";
|
|
6
|
+
|
|
7
|
+
class DtsxWebpackPlugin {
|
|
8
|
+
options;
|
|
9
|
+
state;
|
|
10
|
+
constructor(options = {}) {
|
|
11
|
+
this.options = {
|
|
12
|
+
trigger: "afterEmit",
|
|
13
|
+
entryPointsOnly: true,
|
|
14
|
+
bundle: false,
|
|
15
|
+
bundleOutput: "index.d.ts",
|
|
16
|
+
emitOnError: false,
|
|
17
|
+
declarationMap: false,
|
|
18
|
+
skipUnchanged: true,
|
|
19
|
+
...options
|
|
20
|
+
};
|
|
21
|
+
this.state = {
|
|
22
|
+
lastBuildFiles: new Set,
|
|
23
|
+
generatedFiles: new Set,
|
|
24
|
+
isFirstBuild: true,
|
|
25
|
+
errors: []
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
apply(compiler) {
|
|
29
|
+
const { trigger } = this.options;
|
|
30
|
+
switch (trigger) {
|
|
31
|
+
case "emit":
|
|
32
|
+
compiler.hooks.emit.tapAsync(PLUGIN_NAME, (compilation, callback) => {
|
|
33
|
+
this.handleGeneration(compiler, compilation).then(() => callback()).catch(callback);
|
|
34
|
+
});
|
|
35
|
+
break;
|
|
36
|
+
case "afterEmit":
|
|
37
|
+
compiler.hooks.afterEmit.tapAsync(PLUGIN_NAME, (compilation, callback) => {
|
|
38
|
+
this.handleGeneration(compiler, compilation).then(() => callback()).catch(callback);
|
|
39
|
+
});
|
|
40
|
+
break;
|
|
41
|
+
case "done":
|
|
42
|
+
compiler.hooks.done.tapAsync(PLUGIN_NAME, (stats, callback) => {
|
|
43
|
+
this.handleGeneration(compiler, stats.compilation).then(() => callback()).catch(callback);
|
|
44
|
+
});
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
compiler.hooks.watchRun.tap(PLUGIN_NAME, () => {
|
|
48
|
+
this.state.isFirstBuild = false;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
async handleGeneration(compiler, compilation) {
|
|
52
|
+
const {
|
|
53
|
+
entryPointsOnly,
|
|
54
|
+
declarationDir,
|
|
55
|
+
bundle,
|
|
56
|
+
bundleOutput,
|
|
57
|
+
exclude = [],
|
|
58
|
+
include = [],
|
|
59
|
+
emitOnError,
|
|
60
|
+
skipUnchanged,
|
|
61
|
+
onSuccess,
|
|
62
|
+
onError,
|
|
63
|
+
onStart,
|
|
64
|
+
...dtsOptions
|
|
65
|
+
} = this.options;
|
|
66
|
+
if (compilation.errors.length > 0 && !emitOnError) {
|
|
67
|
+
console.log(`[${PLUGIN_NAME}] Skipping declaration generation due to compilation errors`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
await onStart?.();
|
|
72
|
+
let filesToProcess = this.getFilesToProcess(compiler, compilation, entryPointsOnly);
|
|
73
|
+
filesToProcess = this.filterFiles(filesToProcess, include, exclude);
|
|
74
|
+
if (skipUnchanged && !this.state.isFirstBuild) {
|
|
75
|
+
const currentFiles = new Set(filesToProcess);
|
|
76
|
+
const hasChanges = this.hasFileChanges(currentFiles);
|
|
77
|
+
if (!hasChanges) {
|
|
78
|
+
console.log(`[${PLUGIN_NAME}] No TypeScript changes detected, skipping`);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
this.state.lastBuildFiles = currentFiles;
|
|
82
|
+
}
|
|
83
|
+
if (filesToProcess.length === 0) {
|
|
84
|
+
console.log(`[${PLUGIN_NAME}] No files to process`);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
console.log(`[${PLUGIN_NAME}] Generating declarations for ${filesToProcess.length} file(s)...`);
|
|
88
|
+
const outputPath = compiler.options.output?.path || "dist";
|
|
89
|
+
const outdir = declarationDir ? resolve(outputPath, declarationDir) : outputPath;
|
|
90
|
+
const config = this.normalizeConfig(dtsOptions, compiler, outdir);
|
|
91
|
+
const stats = await generate({
|
|
92
|
+
...config,
|
|
93
|
+
entrypoints: filesToProcess.map((f) => relative(config.cwd || process.cwd(), f))
|
|
94
|
+
});
|
|
95
|
+
this.state.generatedFiles = new Set;
|
|
96
|
+
if (bundle && this.state.generatedFiles.size > 0) {
|
|
97
|
+
await this.bundleDeclarations(Array.from(this.state.generatedFiles), join(outdir, bundleOutput));
|
|
98
|
+
}
|
|
99
|
+
await onSuccess?.(stats);
|
|
100
|
+
console.log(`[${PLUGIN_NAME}] Generated ${this.state.generatedFiles.size} declaration file(s)`);
|
|
101
|
+
} catch (error) {
|
|
102
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
103
|
+
this.state.errors.push(err);
|
|
104
|
+
if (onError) {
|
|
105
|
+
await onError(err);
|
|
106
|
+
} else {
|
|
107
|
+
console.error(`[${PLUGIN_NAME}] Error generating declarations:`, err.message);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
getFilesToProcess(compiler, compilation, entryPointsOnly) {
|
|
112
|
+
const files = [];
|
|
113
|
+
if (entryPointsOnly) {
|
|
114
|
+
const entries = compiler.options.entry;
|
|
115
|
+
if (typeof entries === "string") {
|
|
116
|
+
files.push(resolve(entries));
|
|
117
|
+
} else if (Array.isArray(entries)) {
|
|
118
|
+
for (const entry of entries) {
|
|
119
|
+
if (typeof entry === "string") {
|
|
120
|
+
files.push(resolve(entry));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} else if (typeof entries === "object") {
|
|
124
|
+
for (const [, entry] of Object.entries(entries)) {
|
|
125
|
+
if (typeof entry === "string") {
|
|
126
|
+
files.push(resolve(entry));
|
|
127
|
+
} else if (typeof entry === "object" && entry.import) {
|
|
128
|
+
const imports = Array.isArray(entry.import) ? entry.import : [entry.import];
|
|
129
|
+
for (const imp of imports) {
|
|
130
|
+
if (typeof imp === "string") {
|
|
131
|
+
files.push(resolve(imp));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
for (const module of compilation.modules) {
|
|
139
|
+
const resource = module.resource;
|
|
140
|
+
if (resource && this.isTypeScriptFile(resource)) {
|
|
141
|
+
files.push(resource);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return files.filter((f) => this.isTypeScriptFile(f));
|
|
146
|
+
}
|
|
147
|
+
isTypeScriptFile(file) {
|
|
148
|
+
return (file.endsWith(".ts") || file.endsWith(".tsx")) && !file.endsWith(".d.ts");
|
|
149
|
+
}
|
|
150
|
+
filterFiles(files, include, exclude) {
|
|
151
|
+
return files.filter((file) => {
|
|
152
|
+
for (const pattern of exclude) {
|
|
153
|
+
if (typeof pattern === "string") {
|
|
154
|
+
if (file.includes(pattern))
|
|
155
|
+
return false;
|
|
156
|
+
} else if (pattern.test(file)) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (include.length > 0) {
|
|
161
|
+
for (const pattern of include) {
|
|
162
|
+
if (typeof pattern === "string") {
|
|
163
|
+
if (file.includes(pattern))
|
|
164
|
+
return true;
|
|
165
|
+
} else if (pattern.test(file)) {
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
return true;
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
hasFileChanges(currentFiles) {
|
|
175
|
+
if (currentFiles.size !== this.state.lastBuildFiles.size) {
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
for (const file of currentFiles) {
|
|
179
|
+
if (!this.state.lastBuildFiles.has(file)) {
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
normalizeConfig(options, compiler, outdir) {
|
|
186
|
+
const context = compiler.options.context || process.cwd();
|
|
187
|
+
let tsconfigPath = options.tsconfigPath;
|
|
188
|
+
if (!tsconfigPath) {
|
|
189
|
+
const defaultPaths = ["tsconfig.json", "tsconfig.build.json"];
|
|
190
|
+
for (const p of defaultPaths) {
|
|
191
|
+
if (existsSync(resolve(context, p))) {
|
|
192
|
+
tsconfigPath = p;
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
cwd: context,
|
|
199
|
+
root: options.root || "./src",
|
|
200
|
+
outdir,
|
|
201
|
+
tsconfigPath,
|
|
202
|
+
clean: options.clean ?? false,
|
|
203
|
+
keepComments: options.keepComments ?? true,
|
|
204
|
+
...options
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
async bundleDeclarations(files, outputPath) {
|
|
208
|
+
const contents = [
|
|
209
|
+
"/**",
|
|
210
|
+
" * Bundled TypeScript declarations",
|
|
211
|
+
` * Generated by ${PLUGIN_NAME}`,
|
|
212
|
+
" */",
|
|
213
|
+
""
|
|
214
|
+
];
|
|
215
|
+
const imports = new Map;
|
|
216
|
+
const declarations = [];
|
|
217
|
+
for (const file of files) {
|
|
218
|
+
if (!existsSync(file))
|
|
219
|
+
continue;
|
|
220
|
+
const content = readFileSync(file, "utf-8");
|
|
221
|
+
const lines = content.split(`
|
|
222
|
+
`);
|
|
223
|
+
for (const line of lines) {
|
|
224
|
+
const trimmed = line.trim();
|
|
225
|
+
if (trimmed.startsWith("import ")) {
|
|
226
|
+
const match = trimmed.match(/from\s+['"]([^'"]+)['"]/);
|
|
227
|
+
if (match && !match[1].startsWith(".")) {
|
|
228
|
+
if (!imports.has(match[1])) {
|
|
229
|
+
imports.set(match[1], new Set);
|
|
230
|
+
}
|
|
231
|
+
const specMatch = trimmed.match(/\{([^}]+)\}/);
|
|
232
|
+
if (specMatch) {
|
|
233
|
+
specMatch[1].split(",").forEach((s) => {
|
|
234
|
+
imports.get(match[1]).add(s.trim());
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
if (trimmed.startsWith("import ") || trimmed === "")
|
|
241
|
+
continue;
|
|
242
|
+
declarations.push(line);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
for (const [source, specifiers] of imports) {
|
|
246
|
+
if (specifiers.size > 0) {
|
|
247
|
+
contents.push(`import { ${Array.from(specifiers).join(", ")} } from '${source}';`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (imports.size > 0) {
|
|
251
|
+
contents.push("");
|
|
252
|
+
}
|
|
253
|
+
contents.push(...declarations);
|
|
254
|
+
const outDir = dirname(outputPath);
|
|
255
|
+
if (!existsSync(outDir)) {
|
|
256
|
+
mkdirSync(outDir, { recursive: true });
|
|
257
|
+
}
|
|
258
|
+
writeFileSync(outputPath, contents.join(`
|
|
259
|
+
`));
|
|
260
|
+
console.log(`[${PLUGIN_NAME}] Bundled declarations to ${outputPath}`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function dtsx(options = {}) {
|
|
264
|
+
return new DtsxWebpackPlugin(options);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
class DtsxCheckPlugin {
|
|
268
|
+
apply(compiler) {
|
|
269
|
+
compiler.hooks.done.tap("DtsxCheckPlugin", (stats) => {
|
|
270
|
+
if (stats.hasErrors()) {
|
|
271
|
+
console.log("[DtsxCheckPlugin] Build has errors, skipping type check");
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
console.log("[DtsxCheckPlugin] Build passed");
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
function dtsxCheck() {
|
|
279
|
+
return new DtsxCheckPlugin;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
class DtsxWatchPlugin {
|
|
283
|
+
options;
|
|
284
|
+
constructor(options = {}) {
|
|
285
|
+
this.options = options;
|
|
286
|
+
}
|
|
287
|
+
apply(compiler) {
|
|
288
|
+
const { onDeclarationChange } = this.options;
|
|
289
|
+
compiler.hooks.afterEmit.tap("DtsxWatchPlugin", (compilation) => {
|
|
290
|
+
if (!onDeclarationChange)
|
|
291
|
+
return;
|
|
292
|
+
for (const file of compilation.emittedAssets) {
|
|
293
|
+
if (file.endsWith(".d.ts")) {
|
|
294
|
+
onDeclarationChange(file);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
function dtsxWatch(options = {}) {
|
|
301
|
+
return new DtsxWatchPlugin(options);
|
|
302
|
+
}
|
|
303
|
+
var src_default = DtsxWebpackPlugin;
|
|
304
|
+
export {
|
|
305
|
+
dtsxWatch,
|
|
306
|
+
dtsxCheck,
|
|
307
|
+
dtsx,
|
|
308
|
+
src_default as default,
|
|
309
|
+
DtsxWebpackPlugin,
|
|
310
|
+
DtsxWatchPlugin,
|
|
311
|
+
DtsxCheckPlugin
|
|
312
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "webpack-plugin-dtsx",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.9.10",
|
|
5
|
+
"description": "A webpack plugin that auto generates your DTS types extremely fast.",
|
|
6
|
+
"author": "Chris Breuer <chris@ow3.org>",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://github.com/stacksjs/dtsx/tree/main/packages/webpack-plugin#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/stacksjs/dtsx.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/stacksjs/dtsx/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"dts",
|
|
18
|
+
"dtsx",
|
|
19
|
+
"emit",
|
|
20
|
+
"generation",
|
|
21
|
+
"typescript",
|
|
22
|
+
"types",
|
|
23
|
+
"auto",
|
|
24
|
+
"stacks",
|
|
25
|
+
"webpack",
|
|
26
|
+
"plugin",
|
|
27
|
+
"package"
|
|
28
|
+
],
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"import": "./dist/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./*": {
|
|
35
|
+
"import": "./dist/*"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"module": "./dist/index.js",
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"files": [
|
|
41
|
+
"LICENSE.md",
|
|
42
|
+
"README.md",
|
|
43
|
+
"dist"
|
|
44
|
+
],
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "bun build.ts",
|
|
47
|
+
"prepublishOnly": "bun run build",
|
|
48
|
+
"test": "bun test",
|
|
49
|
+
"typecheck": "bun tsc --noEmit"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@stacksjs/dtsx": "0.9.10"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"webpack": "^4.0.0 || ^5.0.0"
|
|
56
|
+
}
|
|
57
|
+
}
|