bio-dts 0.2.0 → 0.3.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.
@@ -0,0 +1,159 @@
1
+ function skipWhitespace(str, pos) {
2
+ let i = pos;
3
+
4
+ let char;
5
+ for (; (char = str.charAt(i)) && char !== '\n' && /\s/.test(char); i++) {
6
+
7
+ // ignore
8
+ }
9
+
10
+ return i;
11
+ }
12
+
13
+ function skipText(str, pos) {
14
+ let i = pos;
15
+ let char;
16
+
17
+ for (; (char = str.charAt(i)) && /\S/.test(char); i++) {
18
+
19
+ // ignore
20
+ }
21
+
22
+ return i;
23
+ }
24
+
25
+ function findClose(str, pos, openChar, closeChar) {
26
+
27
+ if (str.charAt(pos) !== openChar) {
28
+ return false;
29
+ }
30
+
31
+ let char;
32
+
33
+ let i = pos;
34
+
35
+ let open = 0;
36
+
37
+ while ((char = str.charAt(i++))) {
38
+ switch (char) {
39
+ case openChar:
40
+ open++;
41
+ break;
42
+ case closeChar:
43
+ if (--open === 0) {
44
+ return {
45
+ start: pos,
46
+ end: i,
47
+ value: str.substring(pos, i)
48
+ };
49
+ }
50
+ break;
51
+ }
52
+ }
53
+ }
54
+
55
+ function findNewline(str, pos) {
56
+
57
+ let i = pos;
58
+ let char;
59
+
60
+ for (; (char = str.charAt(i)) && /[^\n]/.test(char); i++) {
61
+
62
+ // ignore
63
+ }
64
+
65
+ return i;
66
+ }
67
+
68
+ export function parse(str) {
69
+
70
+ var i = 0, j;
71
+
72
+ var tags = [];
73
+ var tag;
74
+
75
+ while ((i = str.indexOf('@', i)) && i !== -1) {
76
+ j = i + 1;
77
+ tag = {
78
+ start: i
79
+ };
80
+
81
+ // parse tag name
82
+ j = skipText(str, i);
83
+
84
+ tag.name = str.substring(i + 1, j);
85
+
86
+ i = skipWhitespace(str, j);
87
+
88
+ // parse type
89
+ if ([ 'param', 'return', 'returns', 'typedef' ].includes(tag.name)) {
90
+
91
+ let match = findClose(str, i, '{', '}');
92
+
93
+ if (match) {
94
+ tag.type = match;
95
+
96
+ i = skipWhitespace(str, match.end);
97
+ }
98
+ }
99
+
100
+ // parse param
101
+ if ([ 'param', 'typedef' ].includes(tag.name)) {
102
+
103
+ let match = tag.name === 'param' && findClose(str, i, '[', ']');
104
+
105
+ if (match) {
106
+ tag.param = match;
107
+
108
+ const contents = tag.param.contents = str.substring(match.start + 1, match.end - 1);
109
+ const idxEq = contents.indexOf('=');
110
+
111
+ tag.param.name = idxEq !== -1 ? contents.substring(0, idxEq) : contents;
112
+ } else {
113
+ j = skipText(str, i);
114
+
115
+ tag.param = {
116
+ start: i,
117
+ end: j,
118
+ name: str.substring(i, j),
119
+ value: str.substring(i, j)
120
+ };
121
+ }
122
+
123
+ i = skipWhitespace(str, tag.param.end);
124
+ }
125
+
126
+ j = findNewline(str, i);
127
+
128
+ tag.description = i !== j ? {
129
+ start: i,
130
+ end: j,
131
+ value: str.substring(i, j)
132
+ } : null;
133
+
134
+ tag.end = j;
135
+
136
+ tags.push(tag);
137
+
138
+ i = j + 1;
139
+ }
140
+
141
+ return tags;
142
+ }
143
+
144
+ export function dbg(str, pos) {
145
+
146
+ const arr = Array.from(str);
147
+
148
+ arr.splice(pos, 0, '|');
149
+
150
+ return arr.join('');
151
+ }
152
+
153
+ export function replace(str, range, contents) {
154
+ const arr = Array.from(str);
155
+
156
+ arr.splice(range.start, range.end - range.start, contents);
157
+
158
+ return arr.join('');
159
+ }
@@ -1,5 +1,14 @@
1
1
  import { isArray, isNode, keys, parseDts, path, print } from './util.js';
