@ui5/webcomponents-tools 2.16.0-rc.0 → 2.16.0-rc.1
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/CHANGELOG.md +11 -0
- package/components-package/nps.js +0 -1
- package/lib/cem/cem.js +1 -1
- package/lib/cem/patch/@custom-elements-manifest/analyzer/cli.js +128 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/package.json +59 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/browser-entrypoint.js +23 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/create.js +117 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/arrow-function.js +26 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/class-jsdoc.js +157 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/classes.js +20 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createArrowFunction.js +17 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createAttribute.js +24 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createClass.js +301 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createClassField.js +26 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createFunctionLike.js +73 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createMixin.js +33 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createVariable.js +22 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/handlers.js +338 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/custom-elements-define-calls.js +90 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/exports.js +156 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/function-like.js +24 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/mixins.js +29 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/reexported-wrapped-mixin-exports.js +84 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/variables.js +34 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/collect-phase/collect-imports.js +101 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/catalyst/catalyst.js +11 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/catalyst/controller.js +34 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/catalyst-major-2/catalyst.js +11 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/catalyst-major-2/controller.js +34 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/decorators/attr.js +53 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/decorators/custom-element-decorator.js +36 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/fast/fast.js +7 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/lit.js +13 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/member-denylist.js +21 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/method-denylist.js +20 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/property-decorator.js +94 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/static-properties.js +121 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/utils.js +66 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/stencil/stencil.js +129 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/index.js +80 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/link-phase/cleanup-classes.js +25 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/link-phase/field-denylist.js +22 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/link-phase/method-denylist.js +25 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/post-processing/apply-inheritance.js +78 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/post-processing/is-custom-element.js +34 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/post-processing/link-class-to-tagname.js +27 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/post-processing/remove-unexported-declarations.js +23 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/post-processing/resolve-initializers.js +52 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/ast-helpers.js +186 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/cli-helpers.js +164 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/exports.js +44 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/find-external-manifests.js +67 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/imports.js +25 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/index.js +71 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/jsdoc.js +19 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/manifest-helpers.js +194 -0
- package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/mixins.js +112 -0
- package/package.json +3 -3
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import { createFunctionLike } from './createFunctionLike.js';
|
|
3
|
+
import { createAttribute, createAttributeFromField } from './createAttribute.js';
|
|
4
|
+
import { createField } from './createClassField.js';
|
|
5
|
+
import { handleHeritage, handleJsDoc, handleAttrJsDoc, handleTypeInference, handleDefaultValue } from './handlers.js';
|
|
6
|
+
import { hasAttrAnnotation, hasIgnoreJSDoc, isDispatchEvent, isBindCall, isProperty, isReturnStatement } from '../../../utils/ast-helpers.js';
|
|
7
|
+
import { resolveModuleOrPackageSpecifier } from '../../../utils/index.js';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Creates a classDoc
|
|
12
|
+
*/
|
|
13
|
+
export function createClass(node, moduleDoc, context) {
|
|
14
|
+
let classTemplate = {
|
|
15
|
+
kind: 'class',
|
|
16
|
+
description: '',
|
|
17
|
+
/**
|
|
18
|
+
* In case of a class node?.name?.getText()
|
|
19
|
+
* In case of a mixin node?.parent?.parent?.name?.getText()
|
|
20
|
+
*/
|
|
21
|
+
name: node?.name?.getText() || node?.parent?.parent?.name?.getText() || '',
|
|
22
|
+
cssProperties: [],
|
|
23
|
+
cssParts: [],
|
|
24
|
+
slots: [],
|
|
25
|
+
members: [],
|
|
26
|
+
events: [],
|
|
27
|
+
attributes: [],
|
|
28
|
+
cssStates: [],
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
node?.members?.forEach(member => {
|
|
32
|
+
/**
|
|
33
|
+
* Handle attributes
|
|
34
|
+
*/
|
|
35
|
+
if (isProperty(member)) {
|
|
36
|
+
if (member?.name?.getText() === 'observedAttributes') {
|
|
37
|
+
/**
|
|
38
|
+
* @example static observedAttributes
|
|
39
|
+
*/
|
|
40
|
+
if (ts.isPropertyDeclaration(member)) {
|
|
41
|
+
member?.initializer?.elements?.forEach((element) => {
|
|
42
|
+
if (ts.isStringLiteral(element)) {
|
|
43
|
+
const attribute = createAttribute(element);
|
|
44
|
+
classTemplate.attributes.push(attribute);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @example static get observedAttributes() {}
|
|
51
|
+
*/
|
|
52
|
+
if (ts.isGetAccessor(member)) {
|
|
53
|
+
const returnStatement = member?.body?.statements?.find(isReturnStatement);
|
|
54
|
+
|
|
55
|
+
returnStatement?.expression?.elements?.forEach((element) => {
|
|
56
|
+
if (ts.isStringLiteral(element)) {
|
|
57
|
+
const attribute = createAttribute(element);
|
|
58
|
+
classTemplate.attributes.push(attribute);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Second pass through a class's members.
|
|
68
|
+
* We do this in two passes, because we need to know whether or not a class has any
|
|
69
|
+
* attributes, so we handle those first.
|
|
70
|
+
*/
|
|
71
|
+
node?.members?.forEach(member => {
|
|
72
|
+
/**
|
|
73
|
+
* Handle class methods
|
|
74
|
+
*/
|
|
75
|
+
if (ts.isMethodDeclaration(member) && !hasIgnoreJSDoc(member)) {
|
|
76
|
+
const method = createFunctionLike(member);
|
|
77
|
+
classTemplate.members.push(method);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Handle fields
|
|
82
|
+
*/
|
|
83
|
+
if (isProperty(member) && !hasIgnoreJSDoc(member)) {
|
|
84
|
+
const field = createField(member);
|
|
85
|
+
|
|
86
|
+
/** If a member has only a getAccessor, it means it's readonly */
|
|
87
|
+
if(ts.isGetAccessor(member)) {
|
|
88
|
+
const hasSetter = node.members.some(m => ts.isSetAccessor(m) && m.name.getText() === field.name);
|
|
89
|
+
if(!hasSetter) {
|
|
90
|
+
field.readonly = true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Flag class fields that get assigned a variable, so we can resolve it later (in the RESOLVE-INITIALIZERS plugin) */
|
|
95
|
+
if (member?.initializer?.kind === ts.SyntaxKind.Identifier) {
|
|
96
|
+
field.resolveInitializer = {
|
|
97
|
+
...resolveModuleOrPackageSpecifier(moduleDoc, context, member?.initializer?.getText()),
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Handle @attr
|
|
103
|
+
* If a field has a @attr annotation, also create an attribute for it
|
|
104
|
+
*/
|
|
105
|
+
if (hasAttrAnnotation(member)) {
|
|
106
|
+
let attribute = createAttributeFromField(field);
|
|
107
|
+
attribute = handleAttrJsDoc(member, attribute);
|
|
108
|
+
field.attribute = attribute.name;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* If the attribute already exists, merge it together with the extra
|
|
112
|
+
* information we got from the field (like type, summary, description, etc)
|
|
113
|
+
*/
|
|
114
|
+
let attrAlreadyExists = classTemplate.attributes.find(attr => attr.name === attribute.name);
|
|
115
|
+
|
|
116
|
+
if (attrAlreadyExists) {
|
|
117
|
+
classTemplate.attributes = classTemplate.attributes.map(attr => {
|
|
118
|
+
return attr.name === attribute.name ? { ...attrAlreadyExists, ...attribute } : attr;
|
|
119
|
+
});
|
|
120
|
+
} else {
|
|
121
|
+
classTemplate.attributes.push(attribute);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* A class can have a static prop and an instance prop with the same name,
|
|
127
|
+
* both should be output in the CEM
|
|
128
|
+
*
|
|
129
|
+
* If not a static prop, we merge getter and setter pairs here
|
|
130
|
+
*/
|
|
131
|
+
if (field?.static) {
|
|
132
|
+
classTemplate.members.push(field);
|
|
133
|
+
} else {
|
|
134
|
+
const fieldExists = classTemplate.members
|
|
135
|
+
.filter(mem => !mem?.static)
|
|
136
|
+
.find(mem => mem?.name === member?.name?.getText());
|
|
137
|
+
|
|
138
|
+
if (fieldExists) {
|
|
139
|
+
classTemplate.members = classTemplate.members.map(mem => mem?.name === member?.name?.getText() && !mem?.static ? { ...mem, ...field } : mem);
|
|
140
|
+
} else {
|
|
141
|
+
classTemplate.members.push(field);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Handle events
|
|
148
|
+
*
|
|
149
|
+
* In order to find `this.dispatchEvent` calls, we have to traverse a method's AST
|
|
150
|
+
*/
|
|
151
|
+
if (ts.isMethodDeclaration(member)) {
|
|
152
|
+
eventsVisitor(member, classTemplate);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
getDefaultValuesFromConstructorVisitor(node, classTemplate, context);
|
|
157
|
+
|
|
158
|
+
classTemplate.members = classTemplate?.members?.filter(mem => !mem.ignore);
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Inheritance
|
|
162
|
+
*/
|
|
163
|
+
classTemplate = handleHeritage(classTemplate, moduleDoc, context, node);
|
|
164
|
+
|
|
165
|
+
return classTemplate;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function eventsVisitor(source, classTemplate) {
|
|
169
|
+
visitNode(source);
|
|
170
|
+
|
|
171
|
+
function visitNode(node) {
|
|
172
|
+
switch (node.kind) {
|
|
173
|
+
case ts.SyntaxKind.CallExpression:
|
|
174
|
+
|
|
175
|
+
/** If callexpression is `this.dispatchEvent` */
|
|
176
|
+
if (isDispatchEvent(node) && !hasIgnoreJSDoc(node.parent)) {
|
|
177
|
+
node?.arguments?.forEach((arg) => {
|
|
178
|
+
if (arg.kind === ts.SyntaxKind.NewExpression) {
|
|
179
|
+
/** e.g. `selected-changed` */
|
|
180
|
+
const eventName = arg?.arguments?.[0]?.text;
|
|
181
|
+
/**
|
|
182
|
+
* Check if event already exists
|
|
183
|
+
*/
|
|
184
|
+
const eventExists = classTemplate?.events?.some(event => event.name === eventName);
|
|
185
|
+
|
|
186
|
+
if (!eventExists) {
|
|
187
|
+
let eventDoc = {
|
|
188
|
+
...(eventName ? { name: eventName } : {}),
|
|
189
|
+
type: {
|
|
190
|
+
text: arg.expression.text,
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
eventDoc = handleJsDoc(eventDoc, node?.parent);
|
|
195
|
+
delete eventDoc.privacy;
|
|
196
|
+
classTemplate.events.push(eventDoc);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
ts.forEachChild(node, visitNode);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function getDefaultValuesFromConstructorVisitor(source, classTemplate, context) {
|
|
209
|
+
visitNode(source);
|
|
210
|
+
|
|
211
|
+
function visitNode(node) {
|
|
212
|
+
switch (node.kind) {
|
|
213
|
+
case ts.SyntaxKind.Constructor:
|
|
214
|
+
/**
|
|
215
|
+
* For every member that was added in the classDoc, we want to add a default value if we can
|
|
216
|
+
* To do this, we visit a class's constructor, and loop through the statements
|
|
217
|
+
*/
|
|
218
|
+
node.body?.statements?.filter((statement) => statement.kind === ts.SyntaxKind.ExpressionStatement)
|
|
219
|
+
.filter((statement) => statement.expression.kind === ts.SyntaxKind.BinaryExpression)
|
|
220
|
+
.forEach((statement) => mapClassMember(source, classTemplate, context, node, statement, statement.expression));
|
|
221
|
+
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
ts.forEachChild(node, visitNode);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function mapClassMember(source, classTemplate, context, node, statement, expression) {
|
|
230
|
+
let existingMember = classTemplate?.members?.find(member => expression?.left?.name?.getText() === member.name && member.kind === 'field');
|
|
231
|
+
|
|
232
|
+
// If the source is minified, or otherwise has a comma separated prop initialization
|
|
233
|
+
if (expression?.operatorToken?.kind === ts.SyntaxKind.CommaToken) {
|
|
234
|
+
if (expression.left.kind === ts.SyntaxKind.BinaryExpression) {
|
|
235
|
+
mapClassMember(source, classTemplate, context, node, statement, expression.left);
|
|
236
|
+
}
|
|
237
|
+
if (expression.right.kind === ts.SyntaxKind.BinaryExpression) {
|
|
238
|
+
mapClassMember(source, classTemplate, context, node, statement, expression.right);
|
|
239
|
+
}
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (!existingMember) {
|
|
244
|
+
if (hasIgnoreJSDoc(statement)) return;
|
|
245
|
+
if (isBindCall(statement)) return;
|
|
246
|
+
|
|
247
|
+
existingMember = {
|
|
248
|
+
kind: 'field',
|
|
249
|
+
name: expression?.left?.name?.getText(),
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if(!classTemplate.members){
|
|
253
|
+
classTemplate.members = [];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
classTemplate.members.push(existingMember);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (existingMember) {
|
|
260
|
+
if (hasIgnoreJSDoc(statement)) {
|
|
261
|
+
// schedule for deletion
|
|
262
|
+
existingMember.ignore = true;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (!existingMember?.type) {
|
|
266
|
+
existingMember = handleTypeInference(existingMember, expression?.right);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
existingMember = handleJsDoc(existingMember, statement);
|
|
270
|
+
existingMember = handleDefaultValue(existingMember, statement, expression);
|
|
271
|
+
|
|
272
|
+
/** Flag class fields that get assigned a variable, so we can resolve it later (in the RESOLVE-INITIALIZERS plugin) */
|
|
273
|
+
if (expression?.right?.kind === ts.SyntaxKind.Identifier) {
|
|
274
|
+
existingMember.resolveInitializer = {
|
|
275
|
+
...resolveModuleOrPackageSpecifier({ path: source.getSourceFile().fileName }, context, expression?.right?.getText()),
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (hasAttrAnnotation(statement)) {
|
|
280
|
+
const field = existingMember
|
|
281
|
+
let attribute = createAttributeFromField(field);
|
|
282
|
+
attribute = handleAttrJsDoc(statement, attribute);
|
|
283
|
+
|
|
284
|
+
field.attribute = attribute.name;
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* If the attribute already exists, merge it together with the extra
|
|
288
|
+
* information we got from the field (like type, summary, description, etc)
|
|
289
|
+
*/
|
|
290
|
+
let attrAlreadyExists = classTemplate.attributes.find(attr => attr.name === attribute.name);
|
|
291
|
+
|
|
292
|
+
if (attrAlreadyExists) {
|
|
293
|
+
classTemplate.attributes = classTemplate.attributes.map(attr => {
|
|
294
|
+
return attr.name === attribute.name ? { ...attrAlreadyExists, ...attribute } : attr;
|
|
295
|
+
});
|
|
296
|
+
} else {
|
|
297
|
+
classTemplate.attributes.push(attribute);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
handleDefaultValue,
|
|
3
|
+
handleExplicitType,
|
|
4
|
+
handleJsDoc,
|
|
5
|
+
handleModifiers,
|
|
6
|
+
handlePrivateMember,
|
|
7
|
+
handleTypeInference,
|
|
8
|
+
handleWellKnownTypes
|
|
9
|
+
} from './handlers.js';
|
|
10
|
+
|
|
11
|
+
export function createField(node) {
|
|
12
|
+
let fieldTemplate = {
|
|
13
|
+
kind: 'field',
|
|
14
|
+
name: node?.name?.getText() || '',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
fieldTemplate = handlePrivateMember(fieldTemplate, node);
|
|
18
|
+
fieldTemplate = handleTypeInference(fieldTemplate, node);
|
|
19
|
+
fieldTemplate = handleExplicitType(fieldTemplate, node);
|
|
20
|
+
fieldTemplate = handleModifiers(fieldTemplate, node);
|
|
21
|
+
fieldTemplate = handleDefaultValue(fieldTemplate, node);
|
|
22
|
+
fieldTemplate = handleWellKnownTypes(fieldTemplate, node);
|
|
23
|
+
fieldTemplate = handleJsDoc(fieldTemplate, node);
|
|
24
|
+
|
|
25
|
+
return fieldTemplate;
|
|
26
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import { has } from '../../../utils/index.js';
|
|
3
|
+
import { handleModifiers, handleJsDoc } from './handlers.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a functionLike, does _not_ handle arrow functions
|
|
7
|
+
*/
|
|
8
|
+
export function createFunctionLike(node) {
|
|
9
|
+
let functionLikeTemplate = {
|
|
10
|
+
kind: '',
|
|
11
|
+
name: node?.name?.getText() || ''
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
functionLikeTemplate = handleKind(functionLikeTemplate, node);
|
|
15
|
+
functionLikeTemplate = handleModifiers(functionLikeTemplate, node);
|
|
16
|
+
functionLikeTemplate = handleParametersAndReturnType(functionLikeTemplate, node);
|
|
17
|
+
functionLikeTemplate = handleJsDoc(functionLikeTemplate, node);
|
|
18
|
+
|
|
19
|
+
return functionLikeTemplate;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Determine the kind of the functionLike, either `'function'` or `'method'`
|
|
24
|
+
*/
|
|
25
|
+
export function handleKind(functionLike, node) {
|
|
26
|
+
switch(node.kind) {
|
|
27
|
+
case ts.SyntaxKind.FunctionDeclaration:
|
|
28
|
+
functionLike.kind = 'function';
|
|
29
|
+
break;
|
|
30
|
+
case ts.SyntaxKind.MethodDeclaration:
|
|
31
|
+
functionLike.kind = 'method';
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
return functionLike;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Handle a functionLikes return type and parameters/parameter types
|
|
39
|
+
*/
|
|
40
|
+
export function handleParametersAndReturnType(functionLike, node) {
|
|
41
|
+
if(node?.type) {
|
|
42
|
+
functionLike.return = {
|
|
43
|
+
type: { text: node.type.getText() }
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const parameters = [];
|
|
48
|
+
node?.parameters?.forEach((param) => {
|
|
49
|
+
const parameter = {
|
|
50
|
+
name: param.name.getText(),
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if(param?.initializer) {
|
|
54
|
+
parameter.default = param.initializer.getText();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if(param?.questionToken) {
|
|
58
|
+
parameter.optional = true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if(param?.type) {
|
|
62
|
+
parameter.type = {text: param.type.getText() }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
parameters.push(parameter);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if(has(parameters)) {
|
|
69
|
+
functionLike.parameters = parameters;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return functionLike;
|
|
73
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createClass } from './createClass.js';
|
|
2
|
+
import { handleParametersAndReturnType } from './createFunctionLike.js';
|
|
3
|
+
import { handleJsDoc } from './handlers.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Takes a mixinFunctionNode, which is the function/arrow function containing the mixin class
|
|
7
|
+
* and the actual class node returned by the mixin declaration
|
|
8
|
+
*/
|
|
9
|
+
export function createMixin(mixinFunctionNode, mixinClassNode, moduleDoc, context) {
|
|
10
|
+
let mixinTemplate = createClass(mixinClassNode, moduleDoc, context);
|
|
11
|
+
|
|
12
|
+
mixinTemplate = handleParametersAndReturnType(mixinTemplate, mixinFunctionNode?.declarationList?.declarations?.[0]?.initializer || mixinFunctionNode);
|
|
13
|
+
mixinTemplate = handleJsDoc(mixinTemplate, mixinFunctionNode);
|
|
14
|
+
mixinTemplate = handleName(mixinTemplate, mixinFunctionNode);
|
|
15
|
+
mixinTemplate = turnClassDocIntoMixin(mixinTemplate);
|
|
16
|
+
|
|
17
|
+
return mixinTemplate;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function handleName(mixin, node) {
|
|
21
|
+
mixin.name = node?.name?.getText() || node?.parent?.name?.getText() || node?.declarationList?.declarations?.[0]?.name?.getText() || '';
|
|
22
|
+
return mixin;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Turns a classDoc into a mixin
|
|
27
|
+
*/
|
|
28
|
+
function turnClassDocIntoMixin(mixin) {
|
|
29
|
+
mixin.kind = 'mixin';
|
|
30
|
+
delete mixin.superclass;
|
|
31
|
+
delete mixin.return;
|
|
32
|
+
return mixin;
|
|
33
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
handleDefaultValue,
|
|
3
|
+
handleExplicitType,
|
|
4
|
+
handleJsDoc,
|
|
5
|
+
handleTypeInference,
|
|
6
|
+
handleWellKnownTypes
|
|
7
|
+
} from './handlers.js';
|
|
8
|
+
|
|
9
|
+
export function createVariable(variableStatementNode, declarationNode) {
|
|
10
|
+
let variableTemplate = {
|
|
11
|
+
kind: 'variable',
|
|
12
|
+
name: declarationNode?.name?.getText() || ''
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
variableTemplate = handleTypeInference(variableTemplate, declarationNode);
|
|
16
|
+
variableTemplate = handleExplicitType(variableTemplate, declarationNode);
|
|
17
|
+
variableTemplate = handleWellKnownTypes(variableTemplate, declarationNode);
|
|
18
|
+
variableTemplate = handleDefaultValue(variableTemplate, declarationNode);
|
|
19
|
+
variableTemplate = handleJsDoc(variableTemplate, variableStatementNode);
|
|
20
|
+
|
|
21
|
+
return variableTemplate;
|
|
22
|
+
}
|