detype 0.6.2 → 1.0.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 +8 -3
- package/dist/cli.js +108 -57
- package/dist/index.d.ts +4 -1
- package/dist/index.js +61 -12
- package/package.json +18 -17
package/README.md
CHANGED
|
@@ -132,17 +132,17 @@ function transformFile(
|
|
|
132
132
|
): Promise<void>;
|
|
133
133
|
|
|
134
134
|
// Remove magic comments without performing the TS to JS transform
|
|
135
|
-
export function removeMagicComments(
|
|
135
|
+
export async function removeMagicComments(
|
|
136
136
|
// Source code
|
|
137
137
|
code: string,
|
|
138
138
|
// File name for the source
|
|
139
139
|
fileName: string,
|
|
140
140
|
// Options to pass to prettier
|
|
141
141
|
prettierOptions?: PrettierOptions | null,
|
|
142
|
-
): string
|
|
142
|
+
): Promise<string>;
|
|
143
143
|
|
|
144
144
|
// Remove magic comments from the input file and write the output to another file
|
|
145
|
-
export function removeMagicCommentsFromFile(
|
|
145
|
+
export async function removeMagicCommentsFromFile(
|
|
146
146
|
inputFileName: string,
|
|
147
147
|
outputFileName: string,
|
|
148
148
|
): Promise<void>;
|
|
@@ -150,6 +150,11 @@ export function removeMagicCommentsFromFile(
|
|
|
150
150
|
|
|
151
151
|
## Change log
|
|
152
152
|
|
|
153
|
+
### 1.0
|
|
154
|
+
|
|
155
|
+
- BREAKING CHANGE: `removeMagicComments` is now async due to Prettier's API change
|
|
156
|
+
- feat: support transform defineProps's and defineEmits's types to parameters ([PR by Dunqing](https://github.com/cyco130/detype/pull/11))
|
|
157
|
+
|
|
153
158
|
### 0.6
|
|
154
159
|
|
|
155
160
|
- feature: Option to remove @ts-ignore and @ts-expect-error comments
|
package/dist/cli.js
CHANGED
|
@@ -14,30 +14,55 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
14
14
|
return to;
|
|
15
15
|
};
|
|
16
16
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
17
21
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
18
22
|
mod
|
|
19
23
|
));
|
|
20
24
|
|
|
21
25
|
// src/cli-lib.ts
|
|
22
|
-
var
|
|
23
|
-
var
|
|
26
|
+
var import_node_fs2 = __toESM(require("fs"));
|
|
27
|
+
var import_node_path = __toESM(require("path"));
|
|
24
28
|
|
|
25
29
|
// src/transformFile.ts
|
|
26
|
-
var
|
|
30
|
+
var import_node_fs = __toESM(require("fs"));
|
|
27
31
|
|
|
28
32
|
// src/transform.ts
|
|
29
33
|
var import_core = require("@babel/core");
|
|
30
34
|
var import_prettier = require("prettier");
|
|
31
35
|
var import_compiler_sfc = require("@vuedx/compiler-sfc");
|
|
36
|
+
var import_compiler_sfc2 = require("@vue/compiler-sfc");
|
|
32
37
|
var import_template_ast_types = require("@vuedx/template-ast-types");
|
|
33
38
|
var import_preset_typescript = __toESM(require("@babel/preset-typescript"));
|
|
34
39
|
var import_string_prototype = require("string.prototype.replaceall");
|
|
35
40
|
(0, import_string_prototype.shim)();
|
|
41
|
+
function getDefinePropsObject(content) {
|
|
42
|
+
const matched = /\sprops:\s*\{/m.exec(content);
|
|
43
|
+
if (matched) {
|
|
44
|
+
const startContentIndex = matched.index + matched[0].length - 1;
|
|
45
|
+
let leftBracketCount = 1;
|
|
46
|
+
let endContentIndex = startContentIndex + 1;
|
|
47
|
+
while (leftBracketCount) {
|
|
48
|
+
if (content.charAt(endContentIndex) === "{") {
|
|
49
|
+
leftBracketCount++;
|
|
50
|
+
} else if (content.charAt(endContentIndex) === "}") {
|
|
51
|
+
leftBracketCount--;
|
|
52
|
+
}
|
|
53
|
+
endContentIndex++;
|
|
54
|
+
}
|
|
55
|
+
return content.substring(startContentIndex, endContentIndex);
|
|
56
|
+
}
|
|
57
|
+
return "";
|
|
58
|
+
}
|
|
36
59
|
async function transform(code, fileName, options = {}) {
|
|
37
|
-
var _a, _b, _c, _d;
|
|
60
|
+
var _a, _b, _c, _d, _e;
|
|
38
61
|
const { prettierOptions, ...removeTypeOptions } = options;
|
|
39
62
|
const originalCode = code;
|
|
40
63
|
const originalFileName = fileName;
|
|
64
|
+
let propsContent = "";
|
|
65
|
+
let emitsContent = "";
|
|
41
66
|
code = code.replaceAll("\r\n", "\n");
|
|
42
67
|
if (fileName.endsWith(".vue")) {
|
|
43
68
|
const parsedVue = (0, import_compiler_sfc.parse)(code);
|
|
@@ -45,6 +70,19 @@ async function transform(code, fileName, options = {}) {
|
|
|
45
70
|
return originalCode;
|
|
46
71
|
}
|
|
47
72
|
let { script: script1, scriptSetup: script2 } = parsedVue.descriptor;
|
|
73
|
+
const isContainsDefinePropsType = script2 == null ? void 0 : script2.content.match(/defineProps\s*</m);
|
|
74
|
+
const isContainsDefineEmitType = script2 == null ? void 0 : script2.content.match(/defineEmits\s*</m);
|
|
75
|
+
if (isContainsDefinePropsType || isContainsDefineEmitType) {
|
|
76
|
+
const { content } = (0, import_compiler_sfc2.compileScript)(parsedVue.descriptor, {
|
|
77
|
+
id: "xxxxxxx"
|
|
78
|
+
});
|
|
79
|
+
if (isContainsDefinePropsType) {
|
|
80
|
+
propsContent = getDefinePropsObject(content);
|
|
81
|
+
}
|
|
82
|
+
if (isContainsDefineEmitType) {
|
|
83
|
+
emitsContent = ((_c = content.match(/\semits:\s(\[.*\]?)/m)) == null ? void 0 : _c[1]) || "";
|
|
84
|
+
}
|
|
85
|
+
}
|
|
48
86
|
if (script1 && script2 && script1.loc.start.offset < script2.loc.start.offset) {
|
|
49
87
|
[script2, script1] = [script1, script2];
|
|
50
88
|
}
|
|
@@ -52,20 +90,26 @@ async function transform(code, fileName, options = {}) {
|
|
|
52
90
|
code,
|
|
53
91
|
fileName,
|
|
54
92
|
script1,
|
|
55
|
-
(
|
|
93
|
+
(_d = parsedVue.descriptor.template) == null ? void 0 : _d.ast,
|
|
56
94
|
removeTypeOptions
|
|
57
95
|
);
|
|
58
96
|
code = await removeTypesFromVueSfcScript(
|
|
59
97
|
code,
|
|
60
98
|
fileName,
|
|
61
99
|
script2,
|
|
62
|
-
(
|
|
100
|
+
(_e = parsedVue.descriptor.template) == null ? void 0 : _e.ast,
|
|
63
101
|
removeTypeOptions
|
|
64
102
|
);
|
|
65
103
|
} else {
|
|
66
104
|
code = await removeTypes(code, fileName, removeTypeOptions);
|
|
67
105
|
}
|
|
68
|
-
|
|
106
|
+
if (propsContent) {
|
|
107
|
+
code = code.replace("defineProps(", (str) => `${str}${propsContent}`);
|
|
108
|
+
}
|
|
109
|
+
if (emitsContent) {
|
|
110
|
+
code = code.replace("defineEmits(", (str) => `${str}${emitsContent}`);
|
|
111
|
+
}
|
|
112
|
+
code = await (0, import_prettier.format)(code, {
|
|
69
113
|
...prettierOptions,
|
|
70
114
|
filepath: originalFileName
|
|
71
115
|
});
|
|
@@ -92,10 +136,11 @@ async function removeTypes(code, fileName, options) {
|
|
|
92
136
|
}
|
|
93
137
|
}
|
|
94
138
|
};
|
|
95
|
-
const
|
|
139
|
+
const babelConfig = {
|
|
96
140
|
filename: fileName,
|
|
97
141
|
retainLines: true,
|
|
98
142
|
plugins: [
|
|
143
|
+
// Plugin to remove leading comments attached to TypeScript-only constructs
|
|
99
144
|
{
|
|
100
145
|
name: "detype-comment-remover",
|
|
101
146
|
visitor: {
|
|
@@ -111,7 +156,11 @@ async function removeTypes(code, fileName, options) {
|
|
|
111
156
|
generatorOpts: {
|
|
112
157
|
shouldPrintComment: (comment) => comment !== "@detype: remove-me" && (!options.removeTsComments || !comment.match(/^\s*(@ts-ignore|@ts-expect-error)/))
|
|
113
158
|
}
|
|
114
|
-
}
|
|
159
|
+
};
|
|
160
|
+
if (options.customizeBabelConfig) {
|
|
161
|
+
options.customizeBabelConfig(babelConfig);
|
|
162
|
+
}
|
|
163
|
+
const babelOutput = await (0, import_core.transformAsync)(code, babelConfig);
|
|
115
164
|
if (!babelOutput || babelOutput.code === void 0 || babelOutput.code === null) {
|
|
116
165
|
throw new Error("Babel error");
|
|
117
166
|
}
|
|
@@ -129,9 +178,9 @@ async function removeTypesFromVueSfcScript(code, fileName, script, templateAst,
|
|
|
129
178
|
(0, import_template_ast_types.traverse)(templateAst, {
|
|
130
179
|
enter(node) {
|
|
131
180
|
if ((0, import_template_ast_types.isSimpleExpressionNode)(node) && !node.isStatic) {
|
|
132
|
-
expressions.add(node.content);
|
|
181
|
+
expressions.add(`[${node.content}]`);
|
|
133
182
|
} else if ((0, import_template_ast_types.isComponentNode)(node)) {
|
|
134
|
-
expressions.add(node.tag);
|
|
183
|
+
expressions.add(`[${node.tag}]`);
|
|
135
184
|
}
|
|
136
185
|
}
|
|
137
186
|
});
|
|
@@ -176,7 +225,7 @@ function processMagicComments(input) {
|
|
|
176
225
|
}
|
|
177
226
|
return input;
|
|
178
227
|
}
|
|
179
|
-
function removeMagicComments(code, fileName, prettierOptions) {
|
|
228
|
+
async function removeMagicComments(code, fileName, prettierOptions) {
|
|
180
229
|
const REPLACE_COMMENT = "// @detype: replace\n";
|
|
181
230
|
const WITH_COMMENT = "// @detype: with\n";
|
|
182
231
|
const END_COMMENT = "// @detype: end\n";
|
|
@@ -198,7 +247,7 @@ function removeMagicComments(code, fileName, prettierOptions) {
|
|
|
198
247
|
start = code.indexOf(REPLACE_COMMENT, before.length + keptText.length);
|
|
199
248
|
startEnd = start + REPLACE_COMMENT.length;
|
|
200
249
|
}
|
|
201
|
-
code = (0, import_prettier.format)(code, {
|
|
250
|
+
code = await (0, import_prettier.format)(code, {
|
|
202
251
|
...prettierOptions,
|
|
203
252
|
filepath: fileName
|
|
204
253
|
});
|
|
@@ -207,7 +256,7 @@ function removeMagicComments(code, fileName, prettierOptions) {
|
|
|
207
256
|
|
|
208
257
|
// src/transformFile.ts
|
|
209
258
|
var import_prettier2 = require("prettier");
|
|
210
|
-
var { readFile, writeFile } =
|
|
259
|
+
var { readFile, writeFile } = import_node_fs.default.promises;
|
|
211
260
|
async function transformFile(inputFileName, outputFileName, options = {}) {
|
|
212
261
|
const code = await readFile(inputFileName, "utf-8");
|
|
213
262
|
const prettierOptions = await (0, import_prettier2.resolveConfig)(inputFileName);
|
|
@@ -230,7 +279,7 @@ var import_fast_glob = __toESM(require("fast-glob"));
|
|
|
230
279
|
// package.json
|
|
231
280
|
var package_default = {
|
|
232
281
|
name: "detype",
|
|
233
|
-
version: "0.
|
|
282
|
+
version: "1.0.0",
|
|
234
283
|
description: "Removes TypeScript type annotations but keeps the formatting",
|
|
235
284
|
main: "dist/index.js",
|
|
236
285
|
bin: "detype.js",
|
|
@@ -254,27 +303,28 @@ var package_default = {
|
|
|
254
303
|
"index.d.ts"
|
|
255
304
|
],
|
|
256
305
|
dependencies: {
|
|
257
|
-
"@babel/core": "^7.
|
|
258
|
-
"@babel/preset-typescript": "^7.
|
|
306
|
+
"@babel/core": "^7.23.7",
|
|
307
|
+
"@babel/preset-typescript": "^7.23.3",
|
|
308
|
+
"@vue/compiler-dom": "^3.4.3",
|
|
309
|
+
"@vue/compiler-sfc": "^3.4.3",
|
|
259
310
|
"@vuedx/compiler-sfc": "0.7.1",
|
|
260
311
|
"@vuedx/template-ast-types": "0.7.1",
|
|
261
|
-
"fast-glob": "^3.2
|
|
262
|
-
prettier: "^
|
|
263
|
-
"string.prototype.replaceall": "^1.0.
|
|
312
|
+
"fast-glob": "^3.3.2",
|
|
313
|
+
prettier: "^3.1.1",
|
|
314
|
+
"string.prototype.replaceall": "^1.0.8"
|
|
264
315
|
},
|
|
265
316
|
devDependencies: {
|
|
266
|
-
"@babel/traverse": "^7.
|
|
267
|
-
"@cyco130/eslint-config": "^
|
|
268
|
-
"@types/babel__core": "^7.
|
|
269
|
-
"@types/babel__traverse": "^7.
|
|
270
|
-
"@types/node": "
|
|
271
|
-
|
|
272
|
-
eslint: "^8.29.0",
|
|
317
|
+
"@babel/traverse": "^7.23.7",
|
|
318
|
+
"@cyco130/eslint-config": "^3.6.0",
|
|
319
|
+
"@types/babel__core": "^7.20.5",
|
|
320
|
+
"@types/babel__traverse": "^7.20.5",
|
|
321
|
+
"@types/node": "20.10.6",
|
|
322
|
+
eslint: "^8.56.0",
|
|
273
323
|
"npm-run-all": "^4.1.5",
|
|
274
|
-
rimraf: "^
|
|
275
|
-
tsup: "^
|
|
276
|
-
typescript: "^
|
|
277
|
-
vitest: "
|
|
324
|
+
rimraf: "^5.0.5",
|
|
325
|
+
tsup: "^8.0.1",
|
|
326
|
+
typescript: "^5.3.3",
|
|
327
|
+
vitest: "1.1.0"
|
|
278
328
|
},
|
|
279
329
|
repository: {
|
|
280
330
|
type: "git",
|
|
@@ -295,7 +345,7 @@ var package_default = {
|
|
|
295
345
|
};
|
|
296
346
|
|
|
297
347
|
// src/cli-lib.ts
|
|
298
|
-
var { stat, mkdir } =
|
|
348
|
+
var { stat, mkdir } = import_node_fs2.default.promises;
|
|
299
349
|
async function cli(...args2) {
|
|
300
350
|
let dashDash = false;
|
|
301
351
|
const params = [];
|
|
@@ -343,26 +393,24 @@ async function cli(...args2) {
|
|
|
343
393
|
printUsage();
|
|
344
394
|
return false;
|
|
345
395
|
}
|
|
346
|
-
const files = (await (0, import_fast_glob.default)(unixify(input + "/**/*.{ts,tsx,vue}"))).filter(
|
|
347
|
-
|
|
348
|
-
);
|
|
349
|
-
const dirs = [...new Set(files.map((file) => import_path.default.dirname(file)))].sort();
|
|
350
|
-
await mkdir(import_path.default.normalize(output), { recursive: true });
|
|
396
|
+
const files = (await (0, import_fast_glob.default)(unixify(input + "/**/*.{ts,tsx,vue}"))).filter((file) => !file.endsWith(".d.ts"));
|
|
397
|
+
const dirs = [...new Set(files.map((file) => import_node_path.default.dirname(file)))].sort();
|
|
398
|
+
await mkdir(import_node_path.default.normalize(output), { recursive: true });
|
|
351
399
|
for (const dir of dirs) {
|
|
352
|
-
const outDir =
|
|
400
|
+
const outDir = import_node_path.default.join(output, import_node_path.default.relative(input, dir));
|
|
353
401
|
if (outDir === output)
|
|
354
402
|
continue;
|
|
355
|
-
await mkdir(
|
|
403
|
+
await mkdir(import_node_path.default.normalize(outDir), { recursive: true });
|
|
356
404
|
}
|
|
357
405
|
for (const file of files) {
|
|
358
|
-
const inputDir =
|
|
359
|
-
const outputName = inferName(file,
|
|
406
|
+
const inputDir = import_node_path.default.dirname(import_node_path.default.relative(input, file));
|
|
407
|
+
const outputName = inferName(file, import_node_path.default.join(output, inputDir));
|
|
360
408
|
removeMagic ? await removeMagicCommentsFromFile(
|
|
361
|
-
|
|
362
|
-
|
|
409
|
+
import_node_path.default.normalize(file),
|
|
410
|
+
import_node_path.default.normalize(outputName)
|
|
363
411
|
) : await transformFile(
|
|
364
|
-
|
|
365
|
-
|
|
412
|
+
import_node_path.default.normalize(file),
|
|
413
|
+
import_node_path.default.normalize(outputName),
|
|
366
414
|
{ removeTsComments }
|
|
367
415
|
);
|
|
368
416
|
}
|
|
@@ -391,28 +439,28 @@ async function cli(...args2) {
|
|
|
391
439
|
}
|
|
392
440
|
output = inferName(input);
|
|
393
441
|
}
|
|
394
|
-
const outputDir =
|
|
442
|
+
const outputDir = import_node_path.default.dirname(output);
|
|
395
443
|
if (outputDir) {
|
|
396
|
-
await mkdir(
|
|
444
|
+
await mkdir(import_node_path.default.normalize(outputDir), { recursive: true });
|
|
397
445
|
}
|
|
398
446
|
removeMagic ? await removeMagicCommentsFromFile(
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
) : await transformFile(
|
|
447
|
+
import_node_path.default.normalize(input),
|
|
448
|
+
import_node_path.default.normalize(output)
|
|
449
|
+
) : await transformFile(import_node_path.default.normalize(input), import_node_path.default.normalize(output), {
|
|
402
450
|
removeTsComments
|
|
403
451
|
});
|
|
404
452
|
return true;
|
|
405
453
|
function inferName(input2, outputDir2) {
|
|
406
454
|
let output2;
|
|
407
|
-
const { dir, name, ext } =
|
|
455
|
+
const { dir, name, ext } = import_node_path.default.parse(input2);
|
|
408
456
|
if (removeMagic) {
|
|
409
|
-
output2 =
|
|
457
|
+
output2 = import_node_path.default.join(outputDir2 ?? dir, `${name}${ext}`);
|
|
410
458
|
} else if (ext === ".ts") {
|
|
411
|
-
output2 =
|
|
459
|
+
output2 = import_node_path.default.join(outputDir2 ?? dir, name + ".js");
|
|
412
460
|
} else if (ext === ".tsx") {
|
|
413
|
-
output2 =
|
|
461
|
+
output2 = import_node_path.default.join(outputDir2 ?? dir, name + ".jsx");
|
|
414
462
|
} else if (ext === ".vue") {
|
|
415
|
-
output2 =
|
|
463
|
+
output2 = import_node_path.default.join(outputDir2 ?? dir, name + ".vue");
|
|
416
464
|
} else {
|
|
417
465
|
throw new Error(`Unknwon file extension ${input2}`);
|
|
418
466
|
}
|
|
@@ -446,9 +494,12 @@ var USAGE = `Usage:
|
|
|
446
494
|
Print this help and exit`;
|
|
447
495
|
var VERSION = package_default.version;
|
|
448
496
|
function unixify(name) {
|
|
449
|
-
return name.replaceAll(
|
|
497
|
+
return name.replaceAll(import_node_path.default.sep, "/");
|
|
450
498
|
}
|
|
451
499
|
|
|
452
500
|
// src/cli.ts
|
|
453
501
|
var args = process.argv.slice(2);
|
|
454
|
-
cli(...args).then((success) => process.exit(success ? 0 : 1))
|
|
502
|
+
cli(...args).then((success) => process.exit(success ? 0 : 1)).catch((error) => {
|
|
503
|
+
console.error(error);
|
|
504
|
+
process.exit(1);
|
|
505
|
+
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { Options } from 'prettier';
|
|
2
2
|
export { Options as PrettierOptions } from 'prettier';
|
|
3
|
+
import { TransformOptions as TransformOptions$1 } from '@babel/core';
|
|
3
4
|
|
|
4
5
|
interface RemoveTypeOptions {
|
|
5
6
|
/** Whether to remove ts-ignore and ts-expect-error comments */
|
|
6
7
|
removeTsComments?: boolean;
|
|
8
|
+
/** Escape hatch for customizing Babel configuration */
|
|
9
|
+
customizeBabelConfig?(config: TransformOptions$1): void;
|
|
7
10
|
}
|
|
8
11
|
interface TransformOptions extends RemoveTypeOptions {
|
|
9
12
|
/** Prettier options */
|
|
@@ -22,7 +25,7 @@ declare function transform(code: string, fileName: string, options?: TransformOp
|
|
|
22
25
|
* @param fileName File name for the source
|
|
23
26
|
* @param prettierOptions Options to pass to prettier
|
|
24
27
|
*/
|
|
25
|
-
declare function removeMagicComments(code: string, fileName: string, prettierOptions?: Options | null): string
|
|
28
|
+
declare function removeMagicComments(code: string, fileName: string, prettierOptions?: Options | null): Promise<string>;
|
|
26
29
|
|
|
27
30
|
/**
|
|
28
31
|
* Transform the input file and write the output to another file
|
package/dist/index.js
CHANGED
|
@@ -18,6 +18,10 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
return to;
|
|
19
19
|
};
|
|
20
20
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
25
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
26
|
mod
|
|
23
27
|
));
|
|
@@ -37,15 +41,36 @@ module.exports = __toCommonJS(src_exports);
|
|
|
37
41
|
var import_core = require("@babel/core");
|
|
38
42
|
var import_prettier = require("prettier");
|
|
39
43
|
var import_compiler_sfc = require("@vuedx/compiler-sfc");
|
|
44
|
+
var import_compiler_sfc2 = require("@vue/compiler-sfc");
|
|
40
45
|
var import_template_ast_types = require("@vuedx/template-ast-types");
|
|
41
46
|
var import_preset_typescript = __toESM(require("@babel/preset-typescript"));
|
|
42
47
|
var import_string_prototype = require("string.prototype.replaceall");
|
|
43
48
|
(0, import_string_prototype.shim)();
|
|
49
|
+
function getDefinePropsObject(content) {
|
|
50
|
+
const matched = /\sprops:\s*\{/m.exec(content);
|
|
51
|
+
if (matched) {
|
|
52
|
+
const startContentIndex = matched.index + matched[0].length - 1;
|
|
53
|
+
let leftBracketCount = 1;
|
|
54
|
+
let endContentIndex = startContentIndex + 1;
|
|
55
|
+
while (leftBracketCount) {
|
|
56
|
+
if (content.charAt(endContentIndex) === "{") {
|
|
57
|
+
leftBracketCount++;
|
|
58
|
+
} else if (content.charAt(endContentIndex) === "}") {
|
|
59
|
+
leftBracketCount--;
|
|
60
|
+
}
|
|
61
|
+
endContentIndex++;
|
|
62
|
+
}
|
|
63
|
+
return content.substring(startContentIndex, endContentIndex);
|
|
64
|
+
}
|
|
65
|
+
return "";
|
|
66
|
+
}
|
|
44
67
|
async function transform(code, fileName, options = {}) {
|
|
45
|
-
var _a, _b, _c, _d;
|
|
68
|
+
var _a, _b, _c, _d, _e;
|
|
46
69
|
const { prettierOptions, ...removeTypeOptions } = options;
|
|
47
70
|
const originalCode = code;
|
|
48
71
|
const originalFileName = fileName;
|
|
72
|
+
let propsContent = "";
|
|
73
|
+
let emitsContent = "";
|
|
49
74
|
code = code.replaceAll("\r\n", "\n");
|
|
50
75
|
if (fileName.endsWith(".vue")) {
|
|
51
76
|
const parsedVue = (0, import_compiler_sfc.parse)(code);
|
|
@@ -53,6 +78,19 @@ async function transform(code, fileName, options = {}) {
|
|
|
53
78
|
return originalCode;
|
|
54
79
|
}
|
|
55
80
|
let { script: script1, scriptSetup: script2 } = parsedVue.descriptor;
|
|
81
|
+
const isContainsDefinePropsType = script2 == null ? void 0 : script2.content.match(/defineProps\s*</m);
|
|
82
|
+
const isContainsDefineEmitType = script2 == null ? void 0 : script2.content.match(/defineEmits\s*</m);
|
|
83
|
+
if (isContainsDefinePropsType || isContainsDefineEmitType) {
|
|
84
|
+
const { content } = (0, import_compiler_sfc2.compileScript)(parsedVue.descriptor, {
|
|
85
|
+
id: "xxxxxxx"
|
|
86
|
+
});
|
|
87
|
+
if (isContainsDefinePropsType) {
|
|
88
|
+
propsContent = getDefinePropsObject(content);
|
|
89
|
+
}
|
|
90
|
+
if (isContainsDefineEmitType) {
|
|
91
|
+
emitsContent = ((_c = content.match(/\semits:\s(\[.*\]?)/m)) == null ? void 0 : _c[1]) || "";
|
|
92
|
+
}
|
|
93
|
+
}
|
|
56
94
|
if (script1 && script2 && script1.loc.start.offset < script2.loc.start.offset) {
|
|
57
95
|
[script2, script1] = [script1, script2];
|
|
58
96
|
}
|
|
@@ -60,20 +98,26 @@ async function transform(code, fileName, options = {}) {
|
|
|
60
98
|
code,
|
|
61
99
|
fileName,
|
|
62
100
|
script1,
|
|
63
|
-
(
|
|
101
|
+
(_d = parsedVue.descriptor.template) == null ? void 0 : _d.ast,
|
|
64
102
|
removeTypeOptions
|
|
65
103
|
);
|
|
66
104
|
code = await removeTypesFromVueSfcScript(
|
|
67
105
|
code,
|
|
68
106
|
fileName,
|
|
69
107
|
script2,
|
|
70
|
-
(
|
|
108
|
+
(_e = parsedVue.descriptor.template) == null ? void 0 : _e.ast,
|
|
71
109
|
removeTypeOptions
|
|
72
110
|
);
|
|
73
111
|
} else {
|
|
74
112
|
code = await removeTypes(code, fileName, removeTypeOptions);
|
|
75
113
|
}
|
|
76
|
-
|
|
114
|
+
if (propsContent) {
|
|
115
|
+
code = code.replace("defineProps(", (str) => `${str}${propsContent}`);
|
|
116
|
+
}
|
|
117
|
+
if (emitsContent) {
|
|
118
|
+
code = code.replace("defineEmits(", (str) => `${str}${emitsContent}`);
|
|
119
|
+
}
|
|
120
|
+
code = await (0, import_prettier.format)(code, {
|
|
77
121
|
...prettierOptions,
|
|
78
122
|
filepath: originalFileName
|
|
79
123
|
});
|
|
@@ -100,10 +144,11 @@ async function removeTypes(code, fileName, options) {
|
|
|
100
144
|
}
|
|
101
145
|
}
|
|
102
146
|
};
|
|
103
|
-
const
|
|
147
|
+
const babelConfig = {
|
|
104
148
|
filename: fileName,
|
|
105
149
|
retainLines: true,
|
|
106
150
|
plugins: [
|
|
151
|
+
// Plugin to remove leading comments attached to TypeScript-only constructs
|
|
107
152
|
{
|
|
108
153
|
name: "detype-comment-remover",
|
|
109
154
|
visitor: {
|
|
@@ -119,7 +164,11 @@ async function removeTypes(code, fileName, options) {
|
|
|
119
164
|
generatorOpts: {
|
|
120
165
|
shouldPrintComment: (comment) => comment !== "@detype: remove-me" && (!options.removeTsComments || !comment.match(/^\s*(@ts-ignore|@ts-expect-error)/))
|
|
121
166
|
}
|
|
122
|
-
}
|
|
167
|
+
};
|
|
168
|
+
if (options.customizeBabelConfig) {
|
|
169
|
+
options.customizeBabelConfig(babelConfig);
|
|
170
|
+
}
|
|
171
|
+
const babelOutput = await (0, import_core.transformAsync)(code, babelConfig);
|
|
123
172
|
if (!babelOutput || babelOutput.code === void 0 || babelOutput.code === null) {
|
|
124
173
|
throw new Error("Babel error");
|
|
125
174
|
}
|
|
@@ -137,9 +186,9 @@ async function removeTypesFromVueSfcScript(code, fileName, script, templateAst,
|
|
|
137
186
|
(0, import_template_ast_types.traverse)(templateAst, {
|
|
138
187
|
enter(node) {
|
|
139
188
|
if ((0, import_template_ast_types.isSimpleExpressionNode)(node) && !node.isStatic) {
|
|
140
|
-
expressions.add(node.content);
|
|
189
|
+
expressions.add(`[${node.content}]`);
|
|
141
190
|
} else if ((0, import_template_ast_types.isComponentNode)(node)) {
|
|
142
|
-
expressions.add(node.tag);
|
|
191
|
+
expressions.add(`[${node.tag}]`);
|
|
143
192
|
}
|
|
144
193
|
}
|
|
145
194
|
});
|
|
@@ -184,7 +233,7 @@ function processMagicComments(input) {
|
|
|
184
233
|
}
|
|
185
234
|
return input;
|
|
186
235
|
}
|
|
187
|
-
function removeMagicComments(code, fileName, prettierOptions) {
|
|
236
|
+
async function removeMagicComments(code, fileName, prettierOptions) {
|
|
188
237
|
const REPLACE_COMMENT = "// @detype: replace\n";
|
|
189
238
|
const WITH_COMMENT = "// @detype: with\n";
|
|
190
239
|
const END_COMMENT = "// @detype: end\n";
|
|
@@ -206,7 +255,7 @@ function removeMagicComments(code, fileName, prettierOptions) {
|
|
|
206
255
|
start = code.indexOf(REPLACE_COMMENT, before.length + keptText.length);
|
|
207
256
|
startEnd = start + REPLACE_COMMENT.length;
|
|
208
257
|
}
|
|
209
|
-
code = (0, import_prettier.format)(code, {
|
|
258
|
+
code = await (0, import_prettier.format)(code, {
|
|
210
259
|
...prettierOptions,
|
|
211
260
|
filepath: fileName
|
|
212
261
|
});
|
|
@@ -214,9 +263,9 @@ function removeMagicComments(code, fileName, prettierOptions) {
|
|
|
214
263
|
}
|
|
215
264
|
|
|
216
265
|
// src/transformFile.ts
|
|
217
|
-
var
|
|
266
|
+
var import_node_fs = __toESM(require("fs"));
|
|
218
267
|
var import_prettier2 = require("prettier");
|
|
219
|
-
var { readFile, writeFile } =
|
|
268
|
+
var { readFile, writeFile } = import_node_fs.default.promises;
|
|
220
269
|
async function transformFile(inputFileName, outputFileName, options = {}) {
|
|
221
270
|
const code = await readFile(inputFileName, "utf-8");
|
|
222
271
|
const prettierOptions = await (0, import_prettier2.resolveConfig)(inputFileName);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "detype",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Removes TypeScript type annotations but keeps the formatting",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": "detype.js",
|
|
@@ -12,27 +12,28 @@
|
|
|
12
12
|
"index.d.ts"
|
|
13
13
|
],
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@babel/core": "^7.
|
|
16
|
-
"@babel/preset-typescript": "^7.
|
|
15
|
+
"@babel/core": "^7.23.7",
|
|
16
|
+
"@babel/preset-typescript": "^7.23.3",
|
|
17
|
+
"@vue/compiler-dom": "^3.4.3",
|
|
18
|
+
"@vue/compiler-sfc": "^3.4.3",
|
|
17
19
|
"@vuedx/compiler-sfc": "0.7.1",
|
|
18
20
|
"@vuedx/template-ast-types": "0.7.1",
|
|
19
|
-
"fast-glob": "^3.2
|
|
20
|
-
"prettier": "^
|
|
21
|
-
"string.prototype.replaceall": "^1.0.
|
|
21
|
+
"fast-glob": "^3.3.2",
|
|
22
|
+
"prettier": "^3.1.1",
|
|
23
|
+
"string.prototype.replaceall": "^1.0.8"
|
|
22
24
|
},
|
|
23
25
|
"devDependencies": {
|
|
24
|
-
"@babel/traverse": "^7.
|
|
25
|
-
"@cyco130/eslint-config": "^
|
|
26
|
-
"@types/babel__core": "^7.
|
|
27
|
-
"@types/babel__traverse": "^7.
|
|
28
|
-
"@types/node": "
|
|
29
|
-
"
|
|
30
|
-
"eslint": "^8.29.0",
|
|
26
|
+
"@babel/traverse": "^7.23.7",
|
|
27
|
+
"@cyco130/eslint-config": "^3.6.0",
|
|
28
|
+
"@types/babel__core": "^7.20.5",
|
|
29
|
+
"@types/babel__traverse": "^7.20.5",
|
|
30
|
+
"@types/node": "20.10.6",
|
|
31
|
+
"eslint": "^8.56.0",
|
|
31
32
|
"npm-run-all": "^4.1.5",
|
|
32
|
-
"rimraf": "^
|
|
33
|
-
"tsup": "^
|
|
34
|
-
"typescript": "^
|
|
35
|
-
"vitest": "
|
|
33
|
+
"rimraf": "^5.0.5",
|
|
34
|
+
"tsup": "^8.0.1",
|
|
35
|
+
"typescript": "^5.3.3",
|
|
36
|
+
"vitest": "1.1.0"
|
|
36
37
|
},
|
|
37
38
|
"repository": {
|
|
38
39
|
"type": "git",
|