2
2
 
3
+ import {
4
+ builders as b
5
+ } from 'ast-types';
6
+
7
+ import {
8
+ parse as parseJSDoc,
9
+ replace as replaceJSDoc
10
+ } from './parsers/jsdoc.js';
11
+
3
12
 
4
13
  /**
5
14
  * @param { { name: string, comments?: any[] } }
@@ -28,35 +37,106 @@ export default function transform(src) {
28
37
  const ast = parseDts(src);
29
38
  const body = path(ast).get('program', 'body');
30
39
 
40
+ const replacements = [];
41
+
42
+ function replace(path, ...args) {
43
+ replacements.push([ path, args ]);
44
+
45
+ return false;
46
+ }
47
+
31
48
  traverse(body, function(path) {
32
49
 
50
+ const {
51
+ value
52
+ } = path;
53
+
33
54
  // filter private members
34
- if (!isPublic(path.value)) {
35
- path.replace();
55
+ if (!isPublic(value)) {
56
+ return replace(path);
36
57
  }
37
58
 
38
59
  // TODO(nikku): transform illegal typescript methods into override calls
60
+
61
+ // TODO(nikku): remove annotations
62
+ //
63
+ // * @typedef
64
+ // * @class
65
+ // * @constructor
66
+ // * @template
67
+ // * @method
68
+
69
+ const comments = path.get('comments') || { value: [] };
70
+
71
+ for (const key of keys(comments.value || []).reverse()) {
72
+
73
+ const comment = comments.get(key);
74
+
75
+ const replacements = [];
76
+
77
+ const doc = comment.value.value.replace(/\n\s+/g, '\n ');
78
+ const tags = parseJSDoc(doc);
79
+
80
+ for (const tag of tags) {
81
+ if (/class|constructor|template|method|typedef/.test(tag.name)) {
82
+ replacements.push([ { start: tag.start - 4, end: tag.end } ]);
83
+
84
+ continue;
85
+ }
86
+
87
+ if (tag.type) {
88
+ replacements.push([ { start: tag.type.start - 1, end: tag.type.end }, '' ]);
89
+ }
90
+
91
+ if (tag.param) {
92
+ replacements.push([ tag.param, tag.param.name ]);
93
+ }
94
+ }
95
+
96
+ const newDoc = replacements.slice().reverse().reduce((newDoc, r) => {
97
+
98
+ const [ { start, end }, replacement = '' ] = r;
99
+
100
+ return replaceJSDoc(newDoc, { start, end }, replacement);
101
+ }, doc);
102
+
103
+ // remove entirely, if empty
104
+ if (!newDoc.replace(/[/*\s]/g, '')) {
105
+ replace(comment);
106
+ } else {
107
+ replace(comment, b.commentBlock.from({
108
+ type: 'CommentBlock',
109
+ leading: true,
110
+ value: newDoc
111
+ }));
112
+ }
113
+ }
114
+
39
115
  });
40
116
 
117
+ for (const [ path, args ] of replacements) {
118
+ path.replace(...args);
119
+ }
120
+
41
121
  return print(ast).code;
42
122
  }
43
123
 
44
124
  function traverse(path, cb) {
45
- cb(path);
125
+ const val = path.value;
46
126
 
47
- if (path.parentPath) {
48
- const val = path.value;
49
-
50
- if (!isNode(val) && !isArray(val)) {
51
- return;
52
- }
127
+ if (!isNode(val) && !isArray(val)) {
128
+ return;
129
+ }
53
130
 
54
- for (const key of keys(val).reverse()) {
55
- if ([ 'loc', 'start', 'end' ].includes(key)) {
56
- continue;
57
- }
131
+ if (cb(path) === false) {
132
+ return;
133
+ }
58
134
 
59
- traverse(path.get(key), cb);
135
+ for (const key of keys(val).reverse()) {
136
+ if ([ 'loc', 'start', 'end' ].includes(key)) {
137
+ continue;
60
138
  }
139
+
140
+ traverse(path.get(key), cb);
61
141
  }
62
142
  }
@@ -146,19 +146,31 @@ export default function transform(src) {
146
146
  const ast = parse(src);
147
147
  const body = path(ast).get('program', 'body');
148
148
 
149
+ const inheritsImports = findInheritsImports(body);
150
+
149
151
  const classes = findConstructors(body);
150
152
 
153
+ // query
151
154
  for (const cls of classes) {
152
- const members = cls.members = [
155
+ cls.members = [
153
156
  ...findEmbeddedMethods(cls),
154
157
  ...findProtoMethods(cls, body)
155
158
  ];
156
159
 
157
- const staticMembers = cls.staticMembers = [
160
+ cls.staticMembers = [
158
161
  ...findStaticMembers(cls, body)
159
162
  ];
160
163
 
161
- const superDeclaration = cls.superDeclaration = findSuperDeclarations(cls, body);
164
+ cls.superDeclaration = findSuperDeclarations(cls, body, inheritsImports);
165
+ }
166
+
167
+ // transform
168
+ for (const cls of classes) {
169
+ const {
170
+ members,
171
+ staticMembers,
172
+ superDeclaration
173
+ } = cls;
162
174
 
163
175
  if (superDeclaration) {
164
176
  cls.ctor.get('body', 'body').unshift(superCall());
@@ -187,26 +199,34 @@ export default function transform(src) {
187
199
  });
188
200
 
189
201
  if (superDeclaration) {
190
- superDeclaration.importDeclarations.forEach(m => m.node.replace());
191
202
  superDeclaration.inheritsExpression.node.replace();
192
203
  }
193
204
  }
194
205
 
206
+ inheritsImports.forEach(m => m.node.replace());
207
+
195
208
  return print(ast).code;
196
209
  }
197
210
 
198
- function findSuperDeclarations(cls, nodes) {
199
-
211
+ function findInheritsImports(nodes) {
200
212
  const importsMatches = matcher`
201
213
  import $1 from 'inherits-browser';
202
214
  `;
203
215
 
204
- const importDeclarations = importsMatches(nodes);
216
+ return importsMatches(nodes).map(m => {
217
+ return {
218
+ node: m[0],
219
+ name: m[1].value.name
220
+ };
221
+ });
222
+ }
223
+
224
+ function findSuperDeclarations(cls, nodes, importDeclarations) {
205
225
 
206
- for (const [ _, identifier ] of importDeclarations) {
226
+ for (const { name: inheritsName } of importDeclarations) {
207
227
 
208
228
  const inheritsMatches = matcher`
209
- ${identifier.value.name}(${cls.name}, $1);
229
+ ${inheritsName}(${cls.name}, $1);
210
230
  `;
211
231
 
212
232
  const inheritsExpressions = inheritsMatches(nodes);
@@ -230,7 +250,6 @@ function findSuperDeclarations(cls, nodes) {
230
250
  const superCalls = superCallMatches(cls.ctor.get('body', 'body'));
231
251
 
232
252
  return {
233
- importDeclarations: importDeclarations.map(m => ({ node: m[0] })),
234
253
  superCalls: superCalls.map(m => ({ node: m[0] })),
235
254
  clazz,
236
255
  inheritsExpression
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bio-dts",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Generate sane and clean types from JavaScript sources",
5
5
  "type": "module",
6
6
  "main": "index.js",