vite-plugin-dts 1.7.3 → 2.0.0-beta.1

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
@@ -1,318 +1,326 @@
1
- <h1 align="center">vite-plugin-dts</h1>
2
-
3
- <p align="center">
4
- A vite plugin that generates declaration files (<code>*.d.ts</code>) from <code>.ts(x)</code> or <code>.vue</code> source files when using vite in <a href="https://vitejs.dev/guide/build.html#library-mode">library mode</a>.
5
- </p>
6
-
7
- <p align="center">
8
- <a href="https://www.npmjs.com/package/vite-plugin-dts">
9
- <img src="https://img.shields.io/npm/v/vite-plugin-dts?color=orange&label=" alt="version" />
10
- </a>
11
- </p>
12
-
13
- <p align="center">
14
- <strong>English</strong> | <a href="./README.zh-CN.md">中文</a>
15
- </p>
16
-
17
- <p align="center"><strong>Notice: </strong><code>skipDiagnostics</code> option default to <code>false</code> since 1.7.0.</p>
18
-
19
- <br />
20
-
21
- ## Install
22
-
23
- ```sh
24
- pnpm add vite-plugin-dts -D
25
- ```
26
-
27
- ## Usage
28
-
29
- In `vite.config.ts`:
30
-
31
- ```ts
32
- import { resolve } from 'path'
33
- import { defineConfig } from 'vite'
34
- import dts from 'vite-plugin-dts'
35
-
36
- export default defineConfig({
37
- build: {
38
- lib: {
39
- entry: resolve(__dirname, 'src/index.ts'),
40
- name: 'MyLib',
41
- formats: ['es'],
42
- fileName: 'my-lib'
43
- }
44
- },
45
- plugins: [dts()]
46
- })
47
- ```
48
-
49
- In your component:
50
-
51
- ```vue
52
- <template>
53
- <div></div>
54
- </template>
55
-
56
- <script lang="ts">
57
- // using defineComponent for inferring types
58
- import { defineComponent } from 'vue'
59
-
60
- export default defineComponent({
61
- name: 'Component'
62
- })
63
- </script>
64
- ```
65
-
66
- ```vue
67
- <script setup lang="ts">
68
- // Need to access the defineProps returned value to
69
- // infer types although you never use the props directly
70
- const props = defineProps<{
71
- color: 'blue' | 'red'
72
- }>()
73
- </script>
74
-
75
- <template>
76
- <div>{{ color }}</div>
77
- </template>
78
- ```
79
-
80
- ## FAQ
81
-
82
- Here are some FAQ's and solutions.
83
-
84
- ### Missing some declaration files after build (before `1.7.0`)
85
-
86
- By default `skipDiagnostics` option is `true`, which means that type diagnostic will be skipped during the build process (some projects may have diagnostic tools such as `vue-tsc`). If there are some files with type errors which interrupt the build process, these files will not be emitted (declaration files won't be generated).
87
-
88
- If your project doesn't use type diagnostic tools, you can set `skipDiagnostics: false` and `logDiagnostics: true` to turn on the diagnostic and log features of this plugin. It will help you check the type errors during build and log error information to the terminal.
89
-
90
- ### Take type error when using both `script` and `setup-script` in vue component
91
-
92
- This is usually caused by using `defineComponent` function in both `script` and `setup-script`. When `vue/compiler-sfc` compiles these files, the default export result from `script` gets merged with the parameter object of `defineComponent` from `setup-script`. This is incompatible with parameters and types returned from `defineComponent`, which results in a type error.
93
-
94
- Here is a simple [example](https://github.com/qmhc/vite-plugin-dts/blob/main/example/components/BothScripts.vue), you should remove the `defineComponent` which in `script` and export a native object directly.
95
-
96
- ### Take errors that unable to infer types from packages which under `node_modules`
97
-
98
- This is a exist issue when TypeScript inferring types from packages which under `node_modules` through soft links (pnpm), you can refer to this [issue](https://github.com/microsoft/TypeScript/issues/42873). Currently has a workaround that add `baseUrl` to your `tsconfig.json` and specify the `paths` for these packages:
99
-
100
- ```json
101
- {
102
- "compilerOptions": {
103
- "baseUrl": ".",
104
- "paths": {
105
- "third-lib": ["node_modules/third-lib"]
106
- }
107
- }
108
- }
109
- ```
110
-
111
- ## Options
112
-
113
- ```ts
114
- import type { ts, Diagnostic } from 'ts-morph'
115
-
116
- interface TransformWriteFile {
117
- filePath?: string
118
- content?: string
119
- }
120
-
121
- export interface PluginOptions {
122
- /**
123
- * Depends on the root directory
124
- *
125
- * Defaults base on your vite config root options
126
- */
127
- root?: string
128
-
129
- /**
130
- * Declaration files output directory
131
- *
132
- * Can be specified a array to output to multiple directories
133
- *
134
- * Defaults base on your vite config output options
135
- */
136
- outputDir?: string | string[]
137
-
138
- /**
139
- * Manually set the root path of the entry files
140
- *
141
- * The output path of each file will be caculated base on it
142
- *
143
- * Defaults is the smallest public path for all files
144
- */
145
- entryRoot?: string
146
-
147
- /**
148
- * Project init compilerOptions using by ts-morph
149
- *
150
- * @default null
151
- */
152
- compilerOptions?: ts.CompilerOptions | null
153
-
154
- /**
155
- * Project init tsconfig.json file path by ts-morph
156
- *
157
- * Plugin also resolve incldue and exclude files from tsconfig.json
158
- *
159
- * @default 'tsconfig.json'
160
- */
161
- tsConfigFilePath?: string
162
-
163
- /**
164
- * Set which paths should exclude when transform aliases
165
- *
166
- * If it's regexp, it will test the original import path directly
167
- *
168
- * @default []
169
- */
170
- aliasesExclude?: (string | RegExp)[]
171
-
172
- /**
173
- * Whether transform file name '.vue.d.ts' to '.d.ts'
174
- *
175
- * @default false
176
- */
177
- cleanVueFileName?: boolean
178
-
179
- /**
180
- * Whether transform dynamic import to static
181
- *
182
- * Force true when `rollupTypes` is effective
183
- *
184
- * eg. 'import('vue').DefineComponent' to 'import { DefineComponent } from "vue"'
185
- *
186
- * @default false
187
- */
188
- staticImport?: boolean
189
-
190
- /**
191
- * Manual set include glob
192
- *
193
- * Defaults base on your tsconfig.json include option
194
- */
195
- include?: string | string[]
196
-
197
- /**
198
- * Manual set exclude glob
199
- *
200
- * Defaults base on your tsconfig.json exclude option, be 'node_modules/**' when empty
201
- */
202
- exclude?: string | string[]
203
-
204
- /**
205
- * Do not emit if content of file only includes 'export {}'
206
- *
207
- * @default true
208
- */
209
- clearPureImport?: boolean
210
-
211
- /**
212
- * Whether generate types entry file
213
- *
214
- * When true will from package.json types field if exists or `${outputDir}/index.d.ts`
215
- *
216
- * Force true when `rollupTypes` is effective
217
- *
218
- * @default false
219
- */
220
- insertTypesEntry?: boolean
221
-
222
- /**
223
- * Set to rollup declaration files after emit
224
- *
225
- * Power by `@microsoft/api-extractor`, it will start a new program which takes some time
226
- *
227
- * @default false
228
- */
229
- rollupTypes?: boolean
230
-
231
- /**
232
- * Whether copy .d.ts source files into outputDir
233
- *
234
- * @default true
235
- */
236
- copyDtsFiles?: boolean
237
-
238
- /**
239
- * Whether emit nothing when has any diagnostic
240
- *
241
- * @default false
242
- */
243
- noEmitOnError?: boolean
244
-
245
- /**
246
- * Whether skip typescript diagnostics
247
- *
248
- * Skip type diagnostics means that type errors will not interrupt the build process
249
- *
250
- * But for the source files with type errors will not be emitted
251
- *
252
- * @default false
253
- */
254
- skipDiagnostics?: boolean
255
-
256
- /**
257
- * Whether log diagnostic informations
258
- *
259
- * Not effective when `skipDiagnostics` is true
260
- *
261
- * @deprecated
262
- * @default false
263
- */
264
- logDiagnostics?: boolean
265
-
266
- /**
267
- * Customize typescript lib folder path
268
- *
269
- * Should pass a relative path to root or a absolute path
270
- *
271
- * @default undefined
272
- */
273
- libFolderPath?: string
274
-
275
- /**
276
- * After emit diagnostic hook
277
- *
278
- * According to the length to judge whether there is any type error
279
- *
280
- * @default () => {}
281
- */
282
- afterDiagnostic?: (diagnostics: Diagnostic[]) => void | Promise<void>
283
-
284
- /**
285
- * Before declaration file be writed hook
286
- *
287
- * You can transform declaration file-path and content through it
288
- *
289
- * The file will be skipped when return exact false
290
- *
291
- * @default () => {}
292
- */
293
- beforeWriteFile?: (filePath: string, content: string) => void | false | TransformWriteFile
294
-
295
- /**
296
- * After build hook
297
- *
298
- * It wil be called after all declaration files are written
299
- *
300
- * @default () => {}
301
- */
302
- afterBuild?: () => void | Promise<void>
303
- }
304
- ```
305
-
306
- ## Example
307
-
308
- Clone and run the following script:
309
-
310
- ```sh
311
- pnpm run test:ts
312
- ```
313
-
314
- Then check `examples/ts/types`.
315
-
316
- ## License
317
-
318
- MIT License.
1
+ <h1 align="center">vite-plugin-dts</h1>
2
+
3
+ <p align="center">
4
+ A vite plugin that generates declaration files (<code>*.d.ts</code>) from <code>.ts(x)</code> or <code>.vue</code> source files when using vite in <a href="https://vitejs.dev/guide/build.html#library-mode">library mode</a>.
5
+ </p>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/vite-plugin-dts">
9
+ <img src="https://img.shields.io/npm/v/vite-plugin-dts?color=orange&label=" alt="version" />
10
+ </a>
11
+ </p>
12
+
13
+ <p align="center">
14
+ <strong>English</strong> | <a href="./README.zh-CN.md">中文</a>
15
+ </p>
16
+
17
+ <p align="center"><strong>Notice: </strong><code>skipDiagnostics</code> option default to <code>false</code> since 1.7.0.</p>
18
+
19
+ <br />
20
+
21
+ ## Install
22
+
23
+ ```sh
24
+ pnpm add vite-plugin-dts -D
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ In `vite.config.ts`:
30
+
31
+ ```ts
32
+ import { resolve } from 'path'
33
+ import { defineConfig } from 'vite'
34
+ import dts from 'vite-plugin-dts'
35
+
36
+ export default defineConfig({
37
+ build: {
38
+ lib: {
39
+ entry: resolve(__dirname, 'src/index.ts'),
40
+ name: 'MyLib',
41
+ formats: ['es'],
42
+ fileName: 'my-lib'
43
+ }
44
+ },
45
+ plugins: [dts()]
46
+ })
47
+ ```
48
+
49
+ In your component:
50
+
51
+ ```vue
52
+ <template>
53
+ <div></div>
54
+ </template>
55
+
56
+ <script lang="ts">
57
+ // using defineComponent for inferring types
58
+ import { defineComponent } from 'vue'
59
+
60
+ export default defineComponent({
61
+ name: 'Component'
62
+ })
63
+ </script>
64
+ ```
65
+
66
+ ```vue
67
+ <script setup lang="ts">
68
+ // Need to access the defineProps returned value to
69
+ // infer types although you never use the props directly
70
+ const props = defineProps<{
71
+ color: 'blue' | 'red'
72
+ }>()
73
+ </script>
74
+
75
+ <template>
76
+ <div>{{ color }}</div>
77
+ </template>
78
+ ```
79
+
80
+ ## FAQ
81
+
82
+ Here are some FAQ's and solutions.
83
+
84
+ ### Missing some declaration files after build (before `1.7.0`)
85
+
86
+ By default `skipDiagnostics` option is `true`, which means that type diagnostic will be skipped during the build process (some projects may have diagnostic tools such as `vue-tsc`). If there are some files with type errors which interrupt the build process, these files will not be emitted (declaration files won't be generated).
87
+
88
+ If your project doesn't use type diagnostic tools, you can set `skipDiagnostics: false` and `logDiagnostics: true` to turn on the diagnostic and log features of this plugin. It will help you check the type errors during build and log error information to the terminal.
89
+
90
+ ### Take type error when using both `script` and `setup-script` in vue component
91
+
92
+ This is usually caused by using `defineComponent` function in both `script` and `setup-script`. When `vue/compiler-sfc` compiles these files, the default export result from `script` gets merged with the parameter object of `defineComponent` from `setup-script`. This is incompatible with parameters and types returned from `defineComponent`, which results in a type error.
93
+
94
+ Here is a simple [example](https://github.com/qmhc/vite-plugin-dts/blob/main/example/components/BothScripts.vue), you should remove the `defineComponent` which in `script` and export a native object directly.
95
+
96
+ ### Take errors that unable to infer types from packages which under `node_modules`
97
+
98
+ This is a exist issue when TypeScript inferring types from packages which under `node_modules` through soft links (pnpm), you can refer to this [issue](https://github.com/microsoft/TypeScript/issues/42873). Currently has a workaround that add `baseUrl` to your `tsconfig.json` and specify the `paths` for these packages:
99
+
100
+ ```json
101
+ {
102
+ "compilerOptions": {
103
+ "baseUrl": ".",
104
+ "paths": {
105
+ "third-lib": ["node_modules/third-lib"]
106
+ }
107
+ }
108
+ }
109
+ ```
110
+
111
+ ## Options
112
+
113
+ ```ts
114
+ import type { ts, Diagnostic } from 'ts-morph'
115
+
116
+ interface TransformWriteFile {
117
+ filePath?: string
118
+ content?: string
119
+ }
120
+
121
+ export interface PluginOptions {
122
+ /**
123
+ * Depends on the root directory
124
+ *
125
+ * Defaults base on your vite config root options
126
+ */
127
+ root?: string
128
+
129
+ /**
130
+ * Declaration files output directory
131
+ *
132
+ * Can be specified a array to output to multiple directories
133
+ *
134
+ * Defaults base on your vite config output options
135
+ */
136
+ outputDir?: string | string[]
137
+
138
+ /**
139
+ * Manually set the root path of the entry files
140
+ *
141
+ * The output path of each file will be caculated base on it
142
+ *
143
+ * Defaults is the smallest public path for all files
144
+ */
145
+ entryRoot?: string
146
+
147
+ /**
148
+ * Project init compilerOptions using by ts-morph
149
+ *
150
+ * @default null
151
+ */
152
+ compilerOptions?: ts.CompilerOptions | null
153
+
154
+ /**
155
+ * Project init tsconfig.json file path by ts-morph
156
+ *
157
+ * Plugin also resolve incldue and exclude files from tsconfig.json
158
+ *
159
+ * @default 'tsconfig.json'
160
+ */
161
+ tsConfigFilePath?: string
162
+
163
+ /**
164
+ * Set which paths should exclude when transform aliases
165
+ *
166
+ * If it's regexp, it will test the original import path directly
167
+ *
168
+ * @default []
169
+ */
170
+ aliasesExclude?: (string | RegExp)[]
171
+
172
+ /**
173
+ * Whether transform file name '.vue.d.ts' to '.d.ts'
174
+ *
175
+ * @default false
176
+ */
177
+ cleanVueFileName?: boolean
178
+
179
+ /**
180
+ * Whether transform dynamic import to static
181
+ *
182
+ * Force true when `rollupTypes` is effective
183
+ *
184
+ * eg. 'import('vue').DefineComponent' to 'import { DefineComponent } from "vue"'
185
+ *
186
+ * @default false
187
+ */
188
+ staticImport?: boolean
189
+
190
+ /**
191
+ * Manual set include glob
192
+ *
193
+ * Defaults base on your tsconfig.json include option
194
+ */
195
+ include?: string | string[]
196
+
197
+ /**
198
+ * Manual set exclude glob
199
+ *
200
+ * Defaults base on your tsconfig.json exclude option, be 'node_modules/**' when empty
201
+ */
202
+ exclude?: string | string[]
203
+
204
+ /**
205
+ * Do not emit if content of file only includes 'export {}'
206
+ *
207
+ * @default true
208
+ */
209
+ clearPureImport?: boolean
210
+
211
+ /**
212
+ * Whether generate types entry file
213
+ *
214
+ * When true will from package.json types field if exists or `${outputDir}/index.d.ts`
215
+ *
216
+ * Force true when `rollupTypes` is effective
217
+ *
218
+ * @default false
219
+ */
220
+ insertTypesEntry?: boolean
221
+
222
+ /**
223
+ * Set to rollup declaration files after emit
224
+ *
225
+ * Power by `@microsoft/api-extractor`, it will start a new program which takes some time
226
+ *
227
+ * @default false
228
+ */
229
+ rollupTypes?: boolean
230
+
231
+ /**
232
+ * Whether copy .d.ts source files into outputDir
233
+ *
234
+ * @default true
235
+ */
236
+ copyDtsFiles?: boolean
237
+
238
+ /**
239
+ * Whether emit nothing when has any diagnostic
240
+ *
241
+ * @default false
242
+ */
243
+ noEmitOnError?: boolean
244
+
245
+ /**
246
+ * Whether skip typescript diagnostics
247
+ *
248
+ * Skip type diagnostics means that type errors will not interrupt the build process
249
+ *
250
+ * But for the source files with type errors will not be emitted
251
+ *
252
+ * @default false
253
+ */
254
+ skipDiagnostics?: boolean
255
+
256
+ /**
257
+ * Whether log diagnostic informations
258
+ *
259
+ * Not effective when `skipDiagnostics` is true
260
+ *
261
+ * @deprecated
262
+ * @default false
263
+ */
264
+ logDiagnostics?: boolean
265
+
266
+ /**
267
+ * Customize typescript lib folder path
268
+ *
269
+ * Should pass a relative path to root or a absolute path
270
+ *
271
+ * @default undefined
272
+ */
273
+ libFolderPath?: string
274
+
275
+ /**
276
+ * After emit diagnostic hook
277
+ *
278
+ * According to the length to judge whether there is any type error
279
+ *
280
+ * @default () => {}
281
+ */
282
+ afterDiagnostic?: (diagnostics: Diagnostic[]) => void | Promise<void>
283
+
284
+ /**
285
+ * Before declaration file be writed hook
286
+ *
287
+ * You can transform declaration file-path and content through it
288
+ *
289
+ * The file will be skipped when return exact false
290
+ *
291
+ * @default () => {}
292
+ */
293
+ beforeWriteFile?: (filePath: string, content: string) => void | false | TransformWriteFile
294
+
295
+ /**
296
+ * After build hook
297
+ *
298
+ * It wil be called after all declaration files are written
299
+ *
300
+ * @default () => {}
301
+ */
302
+ afterBuild?: () => void | Promise<void>
303
+ }
304
+ ```
305
+
306
+ ## Contributors
307
+
308
+ Thanks for all their contributions!
309
+
310
+ <a href="https://github.com/qmhc/vite-plugin-dts/graphs/contributors">
311
+ <img src="https://contrib.rocks/image?repo=qmhc/vite-plugin-dts" />
312
+ </a>
313
+
314
+ ## Example
315
+
316
+ Clone and run the following script:
317
+
318
+ ```sh
319
+ pnpm run test:ts
320
+ ```
321
+
322
+ Then check `examples/ts/types`.
323
+
324
+ ## License
325
+
326
+ MIT License.
package/README.zh-CN.md CHANGED
@@ -302,6 +302,14 @@ export interface PluginOptions {
302
302
  }
303
303
  ```
304
304
 
305
+ ## 贡献者
306
+
307
+ 感谢他们的所做的一切贡献!
308
+
309
+ <a href="https://github.com/qmhc/vite-plugin-dts/graphs/contributors">
310
+ <img src="https://contrib.rocks/image?repo=qmhc/vite-plugin-dts" />
311
+ </a>
312
+
305
313
  ## 示例
306
314
 
307
315
  克隆项目然后执行下列命令:
package/dist/index.cjs CHANGED
@@ -12,6 +12,8 @@ const typescript = require('typescript');
12
12
  const pluginutils = require('@rollup/pluginutils');
13
13
  const node_fs = require('node:fs');
14
14
  const node_module = require('node:module');
15
+ const parser = require('@babel/parser');
16
+ const MagicString = require('magic-string');
15
17
  const apiExtractor = require('@microsoft/api-extractor');
16
18
  const Collector_js = require('@microsoft/api-extractor/lib/collector/Collector.js');
17
19
  const MessageRouter_js = require('@microsoft/api-extractor/lib/collector/MessageRouter.js');
@@ -240,8 +242,6 @@ function transferSetupPosition(content) {
240
242
  return content;
241
243
  }
242
244
 
243
- const exportDefaultRE = /export\s+default/;
244
- const exportDefaultClassRE = /(?:(?:^|\n|;)\s*)export\s+default\s+class\s+([\w$]+)/;
245
245
  const noScriptContent = "import { defineComponent } from 'vue'\nexport default defineComponent({})";
246
246
  const _require = node_module.createRequire((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('index.cjs', document.baseURI).href)));
247
247
  let index = 1;
@@ -299,58 +299,177 @@ function setCompileRoot(root) {
299
299
  }
300
300
  }
301
301
  function parseCode(code) {
302
- const { parse } = requireCompiler();
302
+ const { parse: parseVueCode } = requireCompiler();
303
303
  let descriptor;
304
304
  if (isVue3()) {
305
- descriptor = parse(code).descriptor;
305
+ descriptor = parseVueCode(code).descriptor;
306
306
  } else {
307
- descriptor = parse({ source: code });
307
+ descriptor = parseVueCode({ source: code });
308
308
  }
309
309
  return descriptor;
310
310
  }
311
+ function transformJsToTs(script) {
312
+ if (!script)
313
+ return script;
314
+ const lang = !script.lang || script.lang === "js" ? "ts" : script.lang === "jsx" ? "tsx" : script.lang;
315
+ return { ...script, lang };
316
+ }
317
+ function preprocessVueCode(code, setupScript) {
318
+ const plugins = ["typescript", "decorators-legacy", "jsx"];
319
+ const scriptAst = parser.parse(code, { sourceType: "module", plugins }).program.body;
320
+ const source = new MagicString(code);
321
+ let propsTypeName;
322
+ let propsTypeLiteral;
323
+ if (setupScript) {
324
+ let processDefineProps = function(node) {
325
+ if (node.type === "CallExpression" && node.callee.type === "Identifier") {
326
+ if (node.callee.name === "defineProps") {
327
+ defineProps = node;
328
+ return true;
329
+ } else if (node.callee.name === "withDefaults") {
330
+ const propsDef = node.arguments[0];
331
+ if (propsDef.type === "CallExpression" && propsDef.callee.type === "Identifier" && propsDef.callee.name === "defineProps") {
332
+ defineProps = propsDef;
333
+ return true;
334
+ }
335
+ }
336
+ }
337
+ return false;
338
+ };
339
+ const setupAst = parser.parse(setupScript.content, { sourceType: "module", plugins }).program.body;
340
+ let defineProps;
341
+ for (const node of setupAst) {
342
+ if (node.type === "ExpressionStatement") {
343
+ processDefineProps(node.expression);
344
+ } else if (node.type === "VariableDeclaration" && !node.declare) {
345
+ for (const decl of node.declarations) {
346
+ if (decl.init && processDefineProps(decl.init)) {
347
+ break;
348
+ }
349
+ }
350
+ }
351
+ if (defineProps) {
352
+ const type = defineProps.typeParameters?.params[0];
353
+ if (type && type.type === "TSTypeReference" && type.typeName.type === "Identifier") {
354
+ propsTypeName = type.typeName.name;
355
+ } else if (type?.type === "TSTypeLiteral") {
356
+ propsTypeName = "__DTS_Props__";
357
+ propsTypeLiteral = setupScript.content.substring(type.start, type.end);
358
+ }
359
+ break;
360
+ }
361
+ }
362
+ }
363
+ for (const node of scriptAst) {
364
+ if (node.type === "ExportDefaultDeclaration") {
365
+ let options;
366
+ if (node.declaration.type === "ObjectExpression") {
367
+ options = node.declaration.properties;
368
+ } else if (node.declaration.type === "CallExpression" && node.declaration.arguments[0].type === "ObjectExpression") {
369
+ options = node.declaration.arguments[0].properties;
370
+ }
371
+ if (options) {
372
+ for (const option of options) {
373
+ if (propsTypeName && option.type === "ObjectProperty" && option.key.type === "Identifier" && option.key.name === "props" && option.value.type === "ObjectExpression") {
374
+ for (const prop of option.value.properties) {
375
+ if (prop.type === "ObjectProperty" && prop.key.type === "Identifier") {
376
+ if (prop.value.type === "ObjectExpression") {
377
+ for (const propDef of prop.value.properties) {
378
+ if (propDef.type === "ObjectProperty" && propDef.key.type === "Identifier" && propDef.key.name === "type") {
379
+ source.prependLeft(
380
+ propDef.end,
381
+ ` as unknown as __PropType<${propsTypeName}['${prop.key.name}']>`
382
+ );
383
+ }
384
+ }
385
+ } else {
386
+ source.prependLeft(
387
+ prop.end,
388
+ ` as unknown as __PropType<${propsTypeName}['${prop.key.name}']>`
389
+ );
390
+ }
391
+ }
392
+ }
393
+ }
394
+ if (option.type === "ObjectProperty" && option.key.type === "Identifier" && option.key.name === "components") {
395
+ source.remove(option.start, option.end);
396
+ }
397
+ if (option.type === "ObjectMethod" && option.key.type === "Identifier" && option.key.name === "setup") {
398
+ let exposed;
399
+ let returned;
400
+ for (const node2 of option.body.body) {
401
+ if (!exposed && node2.type === "ExpressionStatement" && node2.expression.type === "CallExpression" && node2.expression.callee.type === "Identifier" && node2.expression.callee.name === "expose") {
402
+ exposed = node2.expression.arguments[0];
403
+ continue;
404
+ }
405
+ if (node2.type === "ReturnStatement") {
406
+ returned = node2;
407
+ break;
408
+ }
409
+ }
410
+ const newReturned = exposed && exposed.type === "ObjectExpression" ? `return ${code.substring(exposed.start, exposed.end)}` : setupScript ? "return {}" : "";
411
+ if (newReturned) {
412
+ if (returned) {
413
+ source.overwrite(returned.start, returned.end, newReturned);
414
+ } else if (option.body.body.length) {
415
+ source.appendRight(option.body.body.at(-1).end, `
416
+ ${newReturned}
417
+ `);
418
+ }
419
+ }
420
+ }
421
+ }
422
+ }
423
+ break;
424
+ }
425
+ }
426
+ if (propsTypeName) {
427
+ if (propsTypeLiteral) {
428
+ source.prepend(`
429
+ type ${propsTypeName} = ${propsTypeLiteral}
430
+
431
+ `);
432
+ }
433
+ source.prepend("import type { PropType as __PropType } from 'vue'\n");
434
+ }
435
+ return source.toString();
436
+ }
311
437
  function compileVueCode(code) {
312
438
  const { compileScript, rewriteDefault } = requireCompiler();
313
439
  const descriptor = parseCode(code);
314
440
  const { script, scriptSetup } = descriptor;
315
- let content = null;
316
- let ext = null;
441
+ let error;
442
+ let content;
443
+ let ext = "js";
317
444
  if (script || scriptSetup) {
445
+ const compiled = compileScript(
446
+ {
447
+ ...descriptor,
448
+ script: transformJsToTs(script),
449
+ scriptSetup: transformJsToTs(scriptSetup),
450
+ cssVars: []
451
+ },
452
+ { id: `${index++}` }
453
+ );
454
+ try {
455
+ content = preprocessVueCode(compiled.content, scriptSetup);
456
+ } catch (e) {
457
+ error = e;
458
+ content = compiled.content;
459
+ }
460
+ content = rewriteDefault(content, "_sfc_main", ["typescript", "decorators-legacy"]);
318
461
  if (scriptSetup) {
319
- const compiled = compileScript(descriptor, {
320
- id: `${index++}`
321
- });
322
- const classMatch = compiled.content.match(exportDefaultClassRE);
323
- const plugins = scriptSetup.lang === "ts" ? ["typescript", "decorators-legacy"] : void 0;
324
- if (classMatch) {
325
- content = compiled.content.replace(exportDefaultClassRE, "\nclass $1") + `
326
- const _sfc_main = ${classMatch[1]}`;
327
- if (exportDefaultRE.test(content)) {
328
- content = rewriteDefault(compiled.content, "_sfc_main", plugins);
329
- }
330
- } else {
331
- content = rewriteDefault(compiled.content, "_sfc_main", plugins);
332
- }
333
462
  content = transferSetupPosition(content);
334
- content = content.replace(/(const __returned__\s?=\s?\{[\s\S]+?)(props)(\s?\})/, "$1props: props as any$3").replace(
335
- /(const __returned__\s?=\s?\{[\s\S]+?)(props,)([\s\S]+?)/,
336
- "$1props: props as any,$3"
337
- );
338
- content += "\nexport default _sfc_main\n";
339
463
  ext = scriptSetup.lang || "js";
340
464
  } else if (script && script.content) {
341
- content = rewriteDefault(
342
- script.content,
343
- "_sfc_main",
344
- script.lang === "ts" ? ["typescript", "decorators-legacy"] : void 0
345
- );
346
- content += "\nexport default _sfc_main\n";
347
465
  ext = script.lang || "js";
348
466
  }
467
+ content += "\nexport default _sfc_main\n";
349
468
  } else {
350
469
  content = noScriptContent;
351
470
  ext = "ts";
352
471
  }
353
- return { content, ext };
472
+ return { error, content, ext };
354
473
  }
355
474
 
356
475
  const dtsRE$1 = /\.d\.tsx?$/;
@@ -488,6 +607,7 @@ function dtsPlugin(options = {}) {
488
607
  const sourceDtsFiles = /* @__PURE__ */ new Set();
489
608
  let hasJsVue = false;
490
609
  let allowJs = false;
610
+ let transformError = false;
491
611
  return {
492
612
  name: "vite:dts",
493
613
  apply: "build",
@@ -568,11 +688,12 @@ ${kolorist.cyan(
568
688
  rootDir: compilerOptions.rootDir || root,
569
689
  noEmitOnError,
570
690
  outDir: ".",
571
- declarationDir: null,
691
+ declarationDir: void 0,
572
692
  noUnusedParameters: false,
573
693
  declaration: true,
574
694
  noEmit: false,
575
- emitDeclarationOnly: true
695
+ emitDeclarationOnly: true,
696
+ composite: false
576
697
  }),
577
698
  tsConfigFilePath: tsConfigPath,
578
699
  skipAddingFilesFromTsConfig: true,
@@ -615,7 +736,19 @@ ${kolorist.cyan(
615
736
  return null;
616
737
  }
617
738
  if (vueRE.test(id)) {
618
- const { content, ext } = compileVueCode(code);
739
+ const { error, content, ext } = compileVueCode(code);
740
+ if (!transformError && error) {
741
+ logger.error(
742
+ kolorist.red(
743
+ `
744
+ ${kolorist.cyan(
745
+ "[vite:dts]"
746
+ )} A error occurred when transform code, maybe there are some inertnal bugs.
747
+ `
748
+ )
749
+ );
750
+ transformError = true;
751
+ }
619
752
  if (content) {
620
753
  if (ext === "js" || ext === "jsx")
621
754
  hasJsVue = true;
package/dist/index.mjs CHANGED
@@ -17,6 +17,8 @@ import typescript from 'typescript';
17
17
  import { createFilter } from '@rollup/pluginutils';
18
18
  import { existsSync, readdirSync, lstatSync, rmdirSync } from 'node:fs';
19
19
  import { createRequire } from 'node:module';
20
+ import { parse } from '@babel/parser';
21
+ import MagicString from 'magic-string';
20
22
  import { ExtractorConfig, CompilerState } from '@microsoft/api-extractor';
21
23
  import { Collector } from '@microsoft/api-extractor/lib/collector/Collector.js';
22
24
  import { MessageRouter } from '@microsoft/api-extractor/lib/collector/MessageRouter.js';
@@ -245,8 +247,6 @@ function transferSetupPosition(content) {
245
247
  return content;
246
248
  }
247
249
 
248
- const exportDefaultRE = /export\s+default/;
249
- const exportDefaultClassRE = /(?:(?:^|\n|;)\s*)export\s+default\s+class\s+([\w$]+)/;
250
250
  const noScriptContent = "import { defineComponent } from 'vue'\nexport default defineComponent({})";
251
251
  const _require = createRequire(import.meta.url);
252
252
  let index = 1;
@@ -304,58 +304,177 @@ function setCompileRoot(root) {
304
304
  }
305
305
  }
306
306
  function parseCode(code) {
307
- const { parse } = requireCompiler();
307
+ const { parse: parseVueCode } = requireCompiler();
308
308
  let descriptor;
309
309
  if (isVue3()) {
310
- descriptor = parse(code).descriptor;
310
+ descriptor = parseVueCode(code).descriptor;
311
311
  } else {
312
- descriptor = parse({ source: code });
312
+ descriptor = parseVueCode({ source: code });
313
313
  }
314
314
  return descriptor;
315
315
  }
316
+ function transformJsToTs(script) {
317
+ if (!script)
318
+ return script;
319
+ const lang = !script.lang || script.lang === "js" ? "ts" : script.lang === "jsx" ? "tsx" : script.lang;
320
+ return { ...script, lang };
321
+ }
322
+ function preprocessVueCode(code, setupScript) {
323
+ const plugins = ["typescript", "decorators-legacy", "jsx"];
324
+ const scriptAst = parse(code, { sourceType: "module", plugins }).program.body;
325
+ const source = new MagicString(code);
326
+ let propsTypeName;
327
+ let propsTypeLiteral;
328
+ if (setupScript) {
329
+ let processDefineProps = function(node) {
330
+ if (node.type === "CallExpression" && node.callee.type === "Identifier") {
331
+ if (node.callee.name === "defineProps") {
332
+ defineProps = node;
333
+ return true;
334
+ } else if (node.callee.name === "withDefaults") {
335
+ const propsDef = node.arguments[0];
336
+ if (propsDef.type === "CallExpression" && propsDef.callee.type === "Identifier" && propsDef.callee.name === "defineProps") {
337
+ defineProps = propsDef;
338
+ return true;
339
+ }
340
+ }
341
+ }
342
+ return false;
343
+ };
344
+ const setupAst = parse(setupScript.content, { sourceType: "module", plugins }).program.body;
345
+ let defineProps;
346
+ for (const node of setupAst) {
347
+ if (node.type === "ExpressionStatement") {
348
+ processDefineProps(node.expression);
349
+ } else if (node.type === "VariableDeclaration" && !node.declare) {
350
+ for (const decl of node.declarations) {
351
+ if (decl.init && processDefineProps(decl.init)) {
352
+ break;
353
+ }
354
+ }
355
+ }
356
+ if (defineProps) {
357
+ const type = defineProps.typeParameters?.params[0];
358
+ if (type && type.type === "TSTypeReference" && type.typeName.type === "Identifier") {
359
+ propsTypeName = type.typeName.name;
360
+ } else if (type?.type === "TSTypeLiteral") {
361
+ propsTypeName = "__DTS_Props__";
362
+ propsTypeLiteral = setupScript.content.substring(type.start, type.end);
363
+ }
364
+ break;
365
+ }
366
+ }
367
+ }
368
+ for (const node of scriptAst) {
369
+ if (node.type === "ExportDefaultDeclaration") {
370
+ let options;
371
+ if (node.declaration.type === "ObjectExpression") {
372
+ options = node.declaration.properties;
373
+ } else if (node.declaration.type === "CallExpression" && node.declaration.arguments[0].type === "ObjectExpression") {
374
+ options = node.declaration.arguments[0].properties;
375
+ }
376
+ if (options) {
377
+ for (const option of options) {
378
+ if (propsTypeName && option.type === "ObjectProperty" && option.key.type === "Identifier" && option.key.name === "props" && option.value.type === "ObjectExpression") {
379
+ for (const prop of option.value.properties) {
380
+ if (prop.type === "ObjectProperty" && prop.key.type === "Identifier") {
381
+ if (prop.value.type === "ObjectExpression") {
382
+ for (const propDef of prop.value.properties) {
383
+ if (propDef.type === "ObjectProperty" && propDef.key.type === "Identifier" && propDef.key.name === "type") {
384
+ source.prependLeft(
385
+ propDef.end,
386
+ ` as unknown as __PropType<${propsTypeName}['${prop.key.name}']>`
387
+ );
388
+ }
389
+ }
390
+ } else {
391
+ source.prependLeft(
392
+ prop.end,
393
+ ` as unknown as __PropType<${propsTypeName}['${prop.key.name}']>`
394
+ );
395
+ }
396
+ }
397
+ }
398
+ }
399
+ if (option.type === "ObjectProperty" && option.key.type === "Identifier" && option.key.name === "components") {
400
+ source.remove(option.start, option.end);
401
+ }
402
+ if (option.type === "ObjectMethod" && option.key.type === "Identifier" && option.key.name === "setup") {
403
+ let exposed;
404
+ let returned;
405
+ for (const node2 of option.body.body) {
406
+ if (!exposed && node2.type === "ExpressionStatement" && node2.expression.type === "CallExpression" && node2.expression.callee.type === "Identifier" && node2.expression.callee.name === "expose") {
407
+ exposed = node2.expression.arguments[0];
408
+ continue;
409
+ }
410
+ if (node2.type === "ReturnStatement") {
411
+ returned = node2;
412
+ break;
413
+ }
414
+ }
415
+ const newReturned = exposed && exposed.type === "ObjectExpression" ? `return ${code.substring(exposed.start, exposed.end)}` : setupScript ? "return {}" : "";
416
+ if (newReturned) {
417
+ if (returned) {
418
+ source.overwrite(returned.start, returned.end, newReturned);
419
+ } else if (option.body.body.length) {
420
+ source.appendRight(option.body.body.at(-1).end, `
421
+ ${newReturned}
422
+ `);
423
+ }
424
+ }
425
+ }
426
+ }
427
+ }
428
+ break;
429
+ }
430
+ }
431
+ if (propsTypeName) {
432
+ if (propsTypeLiteral) {
433
+ source.prepend(`
434
+ type ${propsTypeName} = ${propsTypeLiteral}
435
+
436
+ `);
437
+ }
438
+ source.prepend("import type { PropType as __PropType } from 'vue'\n");
439
+ }
440
+ return source.toString();
441
+ }
316
442
  function compileVueCode(code) {
317
443
  const { compileScript, rewriteDefault } = requireCompiler();
318
444
  const descriptor = parseCode(code);
319
445
  const { script, scriptSetup } = descriptor;
320
- let content = null;
321
- let ext = null;
446
+ let error;
447
+ let content;
448
+ let ext = "js";
322
449
  if (script || scriptSetup) {
450
+ const compiled = compileScript(
451
+ {
452
+ ...descriptor,
453
+ script: transformJsToTs(script),
454
+ scriptSetup: transformJsToTs(scriptSetup),
455
+ cssVars: []
456
+ },
457
+ { id: `${index++}` }
458
+ );
459
+ try {
460
+ content = preprocessVueCode(compiled.content, scriptSetup);
461
+ } catch (e) {
462
+ error = e;
463
+ content = compiled.content;
464
+ }
465
+ content = rewriteDefault(content, "_sfc_main", ["typescript", "decorators-legacy"]);
323
466
  if (scriptSetup) {
324
- const compiled = compileScript(descriptor, {
325
- id: `${index++}`
326
- });
327
- const classMatch = compiled.content.match(exportDefaultClassRE);
328
- const plugins = scriptSetup.lang === "ts" ? ["typescript", "decorators-legacy"] : void 0;
329
- if (classMatch) {
330
- content = compiled.content.replace(exportDefaultClassRE, "\nclass $1") + `
331
- const _sfc_main = ${classMatch[1]}`;
332
- if (exportDefaultRE.test(content)) {
333
- content = rewriteDefault(compiled.content, "_sfc_main", plugins);
334
- }
335
- } else {
336
- content = rewriteDefault(compiled.content, "_sfc_main", plugins);
337
- }
338
467
  content = transferSetupPosition(content);
339
- content = content.replace(/(const __returned__\s?=\s?\{[\s\S]+?)(props)(\s?\})/, "$1props: props as any$3").replace(
340
- /(const __returned__\s?=\s?\{[\s\S]+?)(props,)([\s\S]+?)/,
341
- "$1props: props as any,$3"
342
- );
343
- content += "\nexport default _sfc_main\n";
344
468
  ext = scriptSetup.lang || "js";
345
469
  } else if (script && script.content) {
346
- content = rewriteDefault(
347
- script.content,
348
- "_sfc_main",
349
- script.lang === "ts" ? ["typescript", "decorators-legacy"] : void 0
350
- );
351
- content += "\nexport default _sfc_main\n";
352
470
  ext = script.lang || "js";
353
471
  }
472
+ content += "\nexport default _sfc_main\n";
354
473
  } else {
355
474
  content = noScriptContent;
356
475
  ext = "ts";
357
476
  }
358
- return { content, ext };
477
+ return { error, content, ext };
359
478
  }
360
479
 
361
480
  const dtsRE$1 = /\.d\.tsx?$/;
@@ -493,6 +612,7 @@ function dtsPlugin(options = {}) {
493
612
  const sourceDtsFiles = /* @__PURE__ */ new Set();
494
613
  let hasJsVue = false;
495
614
  let allowJs = false;
615
+ let transformError = false;
496
616
  return {
497
617
  name: "vite:dts",
498
618
  apply: "build",
@@ -573,11 +693,12 @@ ${cyan(
573
693
  rootDir: compilerOptions.rootDir || root,
574
694
  noEmitOnError,
575
695
  outDir: ".",
576
- declarationDir: null,
696
+ declarationDir: void 0,
577
697
  noUnusedParameters: false,
578
698
  declaration: true,
579
699
  noEmit: false,
580
- emitDeclarationOnly: true
700
+ emitDeclarationOnly: true,
701
+ composite: false
581
702
  }),
582
703
  tsConfigFilePath: tsConfigPath,
583
704
  skipAddingFilesFromTsConfig: true,
@@ -620,7 +741,19 @@ ${cyan(
620
741
  return null;
621
742
  }
622
743
  if (vueRE.test(id)) {
623
- const { content, ext } = compileVueCode(code);
744
+ const { error, content, ext } = compileVueCode(code);
745
+ if (!transformError && error) {
746
+ logger.error(
747
+ red(
748
+ `
749
+ ${cyan(
750
+ "[vite:dts]"
751
+ )} A error occurred when transform code, maybe there are some inertnal bugs.
752
+ `
753
+ )
754
+ );
755
+ transformError = true;
756
+ }
624
757
  if (content) {
625
758
  if (ext === "js" || ext === "jsx")
626
759
  hasJsVue = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-dts",
3
- "version": "1.7.3",
3
+ "version": "2.0.0-beta.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": "qmhc",
@@ -53,6 +53,7 @@
53
53
  "typescript"
54
54
  ],
55
55
  "dependencies": {
56
+ "@babel/parser": "^7.20.15",
56
57
  "@microsoft/api-extractor": "^7.33.5",
57
58
  "@rollup/pluginutils": "^5.0.2",
58
59
  "@rushstack/node-core-library": "^3.53.2",
@@ -60,9 +61,11 @@
60
61
  "fast-glob": "^3.2.12",
61
62
  "fs-extra": "^10.1.0",
62
63
  "kolorist": "^1.6.0",
64
+ "magic-string": "^0.29.0",
63
65
  "ts-morph": "17.0.1"
64
66
  },
65
67
  "devDependencies": {
68
+ "@babel/types": "^7.20.7",
66
69
  "@commitlint/cli": "^17.1.2",
67
70
  "@commitlint/config-conventional": "^17.1.0",
68
71
  "@types/debug": "^4.1.7",