@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.
Files changed (58) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/components-package/nps.js +0 -1
  3. package/lib/cem/cem.js +1 -1
  4. package/lib/cem/patch/@custom-elements-manifest/analyzer/cli.js +128 -0
  5. package/lib/cem/patch/@custom-elements-manifest/analyzer/package.json +59 -0
  6. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/browser-entrypoint.js +23 -0
  7. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/create.js +117 -0
  8. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/arrow-function.js +26 -0
  9. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/class-jsdoc.js +157 -0
  10. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/classes.js +20 -0
  11. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createArrowFunction.js +17 -0
  12. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createAttribute.js +24 -0
  13. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createClass.js +301 -0
  14. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createClassField.js +26 -0
  15. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createFunctionLike.js +73 -0
  16. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createMixin.js +33 -0
  17. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createVariable.js +22 -0
  18. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/handlers.js +338 -0
  19. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/custom-elements-define-calls.js +90 -0
  20. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/exports.js +156 -0
  21. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/function-like.js +24 -0
  22. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/mixins.js +29 -0
  23. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/reexported-wrapped-mixin-exports.js +84 -0
  24. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/variables.js +34 -0
  25. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/collect-phase/collect-imports.js +101 -0
  26. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/catalyst/catalyst.js +11 -0
  27. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/catalyst/controller.js +34 -0
  28. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/catalyst-major-2/catalyst.js +11 -0
  29. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/catalyst-major-2/controller.js +34 -0
  30. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/decorators/attr.js +53 -0
  31. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/decorators/custom-element-decorator.js +36 -0
  32. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/fast/fast.js +7 -0
  33. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/lit.js +13 -0
  34. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/member-denylist.js +21 -0
  35. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/method-denylist.js +20 -0
  36. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/property-decorator.js +94 -0
  37. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/static-properties.js +121 -0
  38. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/utils.js +66 -0
  39. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/stencil/stencil.js +129 -0
  40. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/index.js +80 -0
  41. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/link-phase/cleanup-classes.js +25 -0
  42. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/link-phase/field-denylist.js +22 -0
  43. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/link-phase/method-denylist.js +25 -0
  44. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/post-processing/apply-inheritance.js +78 -0
  45. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/post-processing/is-custom-element.js +34 -0
  46. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/post-processing/link-class-to-tagname.js +27 -0
  47. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/post-processing/remove-unexported-declarations.js +23 -0
  48. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/post-processing/resolve-initializers.js +52 -0
  49. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/ast-helpers.js +186 -0
  50. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/cli-helpers.js +164 -0
  51. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/exports.js +44 -0
  52. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/find-external-manifests.js +67 -0
  53. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/imports.js +25 -0
  54. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/index.js +71 -0
  55. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/jsdoc.js +19 -0
  56. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/manifest-helpers.js +194 -0
  57. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/mixins.js +112 -0
  58. 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
+ }