@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
|
@@ -4,6 +4,7 @@ import path from "path";
|
|
|
4
4
|
import fs from 'fs';
|
|
5
5
|
import {
|
|
6
6
|
getDeprecatedStatus,
|
|
7
|
+
getExperimentalStatus,
|
|
7
8
|
getSinceStatus,
|
|
8
9
|
getPrivacyStatus,
|
|
9
10
|
getReference,
|
|
@@ -26,6 +27,7 @@ import { generateCustomData } from "cem-plugin-vs-code-custom-data-generator";
|
|
|
26
27
|
import { customElementJetBrainsPlugin } from "custom-element-jet-brains-integration";
|
|
27
28
|
|
|
28
29
|
const packageJSON = JSON.parse(fs.readFileSync("./package.json"));
|
|
30
|
+
const devMode = process.env.UI5_CEM_MODE === "dev";
|
|
29
31
|
|
|
30
32
|
const extractClassNodeJSDoc = node => {
|
|
31
33
|
const fileContent = node.getFullText();
|
|
@@ -64,12 +66,23 @@ function processClass(ts, classNode, moduleDoc) {
|
|
|
64
66
|
currClass.customElement = !!customElementDecorator || className === "UI5Element" || undefined;
|
|
65
67
|
currClass.kind = "class";
|
|
66
68
|
currClass.deprecated = getDeprecatedStatus(classParsedJsDoc);
|
|
69
|
+
currClass._ui5experimental = getExperimentalStatus(classParsedJsDoc);
|
|
67
70
|
currClass._ui5since = getSinceStatus(classParsedJsDoc);
|
|
68
71
|
currClass._ui5privacy = getPrivacyStatus(classParsedJsDoc);
|
|
69
72
|
currClass._ui5abstract = hasTag(classParsedJsDoc, "abstract") ? true : undefined;
|
|
70
73
|
currClass.description = normalizeDescription(classParsedJsDoc.description || findTag(classParsedJsDoc, "class")?.description);
|
|
71
74
|
currClass._ui5implements = findAllTags(classParsedJsDoc, "implements")
|
|
72
|
-
.map(tag =>
|
|
75
|
+
.map(tag => {
|
|
76
|
+
const correctInterfaceDescription = classNode?.heritageClauses?.some(heritageClause => {
|
|
77
|
+
return heritageClause?.types?.some(type => type.expression?.text === normalizeTagType(tag.type));
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
if (!correctInterfaceDescription) {
|
|
81
|
+
logDocumentationError(moduleDoc.path, `@interface {${tag.type}} tag is used, but the class doesn't implement the corresponding interface`)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return getReference(ts, normalizeTagType(tag.type), classNode, moduleDoc.path)
|
|
85
|
+
})
|
|
73
86
|
.filter(Boolean);
|
|
74
87
|
|
|
75
88
|
|
|
@@ -77,6 +90,10 @@ function processClass(ts, classNode, moduleDoc) {
|
|
|
77
90
|
const superclassTag = findTag(classParsedJsDoc, "extends");
|
|
78
91
|
currClass.superclass = getReference(ts, superclassTag.name, classNode, moduleDoc.path);
|
|
79
92
|
|
|
93
|
+
if (classNode?.heritageClauses?.[0]?.types?.[0]?.expression?.text !== superclassTag.name) {
|
|
94
|
+
logDocumentationError(moduleDoc.path, `@extends ${superclassTag.name} is used, but the class doesn't extend the corresponding superclass`)
|
|
95
|
+
}
|
|
96
|
+
|
|
80
97
|
if (currClass.superclass?.name === "UI5Element") {
|
|
81
98
|
currClass.customElement = true;
|
|
82
99
|
}
|
|
@@ -111,9 +128,13 @@ function processClass(ts, classNode, moduleDoc) {
|
|
|
111
128
|
}
|
|
112
129
|
|
|
113
130
|
// Events
|
|
114
|
-
currClass.events = findAllDecorators(classNode, "event")
|
|
131
|
+
currClass.events = findAllDecorators(classNode, ["event", "eventStrict"])
|
|
115
132
|
?.map(event => processEvent(ts, event, classNode, moduleDoc));
|
|
116
133
|
|
|
134
|
+
const filename = classNode.getSourceFile().fileName;
|
|
135
|
+
const sourceFile = typeProgram.getSourceFile(filename);
|
|
136
|
+
const tsProgramClassNode = sourceFile.statements.find(statement => ts.isClassDeclaration(statement) && statement.name?.text === classNode.name?.text);
|
|
137
|
+
|
|
117
138
|
// Slots (with accessor), methods and fields
|
|
118
139
|
for (let i = 0; i < (currClass.members?.length || 0); i++) {
|
|
119
140
|
const member = currClass.members[i];
|
|
@@ -168,17 +189,21 @@ function processClass(ts, classNode, moduleDoc) {
|
|
|
168
189
|
const propertyDecorator = findDecorator(classNodeMember, "property");
|
|
169
190
|
|
|
170
191
|
if (propertyDecorator) {
|
|
171
|
-
member._ui5validator = propertyDecorator?.expression?.arguments[0]?.properties?.find(property => ["validator", "type"].includes(property.name.text))?.initializer?.text || "String";
|
|
172
192
|
member._ui5noAttribute = propertyDecorator?.expression?.arguments[0]?.properties?.find(property => property.name.text === "noAttribute")?.initializer?.kind === ts.SyntaxKind.TrueKeyword || undefined;
|
|
173
193
|
}
|
|
174
194
|
|
|
175
|
-
if (currClass.customElement && member.privacy === "public"
|
|
176
|
-
const filename = classNode.getSourceFile().fileName;
|
|
177
|
-
const sourceFile = typeProgram.getSourceFile(filename);
|
|
178
|
-
const tsProgramClassNode = sourceFile.statements.find(statement => ts.isClassDeclaration(statement) && statement.name?.text === classNode.name?.text);
|
|
195
|
+
if (currClass.customElement && member.privacy === "public") {
|
|
179
196
|
const tsProgramMember = tsProgramClassNode.members.find(m => ts.isPropertyDeclaration(m) && m.name?.text === member.name);
|
|
180
197
|
const attributeValue = typeChecker.typeToString(typeChecker.getTypeAtLocation(tsProgramMember), tsProgramMember);
|
|
181
198
|
|
|
199
|
+
if (attributeValue === "boolean" && member.default === "true") {
|
|
200
|
+
logDocumentationError(moduleDoc.path, `Boolean properties must be initialzed to false. [${member.name}] property of class [${className}] is intialized to \`true\``)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (!member.type) {
|
|
204
|
+
logDocumentationError(moduleDoc.path, `Public properties must have type. The type of [${member.name}] property is not determinated automatically. Please check it.`)
|
|
205
|
+
}
|
|
206
|
+
|
|
182
207
|
currClass.attributes.push({
|
|
183
208
|
description: member.description,
|
|
184
209
|
name: toKebabCase(member.name),
|
|
@@ -293,6 +318,7 @@ function processInterface(ts, interfaceNode, moduleDoc) {
|
|
|
293
318
|
kind: "interface",
|
|
294
319
|
name: interfaceName,
|
|
295
320
|
description: normalizeDescription(interfaceParsedJsDoc?.description),
|
|
321
|
+
_ui5experimental: getExperimentalStatus(interfaceParsedJsDoc),
|
|
296
322
|
_ui5privacy: getPrivacyStatus(interfaceParsedJsDoc),
|
|
297
323
|
_ui5since: getSinceStatus(interfaceParsedJsDoc),
|
|
298
324
|
deprecated: getDeprecatedStatus(interfaceParsedJsDoc),
|
|
@@ -313,6 +339,7 @@ function processEnum(ts, enumNode, moduleDoc) {
|
|
|
313
339
|
kind: "enum",
|
|
314
340
|
name: enumName,
|
|
315
341
|
description: normalizeDescription(enumJSdoc?.comment),
|
|
342
|
+
_ui5experimental: getExperimentalStatus(enumParsedJsDoc),
|
|
316
343
|
_ui5privacy: getPrivacyStatus(enumParsedJsDoc),
|
|
317
344
|
_ui5since: getSinceStatus(enumParsedJsDoc),
|
|
318
345
|
deprecated: getDeprecatedStatus(enumParsedJsDoc) || undefined,
|
|
@@ -425,14 +452,6 @@ export default {
|
|
|
425
452
|
}
|
|
426
453
|
},
|
|
427
454
|
moduleLinkPhase({ moduleDoc }) {
|
|
428
|
-
for (let i = 0; i < moduleDoc.declarations.length; i++) {
|
|
429
|
-
const shouldRemove = processPublicAPI(moduleDoc.declarations[i]) || ["function", "variable"].includes(moduleDoc.declarations[i].kind)
|
|
430
|
-
if (shouldRemove) {
|
|
431
|
-
moduleDoc.declarations.splice(i, 1);
|
|
432
|
-
i--;
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
455
|
moduleDoc.path = moduleDoc.path?.replace(/^src/, "dist").replace(/\.ts$/, ".js");
|
|
437
456
|
|
|
438
457
|
moduleDoc.exports = moduleDoc.exports.
|
|
@@ -456,41 +475,51 @@ export default {
|
|
|
456
475
|
})
|
|
457
476
|
}
|
|
458
477
|
})
|
|
478
|
+
},
|
|
479
|
+
packageLinkPhase({ customElementsManifest }) {
|
|
480
|
+
customElementsManifest.modules.forEach(moduleDoc => {
|
|
481
|
+
for (let i = 0; i < moduleDoc.declarations.length; i++) {
|
|
482
|
+
const shouldRemove = processPublicAPI(moduleDoc.declarations[i]) || ["function", "variable"].includes(moduleDoc.declarations[i].kind)
|
|
483
|
+
if (shouldRemove) {
|
|
484
|
+
moduleDoc.declarations.splice(i, 1);
|
|
485
|
+
i--;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
459
488
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
489
|
+
const typeReferences = new Set();
|
|
490
|
+
const registerTypeReference = reference => typeReferences.add(JSON.stringify(reference))
|
|
491
|
+
|
|
492
|
+
moduleDoc.declarations.forEach(declaration => {
|
|
493
|
+
["events", "slots", "members"].forEach(memberType => {
|
|
494
|
+
declaration[memberType]?.forEach(member => {
|
|
495
|
+
if (member.type?.references) {
|
|
496
|
+
member.type.references.forEach(registerTypeReference)
|
|
497
|
+
} else if (member._ui5type?.references) {
|
|
498
|
+
member._ui5type.references.forEach(registerTypeReference)
|
|
499
|
+
} else if (member.kind === "method") {
|
|
500
|
+
member.return?.type?.references?.forEach(registerTypeReference)
|
|
501
|
+
|
|
502
|
+
member.parameters?.forEach(parameter => {
|
|
503
|
+
parameter.type?.references?.forEach(registerTypeReference)
|
|
504
|
+
})
|
|
505
|
+
}
|
|
506
|
+
})
|
|
477
507
|
})
|
|
478
|
-
})
|
|
479
|
-
});
|
|
508
|
+
});
|
|
480
509
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
510
|
+
typeReferences.forEach(reference => {
|
|
511
|
+
reference = JSON.parse(reference);
|
|
512
|
+
if (reference.package === packageJSON?.name && reference.module === moduleDoc.path) {
|
|
513
|
+
const hasExport = moduleDoc.exports.some(e => e.declaration?.name === reference.name && e.declaration?.module === reference.module)
|
|
485
514
|
|
|
486
|
-
|
|
487
|
-
|
|
515
|
+
if (!hasExport) {
|
|
516
|
+
logDocumentationError(moduleDoc.path?.replace(/^dist/, "src").replace(/\.js$/, ".ts"), `Type '${reference.name}' is used to describe a public API but is not exported.`,)
|
|
517
|
+
}
|
|
488
518
|
}
|
|
489
|
-
}
|
|
490
|
-
})
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
if (context.dev) {
|
|
519
|
+
})
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
if (devMode) {
|
|
494
523
|
displayDocumentationErrors();
|
|
495
524
|
}
|
|
496
525
|
}
|
package/lib/cem/event.mjs
CHANGED
|
@@ -16,19 +16,10 @@ import {
|
|
|
16
16
|
} from "./utils.mjs";
|
|
17
17
|
|
|
18
18
|
const jsDocRegExp = /\/\*\*(.|\n)+?\s+\*\//;
|
|
19
|
+
const ASTFalseKeywordCode = 94;
|
|
19
20
|
|
|
20
21
|
const getParams = (ts, eventDetails, commentParams, classNode, moduleDoc) => {
|
|
21
22
|
return commentParams?.map(commentParam => {
|
|
22
|
-
const decoratorParam = eventDetails?.find(prop => prop?.name?.text === commentParam?.name);
|
|
23
|
-
|
|
24
|
-
if (!decoratorParam || !decoratorParam?.jsDoc?.[0]) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const decoratorParamParsedComment = parse(decoratorParam?.jsDoc?.[0]?.getText?.(), { spacing: 'preserve' })[0];
|
|
29
|
-
|
|
30
|
-
validateJSDocComment("eventParam", decoratorParamParsedComment, decoratorParam.name?.text, moduleDoc);
|
|
31
|
-
|
|
32
23
|
const { typeName, name } = getType(normalizeTagType(commentParam?.type));
|
|
33
24
|
let type;
|
|
34
25
|
|
|
@@ -47,12 +38,10 @@ const getParams = (ts, eventDetails, commentParams, classNode, moduleDoc) => {
|
|
|
47
38
|
return {
|
|
48
39
|
type,
|
|
49
40
|
name: commentParam?.name,
|
|
50
|
-
_ui5privacy:
|
|
41
|
+
_ui5privacy: "public",
|
|
51
42
|
description: normalizeDescription(commentParam?.description),
|
|
52
|
-
_ui5since: getSinceStatus(decoratorParamParsedComment),
|
|
53
|
-
deprecated: getDeprecatedStatus(decoratorParamParsedComment),
|
|
54
43
|
};
|
|
55
|
-
})
|
|
44
|
+
});
|
|
56
45
|
};
|
|
57
46
|
|
|
58
47
|
function processEvent(ts, event, classNode, moduleDoc) {
|
|
@@ -77,30 +66,32 @@ function processEvent(ts, event, classNode, moduleDoc) {
|
|
|
77
66
|
const privacy = findTag(eventParsedComment, ["public", "private", "protected"])?.tag || "private";
|
|
78
67
|
const sinceTag = findTag(eventParsedComment, "since");
|
|
79
68
|
const commentParams = findAllTags(eventParsedComment, "param");
|
|
80
|
-
const allowPreventDefault = hasTag(eventParsedComment, "allowPreventDefault") || undefined;
|
|
81
69
|
const description = normalizeDescription(eventParsedComment?.description);
|
|
82
70
|
const native = hasTag(eventParsedComment, "native");
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
71
|
+
const eventArgs = event?.expression?.arguments;
|
|
72
|
+
let eventBubbles;
|
|
73
|
+
let eventCancelable;
|
|
74
|
+
let eventDetails;
|
|
75
|
+
|
|
76
|
+
eventArgs && eventArgs.forEach(arg => {
|
|
77
|
+
arg.properties?.forEach(prop => {
|
|
78
|
+
if (prop.name?.text === "bubbles") {
|
|
79
|
+
eventBubbles = prop.initializer.kind === ASTFalseKeywordCode ? false : true;
|
|
80
|
+
} else if (prop.name?.text === "cancelable") {
|
|
81
|
+
eventCancelable = prop.initializer.kind === ASTFalseKeywordCode ? false : true;
|
|
82
|
+
} else if (prop.name?.text === "detail") {
|
|
83
|
+
eventDetails = prop.initializer?.properties;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
});
|
|
88
87
|
|
|
89
88
|
result.description = description;
|
|
90
|
-
result.
|
|
89
|
+
result._ui5Cancelable = eventCancelable !== undefined ? eventCancelable : false;
|
|
90
|
+
result._ui5allowPreventDefault = result._ui5Cancelable;
|
|
91
|
+
result._ui5Bubbles = eventBubbles !== undefined ? eventBubbles : false;
|
|
91
92
|
|
|
92
93
|
if (native) {
|
|
93
94
|
result.type = { text: "Event" };
|
|
94
|
-
} else if (event?.expression?.typeArguments) {
|
|
95
|
-
const typesText = event?.expression?.typeArguments.map(type => type.typeName?.text).filter(Boolean).join(" | ");
|
|
96
|
-
const typeRefs = (getTypeRefs(ts, event.expression)
|
|
97
|
-
?.map(e => getReference(ts, e, event, moduleDoc.path)).filter(Boolean)) || [];
|
|
98
|
-
|
|
99
|
-
result.type = { text: `CustomEvent<${typesText}>` };
|
|
100
|
-
|
|
101
|
-
if (typeRefs.length) {
|
|
102
|
-
result.type.references = typeRefs;
|
|
103
|
-
}
|
|
104
95
|
}
|
|
105
96
|
|
|
106
97
|
if (privacy) {
|
|
@@ -121,7 +112,53 @@ function processEvent(ts, event, classNode, moduleDoc) {
|
|
|
121
112
|
: sinceTag.name;
|
|
122
113
|
}
|
|
123
114
|
|
|
124
|
-
|
|
115
|
+
const eventDetailType = classNode.members?.find(member => {
|
|
116
|
+
return ts.isPropertyDeclaration(member) && member.name.text === "eventDetails"
|
|
117
|
+
})?.type;
|
|
118
|
+
const eventDetailRef = eventDetailType?.members?.find(member => member.name.text === name) || eventDetailType?.types?.[eventDetailType?.types?.length - 1]?.members?.find(member => member.name.text === name);
|
|
119
|
+
const hasGeneric = !!event?.expression?.typeArguments
|
|
120
|
+
|
|
121
|
+
if (commentParams.length) {
|
|
122
|
+
if (eventDetailRef && hasGeneric) {
|
|
123
|
+
logDocumentationError(moduleDoc.path, `Event details for event '${name}' has to be defined either with generic or with eventDetails.`)
|
|
124
|
+
} else if (eventDetails) {
|
|
125
|
+
if (hasGeneric) {
|
|
126
|
+
const typesText = event?.expression?.typeArguments.map(type => type.typeName?.text).filter(Boolean).join(" | ");
|
|
127
|
+
const typeRefs = (getTypeRefs(ts, event.expression)
|
|
128
|
+
?.map(e => getReference(ts, e, event, moduleDoc.path)).filter(Boolean)) || [];
|
|
129
|
+
|
|
130
|
+
result.type = { text: `CustomEvent<${typesText}>` };
|
|
131
|
+
|
|
132
|
+
if (typeRefs.length) {
|
|
133
|
+
result.type.references = typeRefs;
|
|
134
|
+
}
|
|
135
|
+
} else if (eventDetailRef) {
|
|
136
|
+
const typesText = eventDetailRef?.type?.typeName?.text;
|
|
137
|
+
const typeRefs = (getTypeRefs(ts, eventDetailRef)
|
|
138
|
+
?.map(e => getReference(ts, e, event, moduleDoc.path)).filter(Boolean)) || [];
|
|
139
|
+
|
|
140
|
+
result.type = { text: `CustomEvent<${typesText}>` };
|
|
141
|
+
|
|
142
|
+
if (typeRefs.length) {
|
|
143
|
+
result.type.references = typeRefs;
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
logDocumentationError(moduleDoc.path, `Event details for event '${name}' must be described using generics. Add type via generics to the decorator: @event<TypeForDetails>("${name}", {details}).`)
|
|
147
|
+
}
|
|
148
|
+
} else if (eventDetailRef) {
|
|
149
|
+
const typesText = eventDetailRef?.type?.typeName?.text;
|
|
150
|
+
const typeRefs = (getTypeRefs(ts, eventDetailRef)
|
|
151
|
+
?.map(e => getReference(ts, e, event, moduleDoc.path)).filter(Boolean)) || [];
|
|
152
|
+
|
|
153
|
+
result.type = { text: `CustomEvent<${typesText}>` };
|
|
154
|
+
|
|
155
|
+
if (typeRefs.length) {
|
|
156
|
+
result.type.references = typeRefs;
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
logDocumentationError(moduleDoc.path, `Event details for event '${name}' must be described.`)
|
|
160
|
+
}
|
|
161
|
+
|
|
125
162
|
result._ui5parameters = getParams(ts, eventDetails, commentParams, classNode, moduleDoc);
|
|
126
163
|
}
|
|
127
164
|
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import ts from 'typescript';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
// Patch: Custom patch to not merge child parent privacy/type
|
|
6
|
+
// https://github.com/open-wc/custom-elements-manifest/pull/300
|
|
7
|
+
import { globby } from 'globby';
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import commandLineArgs from 'command-line-args';
|
|
10
|
+
import chokidar from 'chokidar';
|
|
11
|
+
import debounce from 'debounce';
|
|
12
|
+
|
|
13
|
+
import { create } from './src/create.js';
|
|
14
|
+
import {
|
|
15
|
+
getUserConfig,
|
|
16
|
+
getCliConfig,
|
|
17
|
+
addFrameworkPlugins,
|
|
18
|
+
addCustomElementsPropertyToPackageJson,
|
|
19
|
+
mergeGlobsAndExcludes,
|
|
20
|
+
timestamp,
|
|
21
|
+
DEFAULTS,
|
|
22
|
+
MENU,
|
|
23
|
+
} from './src/utils/cli-helpers.js';
|
|
24
|
+
import { findExternalManifests } from './src/utils/find-external-manifests.js';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {{argv:string[]; cwd: string; noWrite:boolean}} [opts]
|
|
28
|
+
*/
|
|
29
|
+
export async function cli({ argv = process.argv, cwd = process.cwd(), noWrite } = {}) {
|
|
30
|
+
const mainDefinitions = [{ name: 'command', defaultOption: true }];
|
|
31
|
+
const mainOptions = commandLineArgs(mainDefinitions, { stopAtFirstUnknown: true, argv });
|
|
32
|
+
const cliArgs = mainOptions._unknown || [];
|
|
33
|
+
|
|
34
|
+
if (mainOptions.command === 'analyze') {
|
|
35
|
+
const { config: configPath, ...cliConfig } = getCliConfig(cliArgs);
|
|
36
|
+
const userConfig = await getUserConfig(configPath, cwd);
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Merged config options
|
|
40
|
+
* Command line options override userConfig options
|
|
41
|
+
*/
|
|
42
|
+
const mergedOptions = { ...DEFAULTS, ...userConfig, ...cliConfig };
|
|
43
|
+
const merged = mergeGlobsAndExcludes(DEFAULTS, userConfig, cliConfig);
|
|
44
|
+
async function run() {
|
|
45
|
+
const globs = await globby(merged, { cwd });
|
|
46
|
+
const modules = userConfig?.overrideModuleCreation
|
|
47
|
+
? userConfig.overrideModuleCreation({ ts, globs })
|
|
48
|
+
: globs.map((glob) => {
|
|
49
|
+
const fullPath = path.resolve(cwd, glob);
|
|
50
|
+
const source = fs.readFileSync(fullPath).toString();
|
|
51
|
+
|
|
52
|
+
return ts.createSourceFile(glob, source, ts.ScriptTarget.ES2015, true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
let thirdPartyCEMs = [];
|
|
56
|
+
if (mergedOptions?.dependencies) {
|
|
57
|
+
try {
|
|
58
|
+
const fullPathGlobs = globs.map(glob => path.resolve(cwd, glob));
|
|
59
|
+
thirdPartyCEMs = await findExternalManifests(fullPathGlobs, {basePath: cwd});
|
|
60
|
+
} catch (e) {
|
|
61
|
+
if (mergedOptions.dev) console.log(`Failed to add third party CEMs. \n\n${e.stack}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let plugins = await addFrameworkPlugins(mergedOptions);
|
|
66
|
+
plugins = [...plugins, ...(userConfig?.plugins || [])];
|
|
67
|
+
|
|
68
|
+
const context = { dev: mergedOptions.dev, thirdPartyCEMs };
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Create the manifest
|
|
72
|
+
*/
|
|
73
|
+
const customElementsManifest = create({modules, plugins, context});
|
|
74
|
+
|
|
75
|
+
if (mergedOptions.dev) {
|
|
76
|
+
console.log(JSON.stringify(customElementsManifest, null, 2));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if(!noWrite) {
|
|
80
|
+
const outdir = path.join(cwd, mergedOptions.outdir);
|
|
81
|
+
if (!fs.existsSync(outdir)) {
|
|
82
|
+
fs.mkdirSync(outdir, { recursive: true });
|
|
83
|
+
}
|
|
84
|
+
fs.writeFileSync(
|
|
85
|
+
path.join(outdir, 'custom-elements.json'),
|
|
86
|
+
`${JSON.stringify(customElementsManifest, null, 2)}\n`,
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!mergedOptions.quiet) {
|
|
91
|
+
console.log(`[${timestamp()}] @custom-elements-manifest/analyzer: Created new manifest.`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return customElementsManifest;
|
|
95
|
+
}
|
|
96
|
+
/** The manifest that will be returned for programmatic calls of cli */
|
|
97
|
+
const manifest = await run();
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Watch mode
|
|
101
|
+
*/
|
|
102
|
+
if (mergedOptions.watch) {
|
|
103
|
+
const fileWatcher = chokidar.watch(merged);
|
|
104
|
+
|
|
105
|
+
const onChange = debounce(run, 100);
|
|
106
|
+
|
|
107
|
+
fileWatcher.addListener('add', onChange);
|
|
108
|
+
fileWatcher.addListener('change', onChange);
|
|
109
|
+
fileWatcher.addListener('unlink', onChange);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
if (mergedOptions.packagejson) {
|
|
114
|
+
addCustomElementsPropertyToPackageJson(mergedOptions.outdir);
|
|
115
|
+
}
|
|
116
|
+
} catch {
|
|
117
|
+
console.log(
|
|
118
|
+
`Could not add 'customElements' property to ${cwd}${
|
|
119
|
+
path.sep
|
|
120
|
+
}package.json. \nAdding this property helps tooling locate your Custom Elements Manifest. Please consider adding it yourself, or file an issue if you think this is a bug.\nhttps://www.github.com/open-wc/custom-elements-manifest`,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return manifest;
|
|
125
|
+
} else {
|
|
126
|
+
console.log(MENU);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@custom-elements-manifest/analyzer",
|
|
3
|
+
"version": "0.10.10",
|
|
4
|
+
"description": "",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"types": "index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"custom-elements-manifest": "./cem.js",
|
|
10
|
+
"cem": "./cem.js"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/open-wc/custom-elements-manifest.git",
|
|
15
|
+
"directory": "packages/analyzer"
|
|
16
|
+
},
|
|
17
|
+
"author": "open-wc",
|
|
18
|
+
"homepage": "https://github.com/open-wc/custom-elements-manifest",
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/open-wc/custom-elements-manifest"
|
|
21
|
+
},
|
|
22
|
+
"main": "index.js",
|
|
23
|
+
"scripts": {
|
|
24
|
+
"prepublishOnly": "npm test && npm run build:browser",
|
|
25
|
+
"start": "nodemon --ignore './custom-elements.json' cem.js analyze --dev --fast",
|
|
26
|
+
"test": "asdgf",
|
|
27
|
+
"build:browser": "esbuild src/browser-entrypoint.js --bundle --format=esm --outfile=browser/index.js",
|
|
28
|
+
"test:watch": "watchexec -w src -w test npm test",
|
|
29
|
+
"update-fixtures": "node scripts/update-version.js --version 1.0.0"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"custom-elements",
|
|
33
|
+
"custom-elements-json",
|
|
34
|
+
"custom-elements-manifest",
|
|
35
|
+
"customelements",
|
|
36
|
+
"webcomponents",
|
|
37
|
+
"customelementsjson",
|
|
38
|
+
"customelementsmanifest"
|
|
39
|
+
],
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@custom-elements-manifest/find-dependencies": "^0.0.6",
|
|
42
|
+
"@github/catalyst": "^1.6.0",
|
|
43
|
+
"@web/config-loader": "0.1.3",
|
|
44
|
+
"chokidar": "3.5.2",
|
|
45
|
+
"command-line-args": "5.1.2",
|
|
46
|
+
"comment-parser": "1.2.4",
|
|
47
|
+
"custom-elements-manifest": "1.0.0",
|
|
48
|
+
"debounce": "1.2.1",
|
|
49
|
+
"globby": "11.0.4",
|
|
50
|
+
"typescript": "~5.4.2"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {},
|
|
53
|
+
"contributors": [
|
|
54
|
+
"Pascal Schilp <pascalschilp@gmail.com>",
|
|
55
|
+
"Benny Powers <web@bennypowers.com>",
|
|
56
|
+
"Matias Huhta <huhta.matias@gmail.com>"
|
|
57
|
+
],
|
|
58
|
+
"customElements": "custom-elements.json"
|
|
59
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is the entrypoint for rollup to correctly bundle the analyzer for the browser.
|
|
3
|
+
* Do not use directly, but import from ./browser/index.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import ts from 'typescript';
|
|
7
|
+
|
|
8
|
+
import { create } from './create.js';
|
|
9
|
+
import { catalystPlugin } from './features/framework-plugins/catalyst/catalyst.js';
|
|
10
|
+
import { catalystPlugin2 } from './features/framework-plugins/catalyst-major-2/catalyst.js';
|
|
11
|
+
import { stencilPlugin } from './features/framework-plugins/stencil/stencil.js';
|
|
12
|
+
import { litPlugin } from './features/framework-plugins/lit/lit.js';
|
|
13
|
+
import { fastPlugin } from './features/framework-plugins/fast/fast.js';
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
ts,
|
|
17
|
+
create,
|
|
18
|
+
catalystPlugin,
|
|
19
|
+
catalystPlugin2,
|
|
20
|
+
stencilPlugin,
|
|
21
|
+
litPlugin,
|
|
22
|
+
fastPlugin
|
|
23
|
+
};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import { FEATURES } from './features/index.js';
|
|
3
|
+
import { withErrorHandling } from './utils/index.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* CORE
|
|
7
|
+
*
|
|
8
|
+
* This function is the core of the analyzer. It takes an array of ts sourceFiles, and creates a
|
|
9
|
+
* custom elements manifest.
|
|
10
|
+
*/
|
|
11
|
+
export function create({modules, plugins = [], context = {dev:false}}) {
|
|
12
|
+
const customElementsManifest = {
|
|
13
|
+
schemaVersion: '1.0.0',
|
|
14
|
+
readme: '',
|
|
15
|
+
modules: [],
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const { dev } = context;
|
|
19
|
+
|
|
20
|
+
const mergedPlugins = [
|
|
21
|
+
...FEATURES,
|
|
22
|
+
...plugins,
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
if(dev) console.log('[INITIALIZE PLUGINS]');
|
|
26
|
+
mergedPlugins.forEach(({name, initialize}) => {
|
|
27
|
+
withErrorHandling(name, () => {
|
|
28
|
+
initialize?.({ts, customElementsManifest, context});
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
modules.forEach(currModule => {
|
|
33
|
+
if(dev) console.log('[COLLECT PHASE]: ', currModule.fileName);
|
|
34
|
+
/**
|
|
35
|
+
* COLLECT PHASE
|
|
36
|
+
* First pass through all modules. Can be used to gather imports, exports, types, default values,
|
|
37
|
+
* which you may need to know the existence of in a later phase.
|
|
38
|
+
*/
|
|
39
|
+
collect(currModule, context, mergedPlugins);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
modules.forEach(currModule => {
|
|
43
|
+
if(dev) console.log('[ANALYZE PHASE]: ', currModule.fileName);
|
|
44
|
+
const moduleDoc = {
|
|
45
|
+
kind: "javascript-module",
|
|
46
|
+
path: currModule.fileName,
|
|
47
|
+
declarations: [],
|
|
48
|
+
exports: []
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* ANALYZE PHASE
|
|
53
|
+
* Go through the AST of every separate module, and gather as much as information as we can
|
|
54
|
+
* This includes a modules imports, which are not specified in custom-elements.json, but are
|
|
55
|
+
* required for the LINK PHASE, and deleted when processed
|
|
56
|
+
*/
|
|
57
|
+
analyze(currModule, moduleDoc, context, mergedPlugins);
|
|
58
|
+
customElementsManifest.modules.push(moduleDoc);
|
|
59
|
+
|
|
60
|
+
if(dev) console.log('[MODULE LINK PHASE]: ', currModule.fileName);
|
|
61
|
+
/**
|
|
62
|
+
* LINK PHASE
|
|
63
|
+
* All information for a module has been gathered, now we can link information together. Like:
|
|
64
|
+
* - Finding a CustomElement's tagname by finding its customElements.define() call (or 'export')
|
|
65
|
+
* - Applying inheritance to classes (adding `inheritedFrom` properties/attrs/events/methods)
|
|
66
|
+
*/
|
|
67
|
+
mergedPlugins.forEach(({name, moduleLinkPhase}) => {
|
|
68
|
+
withErrorHandling(name, () => {
|
|
69
|
+
moduleLinkPhase?.({ts, moduleDoc, context});
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if(dev) console.log('[PACKAGE LINK PHASE]');
|
|
75
|
+
/**
|
|
76
|
+
* PACKAGE LINK PHASE
|
|
77
|
+
* All modules have now been parsed, we can now link information from across modules together
|
|
78
|
+
* - Link classes to their definitions etc
|
|
79
|
+
* - Match tagNames for classDocs
|
|
80
|
+
* - Apply inheritance
|
|
81
|
+
*/
|
|
82
|
+
mergedPlugins.forEach(({name, packageLinkPhase}) => {
|
|
83
|
+
withErrorHandling(name, () => {
|
|
84
|
+
packageLinkPhase?.({customElementsManifest, context});
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return customElementsManifest;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function collect(source, context, mergedPlugins) {
|
|
92
|
+
visitNode(source);
|
|
93
|
+
|
|
94
|
+
function visitNode(node) {
|
|
95
|
+
mergedPlugins.forEach(({name, collectPhase}) => {
|
|
96
|
+
withErrorHandling(name, () => {
|
|
97
|
+
collectPhase?.({ts, node, context});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
ts.forEachChild(node, visitNode);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function analyze(source, moduleDoc, context, mergedPlugins) {
|
|
106
|
+
visitNode(source);
|
|
107
|
+
|
|
108
|
+
function visitNode(node) {
|
|
109
|
+
mergedPlugins.forEach(({name, analyzePhase}) => {
|
|
110
|
+
withErrorHandling(name, () => {
|
|
111
|
+
analyzePhase?.({ts, node, moduleDoc, context});
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
ts.forEachChild(node, visitNode);
|
|
116
|
+
}
|
|
117
|
+
}
|