bio-dts 0.8.1 → 0.10.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.
@@ -17,6 +17,7 @@ export default function generateTypes(fileNames, options) {
17
17
 
18
18
  const host = ts.createCompilerHost(options);
19
19
 
20
+ // @ts-expect-error
20
21
  host._readFile = host.readFile;
21
22
 
22
23
  /**
@@ -26,6 +27,7 @@ export default function generateTypes(fileNames, options) {
26
27
  */
27
28
  host.readFile = (fileName) => {
28
29
 
30
+ // @ts-expect-error
29
31
  let src = host._readFile(fileName);
30
32
 
31
33
  isVerbose(options, fileName) && console.debug('[generate-types] [pre]', fileName, src);
@@ -44,6 +46,7 @@ export default function generateTypes(fileNames, options) {
44
46
  return src;
45
47
  };
46
48
 
49
+ // @ts-expect-error
47
50
  host._writeFile = host.writeFile;
48
51
 
49
52
  host.writeFile = (fileName, text, ...args) => {
@@ -58,6 +61,7 @@ export default function generateTypes(fileNames, options) {
58
61
 
59
62
  isVerbose(options, fileName) && console.debug('[generate-types] [post] [generated]', fileName, text);
60
63
 
64
+ // @ts-expect-error
61
65
  host._writeFile(fileName, text, ...args);
62
66
  };
63
67
 
@@ -1,3 +1,28 @@
1
+ /**
2
+ * @typedef { {
3
+ * start: number,
4
+ * end: number,
5
+ * name: string,
6
+ * type?: {
7
+ * start: number,
8
+ * end: number,
9
+ * value: string
10
+ * },
11
+ * param: {
12
+ * start: number,
13
+ * end: number,
14
+ * name?: string,
15
+ * contents?: string,
16
+ * value: string
17
+ * },
18
+ * description?: {
19
+ * start: number,
20
+ * end: number,
21
+ * value: string
22
+ * }
23
+ * } } JsdocTag
24
+ */
25
+
1
26
  function skipWhitespace(str, pos) {
2
27
  let i = pos;
3
28
 
@@ -65,11 +90,20 @@ function findNewline(str, pos) {
65
90
  return i;
66
91
  }
67
92
 
93
+ /**
94
+ * @param {string} str
95
+ *
96
+ * @return {JsdocTag[]}
97
+ */
68
98
  export function parse(str) {
69
99
 
70
100
  var i = 0, j;
71
101
 
72
102
  var tags = [];
103
+
104
+ /**
105
+ * @type { Partial<JsdocTag> }
106
+ */
73
107
  var tag;
74
108
 
75
109
  while ((i = str.indexOf('@', i)) && i !== -1) {
@@ -133,7 +167,7 @@ export function parse(str) {
133
167
 
134
168
  tag.end = j;
135
169
 
136
- tags.push(tag);
170
+ tags.push(/** @type { JsdocTag } */ (tag));
137
171
 
138
172
  i = j + 1;
139
173
  }
@@ -1,6 +1,10 @@
1
1
  import { parser } from 'recast/parsers/babel.js';
2
2
  import getBabelOptions from 'recast/parsers/_babel_options.js';
3
3
 
4
+ /**
5
+ * @typedef { import('recast/parsers/_babel_options.js').Overrides } Overrides
6
+ */
7
+
4
8
  /**
5
9
  * @param {string} source
6
10
  * @param {Overrides} [options]
@@ -9,9 +9,14 @@ import {
9
9
  replace as replaceJSDoc
10
10
  } from './parsers/jsdoc.js';
11
11
 
12
+ /**
13
+ * @template T
14
+ *
15
+ * @typedef { import('./util.js').Path<T> } Path
16
+ */
12
17
 
13
18
  /**
14
- * @param { { name: string, comments?: any[] } }
19
+ * @param { { name: string, key?: { name?: string }, comments?: any[] } } m
15
20
  *
16
21
  * @return {boolean}
17
22
  */
@@ -136,7 +141,7 @@ export default function transform(src) {
136
141
  /**
137
142
  * Ensure optional args methods are properly escaped
138
143
  *
139
- * @param {import('./util.js').Path} nodePath
144
+ * @param {Path<any>} nodePath
140
145
  *
141
146
  * @return {any[]} replacements
142
147
  */
@@ -286,7 +291,7 @@ export default function transform(src) {
286
291
  * type Woop = import('./Woop').default;
287
292
  * ```
288
293
  *
289
- * @param {import('./util.js').Path} nodePath
294
+ * @param {Path<any>} nodePath
290
295
  *
291
296
  * @return {any[]} replacements
292
297
  */
@@ -309,7 +314,7 @@ export default function transform(src) {
309
314
  /**
310
315
  * Ensure that only documented method parameters are used.
311
316
  *
312
- * @param {Path} nodePath
317
+ * @param {Path<any>} nodePath
313
318
  *
314
319
  * @return {boolean} true if modified
315
320
  */
@@ -356,7 +361,7 @@ export default function transform(src) {
356
361
  * Our strategy is to parse for separate `@overlord` annotated tags,
357
362
  * use the meta-data, and generate a completely new method from it.
358
363
  *
359
- * @param {Path} nodePath
364
+ * @param {Path<any>} nodePath
360
365
  *
361
366
  * @return {boolean} true if modified
362
367
  */
@@ -485,6 +490,9 @@ declare function p${
485
490
 
486
491
  function cleanComment(comment) {
487
492
 
493
+ /**
494
+ * @type { [ { start: number, end: number }, replacement?: string ][] }
495
+ */
488
496
  const replacements = [];
489
497
 
490
498
  const doc = comment.value.replace(/\n\s+/g, '\n ');
@@ -525,7 +533,6 @@ declare function p${
525
533
  return null;
526
534
  } else {
527
535
  return b.commentBlock.from({
528
- type: 'CommentBlock',
529
536
  leading: true,
530
537
  value: newDoc
531
538
  });
@@ -533,7 +540,7 @@ declare function p${
533
540
  }
534
541
 
535
542
  /**
536
- * @param {import('./util.js').Path} nodePath
543
+ * @param {Path<any>} nodePath
537
544
  */
538
545
  function cleanComments(nodePath) {
539
546
 
@@ -552,21 +559,20 @@ declare function p${
552
559
  }
553
560
  }
554
561
 
555
- traverse(body, function(path) {
556
-
557
- const {
558
- value
559
- } = path;
562
+ function transformPath(path) {
560
563
 
561
564
  // filter private members
562
- if (!isPublic(value)) {
565
+ if (!isPublic(path.value)) {
563
566
  return replace(path);
564
567
  }
565
568
 
569
+ // generate overloads based on @overlord annotation
566
570
  if (generateOverloads(path)) {
567
571
  return false;
568
572
  }
569
573
 
574
+ // fix optional before required args
575
+ // (just fine in JavaScript)
570
576
  if (fixOptionalArgsMethods(path)) {
571
577
  return false;
572
578
  }
@@ -575,15 +581,27 @@ declare function p${
575
581
  cleanComments(path);
576
582
 
577
583
  fixTypeExport(path);
578
- });
584
+ }
585
+
586
+ const nodes = [ body ];
579
587
 
580
- for (const [ path, args ] of replacements) {
581
- try {
582
- path.replace(...args);
583
- } catch (err) {
584
- console.error('Failed to replace path', path, ...args, err);
588
+ while (nodes.length) {
589
+ const node = nodes.shift();
585
590
 
586
- throw error(path.value, 'failed to replace path: ' + err.message);
591
+ traverse(node, transformPath);
592
+
593
+ while (replacements.length) {
594
+ const [ path, args ] = replacements.shift();
595
+
596
+ try {
597
+ const replacedPaths = path.replace(...args);
598
+
599
+ nodes.push(...replacedPaths);
600
+ } catch (err) {
601
+ console.error('Failed to replace path', path, ...args, err);
602
+
603
+ throw error(path.value, 'failed to replace path: ' + err.message);
604
+ }
587
605
  }
588
606
  }
589
607
 
@@ -602,7 +620,7 @@ function traverse(path, cb) {
602
620
  }
603
621
 
604
622
  for (const key of keys(val).reverse()) {
605
- if ([ 'loc', 'start', 'end' ].includes(key)) {
623
+ if (typeof key === 'string' && [ 'loc', 'start', 'end' ].includes(key)) {
606
624
  continue;
607
625
  }
608
626
 
@@ -639,9 +657,9 @@ function getFunctionKind(node) {
639
657
  /**
640
658
  * Return host path for node (with attached comments).
641
659
  *
642
- * @param {Path} nodePath
660
+ * @param {Path<any>} nodePath
643
661
  *
644
- * @return {Path}
662
+ * @return {Path<any>}
645
663
  */
646
664
  function getHostPath(nodePath) {
647
665
  return [ 'ExportDefaultDeclaration', 'ExportNamedDeclaration' ].includes(nodePath.parentPath.value.type)
@@ -650,9 +668,9 @@ function getHostPath(nodePath) {
650
668
  }
651
669
 
652
670
  /**
653
- * @param {Node} node
671
+ * @param { { loc: { start: { line: number, column: number } } } } node
654
672
  *
655
- * @return {string}
673
+ * @return {Error}
656
674
  */
657
675
  function error(node, message) {
658
676
 
@@ -6,7 +6,6 @@ import {
6
6
 
7
7
  function superCall() {
8
8
  return b.expressionStatement.from({
9
- 'type': 'ExpressionStatement',
10
9
  'expression': {
11
10
  'type': 'CallExpression',
12
11
  'callee': {
@@ -21,7 +20,6 @@ function clazzConstructor(cls, comments) {
21
20
  const constructor = cls.ctor.value;
22
21
 
23
22
  return b.classMethod.from({
24
- 'type': 'ClassMethod',
25
23
  'static': false,
26
24
  'key': {
27
25
  'type': 'Identifier',
@@ -100,7 +98,6 @@ function clazzDefinition(cls, ctor) {
100
98
  });
101
99
 
102
100
  return b.classDeclaration.from({
103
- 'type': 'ClassDeclaration',
104
101
  'id': {
105
102
  'type': 'Identifier',
106
103
  'name': cls.name
@@ -153,6 +150,7 @@ function splitComment(cls) {
153
150
 
154
151
  /**
155
152
  * @param {string} src
153
+ *
156
154
  * @return {string}
157
155
  */
158
156
  export default function transform(src) {
@@ -162,21 +160,23 @@ export default function transform(src) {
162
160
 
163
161
  const inheritsImports = findInheritsImports(body);
164
162
 
165
- const classes = findConstructors(body);
166
-
167
163
  // query
168
- for (const cls of classes) {
169
- cls.members = [
170
- ...findEmbeddedMembers(cls),
171
- ...findProtoMembers(cls, body)
172
- ];
164
+ const classes = findConstructors(body).map(cls => {
165
+ return {
166
+ ...cls,
173
167
 
174
- cls.staticMembers = [
175
- ...findStaticMembers(cls, body)
176
- ];
168
+ members: [
169
+ ...findEmbeddedMembers(cls),
170
+ ...findProtoMembers(cls, body)
171
+ ],
177
172
 
178
- cls.superDeclaration = findSuperDeclarations(cls, body, inheritsImports);
179
- }
173
+ staticMembers: [
174
+ ...findStaticMembers(cls, body)
175
+ ],
176
+
177
+ superDeclaration: findSuperDeclarations(cls, body, inheritsImports)
178
+ };
179
+ });
180
180
 
181
181
  // transform
182
182
  for (const cls of classes) {
@@ -273,6 +273,15 @@ function findSuperDeclarations(cls, nodes, importDeclarations) {
273
273
 
274
274
  }
275
275
 
276
+ /**
277
+ * @param {any[]} nodes
278
+ *
279
+ * @return { {
280
+ * name: string,
281
+ * ctor: any,
282
+ * node: any
283
+ * }[] }
284
+ */
276
285
  function findConstructors(nodes) {
277
286
 
278
287
  const fns = matcher`
package/lib/util.js CHANGED
@@ -2,10 +2,8 @@ import { parse as recastParse, print as recastPrint } from 'recast';
2
2
  import { Path as PathConstructor } from 'ast-types';
3
3
 
4
4
  /**
5
- * @typedef { {
6
- * get(...any) => any,
7
- * value: any
8
- * } } Path
5
+ * @template T extends
6
+ * @typedef { import('ast-types/lib/path.js').Path<T> } Path
9
7
  */
10
8
 
11
9
  import * as typescriptParser from './parsers/typescript.js';
@@ -17,7 +15,7 @@ const formatOptions = {
17
15
  useTabs: false,
18
16
  reuseWhitespace: false,
19
17
  tabWidth: 2,
20
- quote: 'single'
18
+ quote: /** @type { 'single' } */ ('single')
21
19
  };
22
20
 
23
21
  /**
@@ -75,19 +73,21 @@ export function print(node) {
75
73
  }
76
74
 
77
75
  /**
78
- * @param {any} node
76
+ * @template V
79
77
  *
80
- * @return {Path}
78
+ * @param {V} node
79
+ *
80
+ * @return {Path<V>}
81
81
  */
82
82
  export function path(node) {
83
83
  return new PathConstructor(node);
84
84
  }
85
85
 
86
86
  /**
87
- * @param {string[]} strings
87
+ * @param {TemplateStringsArray} strings
88
88
  * @param {...any} args
89
89
  *
90
- * @return { (node) => [][] }
90
+ * @return { (node) => any[][] }
91
91
  */
92
92
  export function matcher(strings, ...args) {
93
93
 
@@ -102,9 +102,7 @@ export function matcher(strings, ...args) {
102
102
  return code;
103
103
  }, '');
104
104
 
105
- const ast = parse(code, {
106
- parser: typescriptParser
107
- });
105
+ const ast = parse(code);
108
106
 
109
107
  const body = path(ast).get('program', 'body');
110
108
 
@@ -187,11 +185,13 @@ export function matcher(strings, ...args) {
187
185
  }
188
186
 
189
187
  /**
190
- * @param {Path} node
191
- * @param {Path} expectedNode
192
- * @param {Path[]} results
188
+ * @template T
189
+ * @template V
190
+ * @param {Path<T>} node
191
+ * @param {Path<V>} expectedNode
192
+ * @param {Path<any>[]} results
193
193
  *
194
- * @return {Path[] || null}
194
+ * @return {Path<any>[] | null}
195
195
  */
196
196
  function matchNode(node, expectedNode, results = []) {
197
197
 
@@ -209,7 +209,7 @@ export function matcher(strings, ...args) {
209
209
  }
210
210
 
211
211
  for (const key of keys(expectedNode.value)) {
212
- if ([ 'loc', 'start', 'end' ].includes(key)) {
212
+ if (typeof key === 'string' && [ 'loc', 'start', 'end' ].includes(key)) {
213
213
  continue;
214
214
  }
215
215
 
@@ -241,13 +241,16 @@ export function matcher(strings, ...args) {
241
241
  DBG && console.log('BAIL no array match', key);
242
242
  return;
243
243
  }
244
- } else
245
- if (isNode(expectedVal.value)) {
244
+ }
245
+
246
+ else if (isNode(expectedVal.value)) {
246
247
  if (!matchNode(nodeVal, expectedVal, results)) {
247
248
  DBG && console.log('BAIL no match', key);
248
249
  return;
249
250
  }
250
- } else {
251
+ }
252
+
253
+ else {
251
254
  if (nodeVal.value !== expectedVal.value) {
252
255
  DBG && console.log('BAIL no primitive match', key);
253
256
  return;
package/package.json CHANGED
@@ -1,13 +1,18 @@
1
1
  {
2
2
  "name": "bio-dts",
3
- "version": "0.8.1",
3
+ "version": "0.10.0",
4
4
  "description": "Generate sane and clean types from JavaScript sources",
5
5
  "type": "module",
6
- "main": "index.js",
7
6
  "bin": "bin/cmd.js",
7
+ "exports": {
8
+ ".": "./index.js",
9
+ "./lib/*.js": "./lib/*.js",
10
+ "./package.json": "./package.json"
11
+ },
8
12
  "scripts": {
9
- "all": "npm run lint && npm run test && npm run test:dts",
13
+ "all": "run-s lint check-types test test:dts",
10
14
  "lint": "eslint .",
15
+ "check-types": "tsc --noEmit",
11
16
  "test": "mocha test",
12
17
  "test:dts": "node bin/cmd.js --outDir dist -r test/fixtures"
13
18
  },
@@ -18,16 +23,20 @@
18
23
  "author": "Nico Rehwaldt",
19
24
  "license": "MIT",
20
25
  "dependencies": {
21
- "@babel/parser": "^7.21.2",
22
- "recast": "^0.22.0",
26
+ "@babel/parser": "^7.23.9",
27
+ "recast": "^0.23.4",
23
28
  "tiny-glob": "^0.2.9"
24
29
  },
25
30
  "devDependencies": {
26
- "chai": "^4.3.7",
27
- "eslint": "^8.36.0",
31
+ "@babel/types": "^7.23.9",
32
+ "@types/mocha": "^10.0.6",
33
+ "@types/node": "^20.11.19",
34
+ "chai": "^5.1.0",
35
+ "eslint": "^8.56.0",
28
36
  "eslint-plugin-bpmn-io": "^1.0.0",
29
37
  "mocha": "^10.2.0",
30
- "typescript": "^5.0.2"
38
+ "npm-run-all2": "^6.1.2",
39
+ "typescript": "^5.3.3"
31
40
  },
32
41
  "files": [
33
42
  "bin",