detype 0.3.5 → 0.4.2

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
@@ -6,7 +6,9 @@
6
6
  npm i -g detype
7
7
  ```
8
8
 
9
- **detype** is a command line tool and library to remove type annotations and other TypeScript specific syntax constructs and output vanilla JavaScript **without altering the source formatting** too much. It supports `.ts`, `.tsx`, as well as `.vue` extensions.
9
+ Suppose you have a library that you want to provide usage examples for. **detype** can help you generate vanilla JavaScript samples from TypeScript samples automatically and remove the burden of maintaining two separate versions of what is essentially the same code.
10
+
11
+ It is a command line tool and a library that removes type annotations and other TypeScript specific syntax constructs and outputs vanilla JavaScript **without altering the source formatting** too much. It supports `.ts`, `.tsx`, as well as `.vue` files.
10
12
 
11
13
  In other words, it turns this:
12
14
 
@@ -43,26 +45,68 @@ export function bar(foo) {
43
45
  }
44
46
  ```
45
47
 
46
- It achieves this using [Babel](https://babeljs.io/), [Babel's TypeScript preset](https://babeljs.io/docs/en/babel-preset-typescript), a small custom Babel plugin to remove comments attached to TypeScript-only constructs, and [Prettier](https://prettier.io/). For Vue files, it uses the tools from the [VueDX project](https://github.com/vuedx/languagetools) The output is very close to hand-written JavaScript, especially if you were already using Prettier for formatting.
48
+ The output is very close to hand-written JavaScript, especially if you were already using Prettier for formatting.
47
49
 
48
- **One possible use case** is the following: Suppose you have a library that you want to provide usage examples for. Automatically generating vanilla JavaScript samples from TypeScript samples using `detype` would remove the burden of maintaining two separate versions of what is essentially the same code.
50
+ ## Doesn't `tsc` already do that?
49
51
 
50
- ## Installation
52
+ There are lots of tools for transpiling TypeScript into plain JavaScript (`tsc`, `babel`, `swc`, `esbuild`, `sucrase` etc.) but none of them is perfectly suitable for this specific use case. Most of them don't preserve the formatting at all. `sucrase` comes close, but it doesn't remove comments attached to TypeScript-only constructs.
51
53
 
52
- ```sh
53
- npm install detype
54
+ `detype` uses [Babel](https://babeljs.io/), a small Babel plugin to remove comments attached to TypeScript-only constructs, and [Prettier](https://prettier.io/) under the hood. For Vue files, it also uses the tools from the [VueDX project](https://github.com/vuedx/languagetools).
55
+
56
+ ## Magic comments
57
+
58
+ Sometimes you want the generated JavaScript to be slightly different than the TypeScript original. You can use the magic comments feature to achieve this:
59
+
60
+ Input:
61
+
62
+ ```ts
63
+ // @detype: replace
64
+ // These two lines will be removed
65
+ console.log("Hello from TypeScript");
66
+ // @detype: with
67
+ // // Notice the double comments!
68
+ // console.log("Hello from JavaScript");
69
+ // @detype: end
70
+ ```
71
+
72
+ Output:
73
+
74
+ ```js
75
+ // Notice the double comments!
76
+ console.log("Hello from JavaScript");
77
+ ```
78
+
79
+ If you just want to remove the magic comments, you can use the `-m` CLI flag or the `removeMagicComments` function to generate uncluttered TypeScript like this:
80
+
81
+ ```ts
82
+ // These two lines will be removed
83
+ console.log("Hello from TypeScript");
54
84
  ```
55
85
 
86
+ ## System requirements
87
+
56
88
  `detype` requires Node version 12.22.7 or later.
57
89
 
58
90
  ## CLI Usage
59
91
 
60
- ```sh
61
- detype input.ts output.js
62
- detype file.ts # Output to file.js
63
- detype file.tsx # Output to file.jsx
64
- detype file.ts output-dir # Output to output-dir/file.sjs
65
- detype input-dir output-dir # Process recursively, rename .ts(x) as .js(x)
92
+ ```
93
+ detype [-m | --remove-magic-comments] <INPUT> [OUTPUT]
94
+
95
+ INPUT Input file or directory
96
+
97
+ OUTPUT Output file or directory
98
+ (optional if it can be inferred and it won't overwrite the source file)
99
+
100
+ -m, --remove-magic-comments
101
+ Remove magic comments only, don't perform ts > js transform
102
+
103
+ detype [-v | --version]
104
+
105
+ Print version and exit
106
+
107
+ detype [-h | --help]
108
+
109
+ Print this help and exit
66
110
  ```
67
111
 
68
112
  ## Node API
@@ -70,31 +114,51 @@ detype input-dir output-dir # Process recursively, rename .ts(x) as .js(x)
70
114
  ```ts
71
115
  // Transform TypeScript code into vanilla JavaScript without affecting the formatting
72
116
  function transform(
73
- // Source coude
74
- code: string,
75
- // File name for the source (useful for distinguishing between .ts and .tsx)
76
- fileName: string,
77
- // Options to pass to prettier
78
- prettierOptions?: PrettierOptions | null,
117
+ // Source code
118
+ code: string,
119
+ // File name for the source
120
+ fileName: string,
121
+ // Options to pass to prettier
122
+ prettierOptions?: PrettierOptions | null,
79
123
  ): Promise<string>;
80
124
 
81
125
  // Transform the input file and write the output to another file
82
126
  function transformFile(
83
- inputFileName: string,
84
- outputFileName: string,
127
+ inputFileName: string,
128
+ outputFileName: string,
129
+ ): Promise<void>;
130
+
131
+ // Remove magic comments without performing the TS to JS transform
132
+ export function removeMagicComments(
133
+ // Source code
134
+ code: string,
135
+ // File name for the source
136
+ fileName: string,
137
+ // Options to pass to prettier
138
+ prettierOptions?: PrettierOptions | null,
139
+ ): string;
140
+
141
+ // Remove magic comments from the input file and write the output to another file
142
+ export function removeMagicCommentsFromFile(
143
+ inputFileName: string,
144
+ outputFileName: string,
85
145
  ): Promise<void>;
86
146
  ```
87
147
 
88
148
  ## Change log
89
- ## 0.3
90
- - feat: Magic comments
91
- - feat: Expose type declarations
149
+ ### 0.4
150
+ - feature: CLI support for removing magic comments
151
+ - chore: Improve documentation
152
+
153
+ ### 0.3
154
+ - feature: Magic comments
155
+ - feature: Expose type declarations
92
156
  - fix: Better empty line handling
93
157
 
94
- ## 0.2
95
- - feat: for Vue single file components
158
+ ### 0.2
159
+ - feature: for Vue single file components
96
160
 
97
- ## 0.1
161
+ ### 0.1
98
162
  - Initial release
99
163
 
100
164
  ## Credits
package/dist/cli.js CHANGED
@@ -21,33 +21,30 @@ var __spreadValues = (a, b) => {
21
21
  return a;
22
22
  };
23
23
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
24
- var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
25
- var __reExport = (target, module2, desc) => {
26
- if (module2 && typeof module2 === "object" || typeof module2 === "function") {
27
- for (let key of __getOwnPropNames(module2))
28
- if (!__hasOwnProp.call(target, key) && key !== "default")
29
- __defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
24
+ var __copyProps = (to, from, except, desc) => {
25
+ if (from && typeof from === "object" || typeof from === "function") {
26
+ for (let key of __getOwnPropNames(from))
27
+ if (!__hasOwnProp.call(to, key) && key !== except)
28
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
30
29
  }
31
- return target;
32
- };
33
- var __toModule = (module2) => {
34
- return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
30
+ return to;
35
31
  };
32
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
36
33
 
37
34
  // src/cli-lib.ts
38
- var import_fs2 = __toModule(require("fs"));
39
- var import_path = __toModule(require("path"));
35
+ var import_fs2 = __toESM(require("fs"));
36
+ var import_path = __toESM(require("path"));
40
37
 
41
38
  // src/transformFile.ts
42
- var import_fs = __toModule(require("fs"));
39
+ var import_fs = __toESM(require("fs"));
43
40
 
44
41
  // src/transform.ts
45
- var import_core = __toModule(require("@babel/core"));
46
- var import_prettier = __toModule(require("prettier"));
47
- var import_compiler_sfc = __toModule(require("@vuedx/compiler-sfc"));
48
- var import_template_ast_types = __toModule(require("@vuedx/template-ast-types"));
49
- var import_preset_typescript = __toModule(require("@babel/preset-typescript"));
50
- var import_string_prototype = __toModule(require("string.prototype.replaceall"));
42
+ var import_core = require("@babel/core");
43
+ var import_prettier = require("prettier");
44
+ var import_compiler_sfc = require("@vuedx/compiler-sfc");
45
+ var import_template_ast_types = require("@vuedx/template-ast-types");
46
+ var import_preset_typescript = __toESM(require("@babel/preset-typescript"));
47
+ var import_string_prototype = require("string.prototype.replaceall");
51
48
  (0, import_string_prototype.shim)();
52
49
  async function transform(code, fileName, prettierOptions) {
53
50
  var _a, _b, _c, _d;
@@ -117,7 +114,7 @@ async function removeTypesFromVueSfcScript(code, fileName, script, templateAst)
117
114
  if (script === null || script.lang !== "ts")
118
115
  return code;
119
116
  if (script.setup && templateAst) {
120
- const expressions = new Set();
117
+ const expressions = /* @__PURE__ */ new Set();
121
118
  (0, import_template_ast_types.traverse)(templateAst, {
122
119
  enter(node) {
123
120
  if ((0, import_template_ast_types.isSimpleExpressionNode)(node) && !node.isStatic) {
@@ -166,9 +163,36 @@ function processMagicComments(input) {
166
163
  }
167
164
  return input;
168
165
  }
166
+ function removeMagicComments(code, fileName, prettierOptions) {
167
+ const REPLACE_COMMENT = "// @detype: replace\n";
168
+ const WITH_COMMENT = "// @detype: with\n";
169
+ const END_COMMENT = "// @detype: end\n";
170
+ let start = code.indexOf(REPLACE_COMMENT);
171
+ let startEnd = start + REPLACE_COMMENT.length;
172
+ while (start >= 0) {
173
+ const middle = code.indexOf(WITH_COMMENT, start);
174
+ if (middle < 0)
175
+ return code;
176
+ const middleEnd = middle + WITH_COMMENT.length;
177
+ const end = code.indexOf(END_COMMENT, middleEnd);
178
+ if (end < 0)
179
+ return code;
180
+ const endEnd = end + END_COMMENT.length;
181
+ const before = code.slice(0, start);
182
+ const keptText = code.slice(startEnd, middle);
183
+ const after = code.slice(endEnd);
184
+ code = before + keptText + after;
185
+ start = code.indexOf(REPLACE_COMMENT, before.length + keptText.length);
186
+ startEnd = start + REPLACE_COMMENT.length;
187
+ }
188
+ code = (0, import_prettier.format)(code, __spreadProps(__spreadValues({}, prettierOptions), {
189
+ filepath: fileName
190
+ }));
191
+ return code;
192
+ }
169
193
 
170
194
  // src/transformFile.ts
171
- var import_prettier2 = __toModule(require("prettier"));
195
+ var import_prettier2 = require("prettier");
172
196
  var { readFile, writeFile } = import_fs.default.promises;
173
197
  async function transformFile(inputFileName, outputFileName) {
174
198
  const code = await readFile(inputFileName, "utf-8");
@@ -176,14 +200,119 @@ async function transformFile(inputFileName, outputFileName) {
176
200
  const output = await transform(code, inputFileName, prettierConfig);
177
201
  await writeFile(outputFileName, output, "utf-8");
178
202
  }
203
+ async function removeMagicCommentsFromFile(inputFileName, outputFileName) {
204
+ const code = await readFile(inputFileName, "utf-8");
205
+ const prettierConfig = await (0, import_prettier2.resolveConfig)(inputFileName);
206
+ const output = await removeMagicComments(code, inputFileName, prettierConfig);
207
+ await writeFile(outputFileName, output, "utf-8");
208
+ }
209
+
210
+ // src/cli-lib.ts
211
+ var import_fast_glob = __toESM(require("fast-glob"));
212
+
213
+ // package.json
214
+ var name = "detype";
215
+ var version = "0.4.2";
216
+ var description = "Removes TypeScript type annotations but keeps the formatting";
217
+ var main = "dist/index.js";
218
+ var bin = "detype.js";
219
+ var engines = {
220
+ node: ">=12.22.7"
221
+ };
222
+ var scripts = {
223
+ prepublishOnly: "pnpm build",
224
+ build: "node build.mjs",
225
+ watch: "node build.mjs --watch",
226
+ test: "run-p 'test:*'",
227
+ "test:unit": "jest",
228
+ "test:typecheck": "tsc -p tsconfig.json --noEmit",
229
+ "test:lint": "eslint src --max-warnings 0",
230
+ format: "prettier . --write"
231
+ };
232
+ var files = [
233
+ "dist/**/*",
234
+ "index.d.ts"
235
+ ];
236
+ var dependencies = {
237
+ "@babel/core": "^7.17.8",
238
+ "@babel/preset-typescript": "^7.16.7",
239
+ "@vuedx/compiler-sfc": "^0.7.1",
240
+ "@vuedx/template-ast-types": "^0.7.2",
241
+ "fast-glob": "^3.2.11",
242
+ prettier: "^2.6.2",
243
+ "string.prototype.replaceall": "^1.0.6"
244
+ };
245
+ var devDependencies = {
246
+ "@babel/traverse": "^7.17.3",
247
+ "@types/jest": "^27.4.1",
248
+ "@types/node": "17.0.23",
249
+ "@typescript-eslint/eslint-plugin": "^5.17.0",
250
+ "@typescript-eslint/parser": "^5.17.0",
251
+ esbuild: "^0.14.31",
252
+ "esbuild-jest": "^0.5.0",
253
+ "esbuild-node-externals": "^1.4.1",
254
+ eslint: "^8.12.0",
255
+ "eslint-config-prettier": "^8.5.0",
256
+ "eslint-import-resolver-typescript": "^2.7.1",
257
+ "eslint-plugin-import": "^2.25.4",
258
+ "eslint-plugin-no-only-tests": "^2.6.0",
259
+ "eslint-plugin-only-warn": "^1.0.3",
260
+ "eslint-plugin-ssr-friendly": "^1.0.6",
261
+ jest: "^27.5.1",
262
+ "npm-run-all": "^4.1.5",
263
+ rimraf: "^3.0.2",
264
+ typescript: "^4.6.3"
265
+ };
266
+ var repository = {
267
+ type: "git",
268
+ url: "git+https://github.com/cyco130/detype.git"
269
+ };
270
+ var keywords = [
271
+ "typescript",
272
+ "formatting",
273
+ "vue",
274
+ "sfc"
275
+ ];
276
+ var author = "Fatih Ayg\xFCn <cyco130@gmail.com>";
277
+ var license = "MIT";
278
+ var bugs = {
279
+ url: "https://github.com/cyco130/detype/issues"
280
+ };
281
+ var homepage = "https://github.com/cyco130/detype#readme";
282
+ var package_default = {
283
+ name,
284
+ version,
285
+ description,
286
+ main,
287
+ bin,
288
+ engines,
289
+ scripts,
290
+ files,
291
+ dependencies,
292
+ devDependencies,
293
+ repository,
294
+ keywords,
295
+ author,
296
+ license,
297
+ bugs,
298
+ homepage
299
+ };
179
300
 
180
301
  // src/cli-lib.ts
181
- var import_fast_glob = __toModule(require("fast-glob"));
182
302
  var { stat, mkdir } = import_fs2.default.promises;
183
- async function cli(input, output) {
184
- if (!input) {
303
+ async function cli(...args2) {
304
+ let [flag, input, output] = args2;
305
+ if (!flag || flag === "-h" || flag === "--help") {
185
306
  printUsage();
186
- return false;
307
+ return !!flag;
308
+ }
309
+ if (flag === "-v" || flag === "--version") {
310
+ console.log(VERSION);
311
+ return true;
312
+ }
313
+ const removeMagic = flag === "-m" || flag === "--remove-magic-comments";
314
+ if (!removeMagic) {
315
+ [input, output] = args2;
187
316
  }
188
317
  const inputStat = await stat(input);
189
318
  if (inputStat.isDirectory()) {
@@ -192,19 +321,19 @@ async function cli(input, output) {
192
321
  printUsage();
193
322
  return false;
194
323
  }
195
- const files = (await (0, import_fast_glob.default)(import_path.default.join(input, "**/*.{ts,tsx,vue}"))).filter((file) => !file.endsWith(".d.ts"));
196
- const dirs = [...new Set(files.map((file) => import_path.default.dirname(file)))].sort();
197
- await mkdirp(output);
324
+ const files2 = (await (0, import_fast_glob.default)(import_path.default.join(input, "**/*.{ts,tsx,vue}"))).filter((file) => !file.endsWith(".d.ts"));
325
+ const dirs = [...new Set(files2.map((file) => import_path.default.dirname(file)))].sort();
326
+ await mkdir(output, { recursive: true });
198
327
  for (const dir of dirs) {
199
328
  const outDir = import_path.default.join(output, import_path.default.relative(input, dir));
200
329
  if (outDir === output)
201
330
  continue;
202
- await mkdirp(outDir);
331
+ await mkdir(outDir, { recursive: true });
203
332
  }
204
- for (const file of files) {
333
+ for (const file of files2) {
205
334
  const inputDir = import_path.default.dirname(import_path.default.relative(input, file));
206
335
  const outputName = inferName(file, import_path.default.join(output, inputDir));
207
- await transformFile(file, outputName);
336
+ removeMagic ? await removeMagicCommentsFromFile(file, outputName) : await transformFile(file, outputName);
208
337
  }
209
338
  return true;
210
339
  }
@@ -219,46 +348,63 @@ async function cli(input, output) {
219
348
  output = inferName(input, output);
220
349
  }
221
350
  } else {
351
+ if (removeMagic) {
352
+ console.error("Output file name is required when removing magic comments");
353
+ return false;
354
+ }
355
+ if (input.endsWith(".vue")) {
356
+ console.error("Output file name is required for .vue files");
357
+ return false;
358
+ }
222
359
  output = inferName(input);
223
360
  }
224
361
  const outputDir = import_path.default.dirname(output);
225
362
  if (outputDir) {
226
- await mkdirp(outputDir);
363
+ await mkdir(outputDir, { recursive: true });
227
364
  }
228
- await transformFile(input, output);
365
+ removeMagic ? await removeMagicCommentsFromFile(input, output) : await transformFile(input, output);
229
366
  return true;
230
- }
231
- function inferName(input, outputDir) {
232
- let output;
233
- const { dir, name, ext } = import_path.default.parse(input);
234
- if (ext === ".ts") {
235
- output = import_path.default.join(outputDir != null ? outputDir : dir, name + ".js");
236
- } else if (ext === ".tsx") {
237
- output = import_path.default.join(outputDir != null ? outputDir : dir, name + ".jsx");
238
- } else if (ext === ".vue") {
239
- output = import_path.default.join(outputDir != null ? outputDir : dir, name + ".vue");
240
- } else {
241
- throw new Error(`Unknwon file extension ${input}`);
242
- }
243
- return output;
244
- }
245
- async function mkdirp(dir) {
246
- await mkdir(dir, { recursive: true }).catch((error) => {
247
- if (error && error.code == "EEXIST") {
248
- return;
367
+ function inferName(input2, outputDir2) {
368
+ let output2;
369
+ const { dir, name: name2, ext } = import_path.default.parse(input2);
370
+ if (removeMagic) {
371
+ output2 = import_path.default.join(outputDir2 != null ? outputDir2 : dir, `${name2}${ext}`);
372
+ } else if (ext === ".ts") {
373
+ output2 = import_path.default.join(outputDir2 != null ? outputDir2 : dir, name2 + ".js");
374
+ } else if (ext === ".tsx") {
375
+ output2 = import_path.default.join(outputDir2 != null ? outputDir2 : dir, name2 + ".jsx");
376
+ } else if (ext === ".vue") {
377
+ output2 = import_path.default.join(outputDir2 != null ? outputDir2 : dir, name2 + ".vue");
378
+ } else {
379
+ throw new Error(`Unknwon file extension ${input2}`);
249
380
  }
250
- throw error;
251
- });
381
+ return output2;
382
+ }
252
383
  }
253
384
  function printUsage() {
254
- console.error(`Usage:
255
- detype input.ts output.js
256
- detype file.ts # Output to file.js
257
- detype file.tsx # Output to file.jsx
258
- detype file.ts output-dir # Output to output-dir/file.sjs
259
- detype input-dir output-dir # Process recursively, rename .ts(x) as .js(x)`);
385
+ console.error(USAGE);
260
386
  }
387
+ var USAGE = `Usage:
388
+
389
+ detype [-m | --remove-magic-comments] <INPUT> [OUTPUT]
390
+
391
+ INPUT Input file or directory
392
+
393
+ OUTPUT Output file or directory
394
+ (optional if it can be inferred and won't it overwrite the source file)
395
+
396
+ -m, --remove-magic-comments
397
+ Remove magic comments only, don't perform ts > js transform
398
+
399
+ detype [-v | --version]
400
+
401
+ Print version and exit
402
+
403
+ detype [-h | --help]
404
+
405
+ Print this help and exit`;
406
+ var VERSION = package_default.version;
261
407
 
262
408
  // src/cli.ts
263
409
  var args = process.argv.slice(2);
264
- cli(args[0], args[1]).then((success) => process.exit(success ? 0 : 1));
410
+ cli(...args).then((success) => process.exit(success ? 0 : 1));
package/dist/index.js CHANGED
@@ -21,38 +21,38 @@ var __spreadValues = (a, b) => {
21
21
  return a;
22
22
  };
23
23
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
24
- var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
25
24
  var __export = (target, all) => {
26
- __markAsModule(target);
27
25
  for (var name in all)
28
26
  __defProp(target, name, { get: all[name], enumerable: true });
29
27
  };
30
- var __reExport = (target, module2, desc) => {
31
- if (module2 && typeof module2 === "object" || typeof module2 === "function") {
32
- for (let key of __getOwnPropNames(module2))
33
- if (!__hasOwnProp.call(target, key) && key !== "default")
34
- __defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
28
+ var __copyProps = (to, from, except, desc) => {
29
+ if (from && typeof from === "object" || typeof from === "function") {
30
+ for (let key of __getOwnPropNames(from))
31
+ if (!__hasOwnProp.call(to, key) && key !== except)
32
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
35
33
  }
36
- return target;
37
- };
38
- var __toModule = (module2) => {
39
- return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
34
+ return to;
40
35
  };
36
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
37
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
41
38
 
42
39
  // src/index.ts
43
- __export(exports, {
40
+ var src_exports = {};
41
+ __export(src_exports, {
44
42
  removeMagicComments: () => removeMagicComments,
43
+ removeMagicCommentsFromFile: () => removeMagicCommentsFromFile,
45
44
  transform: () => transform,
46
45
  transformFile: () => transformFile
47
46
  });
47
+ module.exports = __toCommonJS(src_exports);
48
48
 
49
49
  // src/transform.ts
50
- var import_core = __toModule(require("@babel/core"));
51
- var import_prettier = __toModule(require("prettier"));
52
- var import_compiler_sfc = __toModule(require("@vuedx/compiler-sfc"));
53
- var import_template_ast_types = __toModule(require("@vuedx/template-ast-types"));
54
- var import_preset_typescript = __toModule(require("@babel/preset-typescript"));
55
- var import_string_prototype = __toModule(require("string.prototype.replaceall"));
50
+ var import_core = require("@babel/core");
51
+ var import_prettier = require("prettier");
52
+ var import_compiler_sfc = require("@vuedx/compiler-sfc");
53
+ var import_template_ast_types = require("@vuedx/template-ast-types");
54
+ var import_preset_typescript = __toESM(require("@babel/preset-typescript"));
55
+ var import_string_prototype = require("string.prototype.replaceall");
56
56
  (0, import_string_prototype.shim)();
57
57
  async function transform(code, fileName, prettierOptions) {
58
58
  var _a, _b, _c, _d;
@@ -122,7 +122,7 @@ async function removeTypesFromVueSfcScript(code, fileName, script, templateAst)
122
122
  if (script === null || script.lang !== "ts")
123
123
  return code;
124
124
  if (script.setup && templateAst) {
125
- const expressions = new Set();
125
+ const expressions = /* @__PURE__ */ new Set();
126
126
  (0, import_template_ast_types.traverse)(templateAst, {
127
127
  enter(node) {
128
128
  if ((0, import_template_ast_types.isSimpleExpressionNode)(node) && !node.isStatic) {
@@ -171,34 +171,37 @@ function processMagicComments(input) {
171
171
  }
172
172
  return input;
173
173
  }
174
- function removeMagicComments(input) {
174
+ function removeMagicComments(code, fileName, prettierOptions) {
175
175
  const REPLACE_COMMENT = "// @detype: replace\n";
176
176
  const WITH_COMMENT = "// @detype: with\n";
177
177
  const END_COMMENT = "// @detype: end\n";
178
- let start = input.indexOf(REPLACE_COMMENT);
178
+ let start = code.indexOf(REPLACE_COMMENT);
179
179
  let startEnd = start + REPLACE_COMMENT.length;
180
180
  while (start >= 0) {
181
- const middle = input.indexOf(WITH_COMMENT, start);
181
+ const middle = code.indexOf(WITH_COMMENT, start);
182
182
  if (middle < 0)
183
- return input;
183
+ return code;
184
184
  const middleEnd = middle + WITH_COMMENT.length;
185
- const end = input.indexOf(END_COMMENT, middleEnd);
185
+ const end = code.indexOf(END_COMMENT, middleEnd);
186
186
  if (end < 0)
187
- return input;
187
+ return code;
188
188
  const endEnd = end + END_COMMENT.length;
189
- const before = input.slice(0, start);
190
- const keptText = input.slice(startEnd, middle);
191
- const after = input.slice(endEnd);
192
- input = before + keptText + after;
193
- start = input.indexOf(REPLACE_COMMENT, before.length + keptText.length);
189
+ const before = code.slice(0, start);
190
+ const keptText = code.slice(startEnd, middle);
191
+ const after = code.slice(endEnd);
192
+ code = before + keptText + after;
193
+ start = code.indexOf(REPLACE_COMMENT, before.length + keptText.length);
194
194
  startEnd = start + REPLACE_COMMENT.length;
195
195
  }
196
- return input;
196
+ code = (0, import_prettier.format)(code, __spreadProps(__spreadValues({}, prettierOptions), {
197
+ filepath: fileName
198
+ }));
199
+ return code;
197
200
  }
198
201
 
199
202
  // src/transformFile.ts
200
- var import_fs = __toModule(require("fs"));
201
- var import_prettier2 = __toModule(require("prettier"));
203
+ var import_fs = __toESM(require("fs"));
204
+ var import_prettier2 = require("prettier");
202
205
  var { readFile, writeFile } = import_fs.default.promises;
203
206
  async function transformFile(inputFileName, outputFileName) {
204
207
  const code = await readFile(inputFileName, "utf-8");
@@ -206,9 +209,16 @@ async function transformFile(inputFileName, outputFileName) {
206
209
  const output = await transform(code, inputFileName, prettierConfig);
207
210
  await writeFile(outputFileName, output, "utf-8");
208
211
  }
212
+ async function removeMagicCommentsFromFile(inputFileName, outputFileName) {
213
+ const code = await readFile(inputFileName, "utf-8");
214
+ const prettierConfig = await (0, import_prettier2.resolveConfig)(inputFileName);
215
+ const output = await removeMagicComments(code, inputFileName, prettierConfig);
216
+ await writeFile(outputFileName, output, "utf-8");
217
+ }
209
218
  // Annotate the CommonJS export names for ESM import in node:
210
219
  0 && (module.exports = {
211
220
  removeMagicComments,
221
+ removeMagicCommentsFromFile,
212
222
  transform,
213
223
  transformFile
214
224
  });
package/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export { PrettierOptions };
5
5
  /**
6
6
  * Transform TypeScript code into vanilla JavaScript without affecting the formatting
7
7
  * @param code Source coude
8
- * @param fileName File name for the source (useful for distinguishing between .ts and .tsx)
8
+ * @param fileName File name for the source
9
9
  * @param prettierOptions Options to pass to prettier
10
10
  */
11
11
  export function transform(
@@ -26,6 +26,22 @@ export function transformFile(
26
26
 
27
27
  /**
28
28
  * Removes magic comments without performing the TS to JS transform
29
- * @param input
29
+ * @param code Source coude
30
+ * @param fileName File name for the source
31
+ * @param prettierOptions Options to pass to prettier
32
+ */
33
+ export function removeMagicComments(
34
+ code: string,
35
+ fileName: string,
36
+ prettierOptions?: PrettierOptions | null,
37
+ ): string;
38
+
39
+ /**
40
+ * Remove magic comments from the input file and write the output to another file
41
+ * @param inputFileName
42
+ * @param outputFileName
30
43
  */
31
- export function removeMagicComments(input: string): string;
44
+ export function removeMagicCommentsFromFile(
45
+ inputFileName: string,
46
+ outputFileName: string,
47
+ ): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "detype",
3
- "version": "0.3.5",
3
+ "version": "0.4.2",
4
4
  "description": "Removes TypeScript type annotations but keeps the formatting",
5
5
  "main": "dist/index.js",
6
6
  "bin": "detype.js",
@@ -12,34 +12,34 @@
12
12
  "index.d.ts"
13
13
  ],
14
14
  "dependencies": {
15
- "@babel/core": "^7.15.8",
16
- "@babel/preset-typescript": "^7.15.0",
15
+ "@babel/core": "^7.17.8",
16
+ "@babel/preset-typescript": "^7.16.7",
17
17
  "@vuedx/compiler-sfc": "^0.7.1",
18
18
  "@vuedx/template-ast-types": "^0.7.2",
19
- "fast-glob": "^3.2.7",
20
- "prettier": "^2.4.1",
19
+ "fast-glob": "^3.2.11",
20
+ "prettier": "^2.6.2",
21
21
  "string.prototype.replaceall": "^1.0.6"
22
22
  },
23
23
  "devDependencies": {
24
- "@babel/traverse": "^7.15.4",
25
- "@types/jest": "^27.0.2",
26
- "@types/node": "12.12.6",
27
- "@typescript-eslint/eslint-plugin": "^4.33.0",
28
- "@typescript-eslint/parser": "^4.33.0",
29
- "esbuild": "^0.13.4",
24
+ "@babel/traverse": "^7.17.3",
25
+ "@types/jest": "^27.4.1",
26
+ "@types/node": "17.0.23",
27
+ "@typescript-eslint/eslint-plugin": "^5.17.0",
28
+ "@typescript-eslint/parser": "^5.17.0",
29
+ "esbuild": "^0.14.31",
30
30
  "esbuild-jest": "^0.5.0",
31
- "esbuild-node-externals": "^1.3.0",
32
- "eslint": "^7.32.0",
33
- "eslint-config-prettier": "^8.3.0",
34
- "eslint-import-resolver-typescript": "^2.5.0",
35
- "eslint-plugin-import": "^2.24.2",
31
+ "esbuild-node-externals": "^1.4.1",
32
+ "eslint": "^8.12.0",
33
+ "eslint-config-prettier": "^8.5.0",
34
+ "eslint-import-resolver-typescript": "^2.7.1",
35
+ "eslint-plugin-import": "^2.25.4",
36
36
  "eslint-plugin-no-only-tests": "^2.6.0",
37
37
  "eslint-plugin-only-warn": "^1.0.3",
38
- "eslint-plugin-ssr-friendly": "^1.0.5",
39
- "jest": "^27.2.4",
38
+ "eslint-plugin-ssr-friendly": "^1.0.6",
39
+ "jest": "^27.5.1",
40
40
  "npm-run-all": "^4.1.5",
41
41
  "rimraf": "^3.0.2",
42
- "typescript": "^4.4.3"
42
+ "typescript": "^4.6.3"
43
43
  },
44
44
  "repository": {
45
45
  "type": "git",
@@ -65,5 +65,6 @@
65
65
  "test:typecheck": "tsc -p tsconfig.json --noEmit",
66
66
  "test:lint": "eslint src --max-warnings 0",
67
67
  "format": "prettier . --write"
68
- }
68
+ },
69
+ "readme": "# detype\n\n> Remove the types, keep the formatting\n\n```sh\nnpm i -g detype\n```\n\nSuppose you have a library that you want to provide usage examples for. **detype** can help you generate vanilla JavaScript samples from TypeScript samples automatically and remove the burden of maintaining two separate versions of what is essentially the same code.\n\nIt is a command line tool and a library that removes type annotations and other TypeScript specific syntax constructs and outputs vanilla JavaScript **without altering the source formatting** too much. It supports `.ts`, `.tsx`, as well as `.vue` files.\n\nIn other words, it turns this:\n\n```ts\nimport type { ParsedPath } from \"path\";\n\nlet x: string;\n\n// This comment should be kept\n\n// This comment should be deleted\n// Ditto for this\ninterface Foo {\n // This should go too\n bar: number;\n}\n\n// This comment should also be kept\nexport function bar(foo: Foo): Date {\n return new Date();\n}\n```\n\ninto this:\n\n```js\nlet x;\n\n// This comment should be kept\n\n// This comment should also be kept\nexport function bar(foo) {\n return new Date();\n}\n```\n\nThe output is very close to hand-written JavaScript, especially if you were already using Prettier for formatting.\n\n## Doesn't `tsc` already do that?\n\nThere are lots of tools for transpiling TypeScript into plain JavaScript (`tsc`, `babel`, `swc`, `esbuild`, `sucrase` etc.) but none of them is perfectly suitable for this specific use case. Most of them don't preserve the formatting at all. `sucrase` comes close, but it doesn't remove comments attached to TypeScript-only constructs.\n\n`detype` uses [Babel](https://babeljs.io/), a small Babel plugin to remove comments attached to TypeScript-only constructs, and [Prettier](https://prettier.io/) under the hood. For Vue files, it also uses the tools from the [VueDX project](https://github.com/vuedx/languagetools).\n\n## Magic comments\n\nSometimes you want the generated JavaScript to be slightly different than the TypeScript original. You can use the magic comments feature to achieve this:\n\nInput:\n\n```ts\n// @detype: replace\n// These two lines will be removed\nconsole.log(\"Hello from TypeScript\");\n// @detype: with\n// // Notice the double comments!\n// console.log(\"Hello from JavaScript\");\n// @detype: end\n```\n\nOutput:\n\n```js\n// Notice the double comments!\nconsole.log(\"Hello from JavaScript\");\n```\n\nIf you just want to remove the magic comments, you can use the `-m` CLI flag or the `removeMagicComments` function to generate uncluttered TypeScript like this:\n\n```ts\n// These two lines will be removed\nconsole.log(\"Hello from TypeScript\");\n```\n\n## System requirements\n\n`detype` requires Node version 12.22.7 or later.\n\n## CLI Usage\n\n```\ndetype [-m | --remove-magic-comments] <INPUT> [OUTPUT]\n\n INPUT Input file or directory\n\n OUTPUT Output file or directory\n (optional if it can be inferred and it won't overwrite the source file)\n\n -m, --remove-magic-comments\n Remove magic comments only, don't perform ts > js transform\n\ndetype [-v | --version]\n\n Print version and exit\n\ndetype [-h | --help]\n\n Print this help and exit\n```\n\n## Node API\n\n```ts\n// Transform TypeScript code into vanilla JavaScript without affecting the formatting\nfunction transform(\n // Source code\n code: string,\n // File name for the source\n fileName: string,\n // Options to pass to prettier\n prettierOptions?: PrettierOptions | null,\n): Promise<string>;\n\n// Transform the input file and write the output to another file\nfunction transformFile(\n inputFileName: string,\n outputFileName: string,\n): Promise<void>;\n\n// Remove magic comments without performing the TS to JS transform\nexport function removeMagicComments(\n // Source code\n code: string,\n // File name for the source\n fileName: string,\n // Options to pass to prettier\n prettierOptions?: PrettierOptions | null,\n): string;\n\n// Remove magic comments from the input file and write the output to another file\nexport function removeMagicCommentsFromFile(\n inputFileName: string,\n outputFileName: string,\n): Promise<void>;\n```\n\n## Change log\n### 0.4\n- feature: CLI support for removing magic comments\n- chore: Improve documentation\n\n### 0.3\n- feature: Magic comments\n- feature: Expose type declarations\n- fix: Better empty line handling\n\n### 0.2\n- feature: for Vue single file components\n\n### 0.1\n- Initial release\n\n## Credits\nFatih Aygün, under MIT License"
69
70
  }