@ui5/webcomponents-tools 0.0.0-bf8366eb6 → 0.0.0-c143e338b
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 +909 -0
- package/LICENSE.txt +201 -0
- package/README.md +7 -10
- package/assets-meta.js +1 -5
- package/bin/dev.js +3 -2
- package/bin/ui5nps.js +265 -0
- package/components-package/eslint.js +59 -31
- package/components-package/nps.js +96 -65
- package/components-package/vite.config.js +7 -11
- package/components-package/wdio.js +12 -5
- package/icons-collection/nps.js +30 -21
- package/lib/amd-to-es6/index.js +15 -10
- package/lib/cem/cem.js +12 -0
- package/lib/cem/custom-elements-manifest.config.mjs +74 -45
- package/lib/cem/event.mjs +69 -32
- 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/lib/cem/schema-internal.json +65 -0
- package/lib/cem/types-internal.d.ts +14 -2
- package/lib/cem/utils.mjs +69 -30
- package/lib/cem/validate.js +61 -55
- package/lib/copy-and-watch/index.js +105 -97
- package/lib/copy-list/index.js +16 -10
- package/lib/create-icons/index.js +24 -19
- package/lib/create-illustrations/index.js +49 -27
- package/lib/create-new-component/{tsFileContentTemplate.js → Component.js} +12 -9
- package/lib/create-new-component/ComponentTemplate.js +12 -0
- package/lib/create-new-component/index.js +13 -12
- package/lib/css-processors/css-processor-components.mjs +74 -59
- package/lib/css-processors/css-processor-themes.mjs +85 -62
- package/lib/css-processors/shared.mjs +5 -35
- package/lib/dev-server/{dev-server.js → dev-server.mjs} +26 -14
- package/lib/dev-server/virtual-index-html-plugin.js +24 -20
- package/lib/generate-js-imports/illustrations.js +53 -54
- package/lib/generate-json-imports/i18n.js +56 -36
- package/lib/generate-json-imports/themes.js +27 -14
- package/lib/hbs2ui5/RenderTemplates/LitRenderer.js +12 -7
- package/lib/hbs2ui5/index.js +3 -3
- package/lib/i18n/defaults.js +15 -9
- package/lib/i18n/toJSON.js +14 -10
- package/lib/icons-hash/icons-hash.mjs +149 -0
- package/lib/remove-dev-mode/remove-dev-mode.mjs +38 -24
- package/lib/rimraf/rimraf.js +31 -0
- package/lib/scoping/get-all-tags.js +9 -2
- package/package.json +22 -17
- package/tsconfig.json +18 -0
- package/lib/css-processors/css-processor-component-styles.mjs +0 -48
- package/lib/dev-server/ssr-dom-shim-loader.js +0 -26
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { hasInitializer } from '../../utils/ast-helpers.js';
|
|
2
|
+
import { isMixin } from '../../utils/mixins.js';
|
|
3
|
+
import { createArrowFunction } from './creators/createArrowFunction.js';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* arrowFunctionPlugin
|
|
8
|
+
*
|
|
9
|
+
* handles arrow functions
|
|
10
|
+
*/
|
|
11
|
+
export function arrowFunctionPlugin() {
|
|
12
|
+
return {
|
|
13
|
+
name: 'CORE - ARROW-FUNCTION',
|
|
14
|
+
analyzePhase({ts, node, moduleDoc}){
|
|
15
|
+
switch(node.kind) {
|
|
16
|
+
case ts.SyntaxKind.VariableStatement:
|
|
17
|
+
if(!isMixin(node) && hasInitializer(node)) {
|
|
18
|
+
const functionLike = createArrowFunction(node);
|
|
19
|
+
moduleDoc.declarations.push(functionLike);
|
|
20
|
+
}
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/class-jsdoc.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { parse } from 'comment-parser';
|
|
2
|
+
import { handleJsDocType, normalizeDescription } from '../../utils/jsdoc.js';
|
|
3
|
+
import { has, safe } from '../../utils/index.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* CLASS-JSDOC
|
|
7
|
+
*
|
|
8
|
+
* Deals with any JSDoc above a class
|
|
9
|
+
*/
|
|
10
|
+
export function classJsDocPlugin() {
|
|
11
|
+
return {
|
|
12
|
+
name: 'CORE - CLASS-JSDOC',
|
|
13
|
+
analyzePhase({ts, node, moduleDoc}){
|
|
14
|
+
switch (node.kind) {
|
|
15
|
+
case ts.SyntaxKind.ClassDeclaration:
|
|
16
|
+
const className = node?.name?.getText();
|
|
17
|
+
const classDoc = moduleDoc?.declarations?.find(declaration => declaration.name === className);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Because we use a bunch of 'non-standard' JSDoc annotations, TS doesn't recognize most of them.
|
|
21
|
+
* Instead we use `comment-parser` to parse the JSDoc.
|
|
22
|
+
*
|
|
23
|
+
* Loops through each JSDoc (yes, there can be multiple) above a class, and parses every JSDoc annotation
|
|
24
|
+
*
|
|
25
|
+
* Checks to see if the item is already in the classDoc, and if so merge and overwrite (JSDoc takes precedence)
|
|
26
|
+
*/
|
|
27
|
+
node?.jsDoc?.forEach(jsDoc => {
|
|
28
|
+
const parsed = parse(jsDoc?.getFullText());
|
|
29
|
+
parsed?.forEach(parsedJsDoc => {
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* If any of the tags is a `@typedef`, we ignore it; this JSDoc comment may be above a class,
|
|
33
|
+
* it probably doesnt _belong_ to the class, but something else in the file
|
|
34
|
+
*/
|
|
35
|
+
if(parsedJsDoc?.tags?.some(tag => tag?.tag === 'typedef')) return;
|
|
36
|
+
|
|
37
|
+
parsedJsDoc?.tags?.forEach(jsDoc => {
|
|
38
|
+
switch(jsDoc.tag) {
|
|
39
|
+
case 'attr':
|
|
40
|
+
case 'attribute':
|
|
41
|
+
const attributeAlreadyExists = classDoc?.attributes?.find(attr => attr.name === jsDoc.name);
|
|
42
|
+
let attributeDoc = attributeAlreadyExists || {};
|
|
43
|
+
attributeDoc = handleClassJsDoc(attributeDoc, jsDoc);
|
|
44
|
+
if(!attributeAlreadyExists) {
|
|
45
|
+
classDoc.attributes.push(attributeDoc);
|
|
46
|
+
}
|
|
47
|
+
break;
|
|
48
|
+
case 'prop':
|
|
49
|
+
case 'property':
|
|
50
|
+
const fieldAlreadyExists = classDoc?.members?.find(member => member.name === jsDoc.name);
|
|
51
|
+
let fieldDoc = fieldAlreadyExists || {};
|
|
52
|
+
fieldDoc = handleClassJsDoc(fieldDoc, jsDoc);
|
|
53
|
+
fieldDoc.kind = 'field';
|
|
54
|
+
if(!fieldAlreadyExists) {
|
|
55
|
+
classDoc.members.push(fieldDoc);
|
|
56
|
+
}
|
|
57
|
+
break;
|
|
58
|
+
case 'fires':
|
|
59
|
+
case 'event':
|
|
60
|
+
const eventAlreadyExists = classDoc?.events?.find(event => event.name === jsDoc.name);
|
|
61
|
+
let eventDoc = eventAlreadyExists || {};
|
|
62
|
+
eventDoc = handleClassJsDoc(eventDoc, jsDoc);
|
|
63
|
+
delete eventDoc.privacy;
|
|
64
|
+
if(!eventAlreadyExists) {
|
|
65
|
+
classDoc.events.push(eventDoc);
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
case 'csspart':
|
|
69
|
+
case 'part':
|
|
70
|
+
let cssPartDoc = {};
|
|
71
|
+
cssPartDoc = handleClassJsDoc(cssPartDoc, jsDoc);
|
|
72
|
+
classDoc.cssParts.push(cssPartDoc);
|
|
73
|
+
break;
|
|
74
|
+
case 'cssprop':
|
|
75
|
+
case 'cssproperty':
|
|
76
|
+
let cssPropertyDoc = {};
|
|
77
|
+
cssPropertyDoc = handleClassJsDoc(cssPropertyDoc, jsDoc);
|
|
78
|
+
classDoc.cssProperties.push(cssPropertyDoc);
|
|
79
|
+
break;
|
|
80
|
+
case 'slot':
|
|
81
|
+
let slotDoc = {};
|
|
82
|
+
slotDoc = handleClassJsDoc(slotDoc, jsDoc);
|
|
83
|
+
classDoc.slots.push(slotDoc);
|
|
84
|
+
break;
|
|
85
|
+
case 'tag':
|
|
86
|
+
case 'tagname':
|
|
87
|
+
case 'element':
|
|
88
|
+
case 'customElement':
|
|
89
|
+
case 'customelement':
|
|
90
|
+
classDoc.tagName = jsDoc?.name || '';
|
|
91
|
+
classDoc.customElement = true;
|
|
92
|
+
break;
|
|
93
|
+
case 'cssState':
|
|
94
|
+
case 'cssstate':
|
|
95
|
+
let statePropertyDoc = {};
|
|
96
|
+
statePropertyDoc = handleClassJsDoc(statePropertyDoc, jsDoc);
|
|
97
|
+
classDoc.cssStates.push(statePropertyDoc);
|
|
98
|
+
break;
|
|
99
|
+
case 'deprecated':
|
|
100
|
+
classDoc.deprecated = jsDoc?.name ? `${jsDoc.name} ${jsDoc?.description}`.trim() : "true";
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Description
|
|
108
|
+
*/
|
|
109
|
+
if(jsDoc?.comment) {
|
|
110
|
+
if(has(jsDoc?.comment)) {
|
|
111
|
+
classDoc.description = jsDoc.comment.map(com => `${safe(() => com?.name?.getText()) ?? ''}${com.text}`).join('');
|
|
112
|
+
} else {
|
|
113
|
+
classDoc.description = normalizeDescription(jsDoc.comment);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Comment-parse doesn't handle annotations with only a description correctly, for example:
|
|
119
|
+
* @summary foo bar
|
|
120
|
+
* will output only 'bar' as the description.
|
|
121
|
+
*
|
|
122
|
+
* Instead, we use TS for this JSDoc annotation.
|
|
123
|
+
*/
|
|
124
|
+
jsDoc?.tags?.forEach(tag => {
|
|
125
|
+
switch(safe(() => tag?.tagName?.getText())) {
|
|
126
|
+
case 'summary':
|
|
127
|
+
classDoc.summary = tag?.comment;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function handleClassJsDoc(doc, tag) {
|
|
140
|
+
if(tag?.type) {
|
|
141
|
+
doc.type = { text: handleJsDocType(tag.type) }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if(tag?.description) {
|
|
145
|
+
doc.description = normalizeDescription(tag.description);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if(tag?.name) {
|
|
149
|
+
doc.name = tag.name === '-' ? '' : tag.name;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if(tag?.default) {
|
|
153
|
+
doc.default = tag.default;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return doc;
|
|
157
|
+
}
|
package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/classes.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createClass } from './creators/createClass.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* classPlugin
|
|
5
|
+
*
|
|
6
|
+
* handles classes
|
|
7
|
+
*/
|
|
8
|
+
export function classPlugin() {
|
|
9
|
+
return {
|
|
10
|
+
name: 'CORE - CLASSES',
|
|
11
|
+
analyzePhase({ts, node, moduleDoc, context}){
|
|
12
|
+
switch(node.kind) {
|
|
13
|
+
case ts.SyntaxKind.ClassDeclaration:
|
|
14
|
+
const klass = createClass(node, moduleDoc, context);
|
|
15
|
+
moduleDoc.declarations.push(klass);
|
|
16
|
+
break;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import { handleParametersAndReturnType } from './createFunctionLike.js';
|
|
3
|
+
import { handleJsDoc } from './handlers.js';
|
|
4
|
+
|
|
5
|
+
export function createArrowFunction(node) {
|
|
6
|
+
const arrowFunction = node?.declarationList?.declarations?.find(declaration => ts.SyntaxKind.ArrowFunction === declaration?.initializer?.kind);
|
|
7
|
+
|
|
8
|
+
let functionLikeTemplate = {
|
|
9
|
+
kind: 'function',
|
|
10
|
+
name: arrowFunction?.name?.getText() || '',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
functionLikeTemplate = handleParametersAndReturnType(functionLikeTemplate, arrowFunction?.initializer);
|
|
14
|
+
functionLikeTemplate = handleJsDoc(functionLikeTemplate, node);
|
|
15
|
+
|
|
16
|
+
return functionLikeTemplate;
|
|
17
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function createAttribute(node) {
|
|
2
|
+
const attributeTemplate = {
|
|
3
|
+
name: node?.text || ''
|
|
4
|
+
}
|
|
5
|
+
return attributeTemplate;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function createAttributeFromField(field) {
|
|
9
|
+
const attribute = {
|
|
10
|
+
...field,
|
|
11
|
+
fieldName: field.name
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Delete the following properties because they don't exist on a attributeDoc
|
|
16
|
+
*/
|
|
17
|
+
delete attribute.kind;
|
|
18
|
+
delete attribute.static;
|
|
19
|
+
delete attribute.privacy;
|
|
20
|
+
delete attribute.reflects;
|
|
21
|
+
delete attribute.resolveInitializer;
|
|
22
|
+
|
|
23
|
+
return attribute;
|
|
24
|
+
}
|
|
@@ -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
|
+
}
|