@next-core/build-next-bricks 1.10.0 → 1.11.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/package.json +3 -3
- package/src/getTypeDeclaration.js +377 -0
- package/src/makeBrickManifest.js +236 -46
- package/src/scanBricks.js +136 -110
- package/src/utils.js +0 -227
package/src/makeBrickManifest.js
CHANGED
|
@@ -1,35 +1,67 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
import { parse } from "doctrine";
|
|
2
|
-
import { getTypeAnnotation } from "./
|
|
3
|
+
import { getTypeAnnotation } from "./getTypeDeclaration.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* @typedef {import("@next-core/brick-manifest").BrickManifest} BrickManifest
|
|
6
7
|
* @typedef {import("@next-core/brick-manifest").PropertyManifest} PropertyManifest
|
|
7
8
|
* @typedef {import("@next-core/brick-manifest").EventManifest} EventManifest
|
|
8
9
|
* @typedef {import("@next-core/brick-manifest").MethodManifest} MethodManifest
|
|
10
|
+
* @typedef {import("@next-core/brick-manifest").MethodParamManifest} MethodParamManifest
|
|
9
11
|
* @typedef {import("@next-core/brick-manifest").ProviderManifest} ProviderManifest
|
|
12
|
+
* @typedef {import("@next-core/brick-manifest").Annotation} Annotation
|
|
10
13
|
* @typedef {import("@babel/types").Node} Node
|
|
11
14
|
* @typedef {import("@babel/traverse").NodePath} NodePath
|
|
12
15
|
* @typedef {import("@babel/types").ClassDeclaration} ClassDeclaration
|
|
16
|
+
* @typedef {import("@babel/types").Identifier} Identifier
|
|
13
17
|
* @typedef {import("doctrine").Tag} Tag
|
|
18
|
+
* @typedef {BrickManifest & { types: BrickTypes; }} BrickManifestAndTypes
|
|
19
|
+
* @typedef {{ name: string; annotation?: Annotation }} BrickPropertyWithAnnotation
|
|
20
|
+
* @typedef {{ name: string; detail: { annotation: Annotation } }} BrickEventWithAnnotation
|
|
21
|
+
* @typedef {{ name: string; params: BrickMethodParamWithAnnotation[]; returns: { annotation?: Annotation } }} BrickMethodWithAnnotation
|
|
22
|
+
* @typedef {{ name: string; annotation?: Annotation }} BrickMethodParamWithAnnotation
|
|
23
|
+
* @typedef {{
|
|
24
|
+
* properties: BrickPropertyWithAnnotation[];
|
|
25
|
+
* events: BrickEventWithAnnotation[];
|
|
26
|
+
* methods: BrickMethodWithAnnotation[];
|
|
27
|
+
* usedReferences?: Set<string>;
|
|
28
|
+
* }} BrickTypes
|
|
29
|
+
* @typedef {ProviderManifest & {
|
|
30
|
+
* params: (MethodParamManifest & {
|
|
31
|
+
* annotation?: Annotation;
|
|
32
|
+
* })[];
|
|
33
|
+
* returns?: {
|
|
34
|
+
* description?: string;
|
|
35
|
+
* annotation?: Annotation;
|
|
36
|
+
* };
|
|
37
|
+
* typeParameters?: Annotation;
|
|
38
|
+
* usedReferences?: Set<string>;
|
|
39
|
+
* }} ProviderManifestAndTypes
|
|
14
40
|
*/
|
|
15
41
|
|
|
16
42
|
/**
|
|
17
43
|
* @param {string} name
|
|
18
44
|
* @param {NodePath} nodePath
|
|
19
|
-
* @param {string} source
|
|
20
|
-
* @
|
|
21
|
-
* @returns {BrickManifest}
|
|
45
|
+
* @param {string} source
|
|
46
|
+
* @returns {BrickManifestAndTypes}
|
|
22
47
|
*/
|
|
23
48
|
export default function makeBrickManifest(name, nodePath, source) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
49
|
+
const classPath =
|
|
50
|
+
/** @type {import("@babel/traverse").NodePath<ClassDeclaration>} */ (
|
|
51
|
+
nodePath.parentPath
|
|
52
|
+
);
|
|
53
|
+
/** @type {BrickManifestAndTypes} */
|
|
27
54
|
const manifest = {
|
|
28
55
|
name,
|
|
29
56
|
properties: [],
|
|
30
57
|
events: [],
|
|
31
58
|
slots: [],
|
|
32
59
|
methods: [],
|
|
60
|
+
types: {
|
|
61
|
+
properties: [],
|
|
62
|
+
events: [],
|
|
63
|
+
methods: [],
|
|
64
|
+
},
|
|
33
65
|
};
|
|
34
66
|
|
|
35
67
|
const docComment = findDocComment(nodePath, source);
|
|
@@ -52,7 +84,11 @@ export default function makeBrickManifest(name, nodePath, source) {
|
|
|
52
84
|
}
|
|
53
85
|
}
|
|
54
86
|
|
|
55
|
-
|
|
87
|
+
manifest.types.usedReferences = scanFields(
|
|
88
|
+
manifest,
|
|
89
|
+
classPath.node.body.body,
|
|
90
|
+
source
|
|
91
|
+
);
|
|
56
92
|
|
|
57
93
|
return manifest;
|
|
58
94
|
}
|
|
@@ -61,18 +97,74 @@ export default function makeBrickManifest(name, nodePath, source) {
|
|
|
61
97
|
* @param {string} name
|
|
62
98
|
* @param {NodePath} nodePath
|
|
63
99
|
* @param {string} source
|
|
64
|
-
* @returns {
|
|
100
|
+
* @returns {ProviderManifestAndTypes}
|
|
65
101
|
*/
|
|
66
102
|
export function makeProviderManifest(name, nodePath, source) {
|
|
67
|
-
/**
|
|
103
|
+
/**
|
|
104
|
+
* @type {ProviderManifestAndTypes}
|
|
105
|
+
*/
|
|
68
106
|
const manifest = {
|
|
69
107
|
name,
|
|
108
|
+
type: "provider",
|
|
109
|
+
params: [],
|
|
110
|
+
usedReferences: new Set(),
|
|
70
111
|
};
|
|
112
|
+
|
|
71
113
|
const docComment = findDocComment(nodePath, source);
|
|
72
114
|
if (docComment) {
|
|
73
115
|
manifest.description = docComment.description;
|
|
74
116
|
manifest.deprecated = getDeprecatedInfo(docComment.tags);
|
|
75
117
|
}
|
|
118
|
+
|
|
119
|
+
const fn = /** @type {import("@babel/types").FunctionDeclaration} */ (
|
|
120
|
+
nodePath.node
|
|
121
|
+
);
|
|
122
|
+
let index = 0;
|
|
123
|
+
for (const param of fn.params) {
|
|
124
|
+
const annotation = getTypeAnnotation(
|
|
125
|
+
param.typeAnnotation,
|
|
126
|
+
source,
|
|
127
|
+
manifest.usedReferences
|
|
128
|
+
);
|
|
129
|
+
if (param.type === "Identifier") {
|
|
130
|
+
manifest.params.push({
|
|
131
|
+
name: param.name,
|
|
132
|
+
description: docComment?.tags.find(
|
|
133
|
+
(tag) => tag.title === "param" && tag.name === param.name
|
|
134
|
+
)?.description,
|
|
135
|
+
annotation,
|
|
136
|
+
});
|
|
137
|
+
} else {
|
|
138
|
+
const paramTag = docComment?.tags.filter(
|
|
139
|
+
(tag) => tag.title === "param"
|
|
140
|
+
)?.[index];
|
|
141
|
+
manifest.params.push({
|
|
142
|
+
name: paramTag?.name ?? `param_${index + 1}`,
|
|
143
|
+
description: paramTag?.description,
|
|
144
|
+
isRestElement: param.type === "RestElement",
|
|
145
|
+
annotation,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
index++;
|
|
149
|
+
}
|
|
150
|
+
const returnAnnotation = getTypeAnnotation(
|
|
151
|
+
fn.returnType,
|
|
152
|
+
source,
|
|
153
|
+
manifest.usedReferences
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
manifest.returns = {
|
|
157
|
+
description: docComment?.tags.find((tag) => tag.title === "returns")
|
|
158
|
+
?.description,
|
|
159
|
+
annotation: returnAnnotation,
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
manifest.typeParameters = getTypeAnnotation(
|
|
163
|
+
fn.typeParameters,
|
|
164
|
+
source,
|
|
165
|
+
manifest.usedReferences
|
|
166
|
+
);
|
|
167
|
+
|
|
76
168
|
return manifest;
|
|
77
169
|
}
|
|
78
170
|
|
|
@@ -93,12 +185,14 @@ function findDocComment({ node, parentPath }, source) {
|
|
|
93
185
|
}
|
|
94
186
|
|
|
95
187
|
/**
|
|
96
|
-
* @param {
|
|
188
|
+
* @param {BrickManifestAndTypes} manifest
|
|
97
189
|
* @param {Node[]} nodes
|
|
98
190
|
* @param {string} source
|
|
99
|
-
* @
|
|
191
|
+
* @returns {Set<string>}
|
|
100
192
|
*/
|
|
101
|
-
function scanFields(manifest, nodes, source
|
|
193
|
+
function scanFields(manifest, nodes, source) {
|
|
194
|
+
/** @type {Set<string>} */
|
|
195
|
+
const usedReferences = new Set();
|
|
102
196
|
for (const node of nodes) {
|
|
103
197
|
if (node.type === "ClassAccessorProperty" && node.decorators?.length) {
|
|
104
198
|
for (const { expression } of node.decorators) {
|
|
@@ -110,7 +204,7 @@ function scanFields(manifest, nodes, source, referenceSet = new Set()) {
|
|
|
110
204
|
case "property": {
|
|
111
205
|
/** @type {PropertyManifest} */
|
|
112
206
|
const prop = {
|
|
113
|
-
name: node.key.name,
|
|
207
|
+
name: /** @type {Identifier} */ (node.key).name,
|
|
114
208
|
};
|
|
115
209
|
const docComment = parseDocComment(node, source);
|
|
116
210
|
if (docComment) {
|
|
@@ -148,12 +242,18 @@ function scanFields(manifest, nodes, source, referenceSet = new Set()) {
|
|
|
148
242
|
) {
|
|
149
243
|
const { typeAnnotation } = node.typeAnnotation;
|
|
150
244
|
prop.type = getTypeWithoutUndefined(typeAnnotation, source);
|
|
151
|
-
|
|
152
|
-
|
|
245
|
+
|
|
246
|
+
const annotation = getTypeAnnotation(
|
|
247
|
+
getNodeWithoutUndefined(typeAnnotation),
|
|
153
248
|
source,
|
|
154
|
-
|
|
249
|
+
usedReferences
|
|
155
250
|
);
|
|
156
|
-
|
|
251
|
+
if (annotation) {
|
|
252
|
+
manifest.types.properties.push({
|
|
253
|
+
name: prop.name,
|
|
254
|
+
annotation,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
157
257
|
}
|
|
158
258
|
if (node.value && !prop.default) {
|
|
159
259
|
prop.default = source.substring(
|
|
@@ -167,7 +267,7 @@ function scanFields(manifest, nodes, source, referenceSet = new Set()) {
|
|
|
167
267
|
|
|
168
268
|
case "event": {
|
|
169
269
|
/** @type {EventManifest} */
|
|
170
|
-
const event = {};
|
|
270
|
+
const event = { name: undefined };
|
|
171
271
|
|
|
172
272
|
// Find out the `type` option for the event.
|
|
173
273
|
if (expression.arguments.length > 0) {
|
|
@@ -190,7 +290,9 @@ function scanFields(manifest, nodes, source, referenceSet = new Set()) {
|
|
|
190
290
|
}
|
|
191
291
|
if (event.name === undefined) {
|
|
192
292
|
throw new Error(
|
|
193
|
-
`Invalid @event() call: no literal type option in event '${
|
|
293
|
+
`Invalid @event() call: no literal type option in event '${
|
|
294
|
+
/** @type {Identifier} */ (node.key).name
|
|
295
|
+
}'`
|
|
194
296
|
);
|
|
195
297
|
}
|
|
196
298
|
const docComment = parseDocComment(node, source);
|
|
@@ -218,12 +320,21 @@ function scanFields(manifest, nodes, source, referenceSet = new Set()) {
|
|
|
218
320
|
const param = typeAnnotation.typeParameters.params[0];
|
|
219
321
|
event.detail ??= {};
|
|
220
322
|
event.detail.type = source.substring(param.start, param.end);
|
|
221
|
-
|
|
323
|
+
|
|
324
|
+
const annotation = getTypeAnnotation(
|
|
222
325
|
param,
|
|
223
326
|
source,
|
|
224
|
-
|
|
327
|
+
usedReferences
|
|
225
328
|
);
|
|
226
|
-
|
|
329
|
+
|
|
330
|
+
if (annotation) {
|
|
331
|
+
manifest.types.events.push({
|
|
332
|
+
name: event.name,
|
|
333
|
+
detail: {
|
|
334
|
+
annotation,
|
|
335
|
+
},
|
|
336
|
+
});
|
|
337
|
+
}
|
|
227
338
|
}
|
|
228
339
|
}
|
|
229
340
|
manifest.events.push(event);
|
|
@@ -241,40 +352,99 @@ function scanFields(manifest, nodes, source, referenceSet = new Set()) {
|
|
|
241
352
|
) {
|
|
242
353
|
/** @type {MethodManifest} */
|
|
243
354
|
const method = {
|
|
244
|
-
name: node.key.name,
|
|
355
|
+
name: /** @type {Identifier} */ (node.key).name,
|
|
245
356
|
params: [],
|
|
246
357
|
};
|
|
247
358
|
const docComment = parseDocComment(node, source);
|
|
248
359
|
if (docComment) {
|
|
249
360
|
method.description = docComment.description;
|
|
250
361
|
method.deprecated = getDeprecatedInfo(docComment.tags);
|
|
362
|
+
method.returns = {
|
|
363
|
+
description: docComment.tags.find(
|
|
364
|
+
(tag) => tag.title === "returns"
|
|
365
|
+
)?.description,
|
|
366
|
+
};
|
|
251
367
|
}
|
|
368
|
+
|
|
369
|
+
let index = 0;
|
|
370
|
+
/** @type {BrickMethodParamWithAnnotation[]} */
|
|
371
|
+
const typedParams = [];
|
|
252
372
|
for (const param of node.params) {
|
|
253
|
-
|
|
373
|
+
const typeAnnotation =
|
|
374
|
+
/** @type {Identifier} */
|
|
375
|
+
(param).typeAnnotation;
|
|
376
|
+
const annotation = getTypeAnnotation(
|
|
377
|
+
typeAnnotation,
|
|
378
|
+
source,
|
|
379
|
+
usedReferences
|
|
380
|
+
);
|
|
381
|
+
const paramType =
|
|
382
|
+
typeAnnotation.type === "TSTypeAnnotation"
|
|
383
|
+
? source.substring(
|
|
384
|
+
typeAnnotation.typeAnnotation.start,
|
|
385
|
+
typeAnnotation.typeAnnotation.end
|
|
386
|
+
)
|
|
387
|
+
: undefined;
|
|
388
|
+
/** @type {string} */
|
|
389
|
+
let paramName;
|
|
390
|
+
if (param.type === "Identifier") {
|
|
391
|
+
paramName = param.name;
|
|
392
|
+
method.params.push({
|
|
393
|
+
name: paramName,
|
|
394
|
+
description: docComment?.tags.find(
|
|
395
|
+
(tag) => tag.title === "param" && tag.name === param.name
|
|
396
|
+
)?.description,
|
|
397
|
+
type: paramType,
|
|
398
|
+
});
|
|
399
|
+
} else {
|
|
400
|
+
const paramTag = docComment?.tags.filter(
|
|
401
|
+
(tag) => tag.title === "param"
|
|
402
|
+
)?.[index];
|
|
403
|
+
paramName = paramTag?.name ?? `param_${index + 1}`;
|
|
404
|
+
method.params.push({
|
|
405
|
+
name: paramName,
|
|
406
|
+
description: paramTag?.description,
|
|
407
|
+
type: paramType,
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
typedParams.push({
|
|
411
|
+
name: paramName,
|
|
412
|
+
annotation,
|
|
413
|
+
});
|
|
414
|
+
index++;
|
|
254
415
|
}
|
|
416
|
+
|
|
417
|
+
/** @type {{ annotation?: Annotation }} */
|
|
418
|
+
const typedReturns = {};
|
|
255
419
|
if (node.returnType && node.returnType.type === "TSTypeAnnotation") {
|
|
256
420
|
const { typeAnnotation } = node.returnType;
|
|
257
|
-
method.
|
|
258
|
-
|
|
259
|
-
typeAnnotation.start,
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
421
|
+
method.returns = {
|
|
422
|
+
...method.returns,
|
|
423
|
+
type: source.substring(typeAnnotation.start, typeAnnotation.end),
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
typedReturns.annotation = getTypeAnnotation(
|
|
263
427
|
typeAnnotation,
|
|
264
428
|
source,
|
|
265
|
-
|
|
429
|
+
usedReferences
|
|
266
430
|
);
|
|
267
|
-
method.return.reference = [...referenceSet];
|
|
268
431
|
}
|
|
432
|
+
manifest.types.methods.push({
|
|
433
|
+
name: method.name,
|
|
434
|
+
params: typedParams,
|
|
435
|
+
returns: typedReturns,
|
|
436
|
+
});
|
|
269
437
|
manifest.methods.push(method);
|
|
270
438
|
}
|
|
271
439
|
}
|
|
272
440
|
}
|
|
273
441
|
}
|
|
442
|
+
|
|
443
|
+
return usedReferences;
|
|
274
444
|
}
|
|
275
445
|
|
|
276
446
|
/**
|
|
277
|
-
* @param {Node
|
|
447
|
+
* @param {Node} node
|
|
278
448
|
* @param {string} source
|
|
279
449
|
*/
|
|
280
450
|
export function parseDocComment(node, source) {
|
|
@@ -290,6 +460,21 @@ export function parseDocComment(node, source) {
|
|
|
290
460
|
}
|
|
291
461
|
}
|
|
292
462
|
|
|
463
|
+
/**
|
|
464
|
+
* @param {Node} node
|
|
465
|
+
* @param {string} source
|
|
466
|
+
* @returns {undefined | { description?: string; deprecated?: boolean | string; }}
|
|
467
|
+
*/
|
|
468
|
+
export function parseTypeComment(node, source) {
|
|
469
|
+
const docComment = parseDocComment(node, source);
|
|
470
|
+
if (docComment) {
|
|
471
|
+
return {
|
|
472
|
+
description: docComment.description,
|
|
473
|
+
deprecated: getDeprecatedInfo(docComment.tags),
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
293
478
|
/**
|
|
294
479
|
* @param {Node} node
|
|
295
480
|
* @param {string} source
|
|
@@ -309,20 +494,25 @@ function getTypeWithoutUndefined(node, source) {
|
|
|
309
494
|
}
|
|
310
495
|
|
|
311
496
|
/**
|
|
312
|
-
* @param {
|
|
313
|
-
* @
|
|
314
|
-
* @param {Set<string} set
|
|
497
|
+
* @param {Node} node
|
|
498
|
+
* @returns {Node}
|
|
315
499
|
*/
|
|
316
|
-
function
|
|
317
|
-
if (
|
|
318
|
-
|
|
319
|
-
type
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
500
|
+
function getNodeWithoutUndefined(node) {
|
|
501
|
+
if (node.type === "TSUnionType") {
|
|
502
|
+
const filteredTypes = node.types.filter(
|
|
503
|
+
(type) => type.type !== "TSUndefinedKeyword"
|
|
504
|
+
);
|
|
505
|
+
if (filteredTypes.length < node.types.length) {
|
|
506
|
+
if (filteredTypes.length === 1) {
|
|
507
|
+
return filteredTypes[0];
|
|
508
|
+
}
|
|
509
|
+
return {
|
|
510
|
+
...node,
|
|
511
|
+
types: filteredTypes,
|
|
512
|
+
};
|
|
513
|
+
}
|
|
324
514
|
}
|
|
325
|
-
return
|
|
515
|
+
return node;
|
|
326
516
|
}
|
|
327
517
|
|
|
328
518
|
/**
|