@ui5/webcomponents-tools 0.0.0-07460127d → 0.0.0-093de5dd1

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 (161) hide show
  1. package/CHANGELOG.md +2440 -1
  2. package/LICENSE.txt +201 -0
  3. package/README.md +7 -10
  4. package/assets-meta.js +154 -0
  5. package/bin/dev.js +13 -1
  6. package/bin/ui5nps.js +274 -0
  7. package/components-package/eslint.js +66 -2
  8. package/components-package/nps.js +147 -48
  9. package/components-package/postcss.components.js +1 -21
  10. package/components-package/postcss.themes.js +1 -23
  11. package/components-package/vite.config.js +9 -0
  12. package/components-package/wdio.js +161 -73
  13. package/icons-collection/nps.js +80 -28
  14. package/lib/amd-to-es6/index.js +107 -0
  15. package/lib/amd-to-es6/no-remaining-require.js +33 -0
  16. package/lib/cem/cem.js +12 -0
  17. package/lib/cem/custom-elements-manifest.config.mjs +546 -0
  18. package/lib/cem/event.mjs +168 -0
  19. package/lib/cem/merge.mjs +220 -0
  20. package/lib/cem/patch/@custom-elements-manifest/analyzer/cli.js +128 -0
  21. package/lib/cem/patch/@custom-elements-manifest/analyzer/package.json +59 -0
  22. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/browser-entrypoint.js +23 -0
  23. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/create.js +117 -0
  24. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/arrow-function.js +26 -0
  25. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/class-jsdoc.js +157 -0
  26. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/classes.js +20 -0
  27. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createArrowFunction.js +17 -0
  28. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createAttribute.js +24 -0
  29. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createClass.js +301 -0
  30. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createClassField.js +26 -0
  31. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createFunctionLike.js +73 -0
  32. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createMixin.js +33 -0
  33. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/createVariable.js +22 -0
  34. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/creators/handlers.js +338 -0
  35. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/custom-elements-define-calls.js +90 -0
  36. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/exports.js +156 -0
  37. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/function-like.js +24 -0
  38. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/mixins.js +29 -0
  39. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/reexported-wrapped-mixin-exports.js +84 -0
  40. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/analyse-phase/variables.js +34 -0
  41. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/collect-phase/collect-imports.js +101 -0
  42. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/catalyst/catalyst.js +11 -0
  43. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/catalyst/controller.js +34 -0
  44. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/catalyst-major-2/catalyst.js +11 -0
  45. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/catalyst-major-2/controller.js +34 -0
  46. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/decorators/attr.js +53 -0
  47. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/decorators/custom-element-decorator.js +36 -0
  48. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/fast/fast.js +7 -0
  49. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/lit.js +13 -0
  50. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/member-denylist.js +21 -0
  51. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/method-denylist.js +20 -0
  52. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/property-decorator.js +94 -0
  53. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/static-properties.js +121 -0
  54. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/utils.js +66 -0
  55. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/framework-plugins/stencil/stencil.js +129 -0
  56. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/index.js +80 -0
  57. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/link-phase/cleanup-classes.js +25 -0
  58. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/link-phase/field-denylist.js +22 -0
  59. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/link-phase/method-denylist.js +25 -0
  60. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/post-processing/apply-inheritance.js +78 -0
  61. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/post-processing/is-custom-element.js +34 -0
  62. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/post-processing/link-class-to-tagname.js +27 -0
  63. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/post-processing/remove-unexported-declarations.js +23 -0
  64. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/features/post-processing/resolve-initializers.js +52 -0
  65. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/ast-helpers.js +186 -0
  66. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/cli-helpers.js +164 -0
  67. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/exports.js +44 -0
  68. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/find-external-manifests.js +67 -0
  69. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/imports.js +25 -0
  70. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/index.js +71 -0
  71. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/jsdoc.js +19 -0
  72. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/manifest-helpers.js +194 -0
  73. package/lib/cem/patch/@custom-elements-manifest/analyzer/src/utils/mixins.js +112 -0
  74. package/lib/cem/schema-internal.json +1422 -0
  75. package/lib/cem/schema.json +1098 -0
  76. package/lib/cem/types-internal.d.ts +808 -0
  77. package/lib/cem/types.d.ts +736 -0
  78. package/lib/cem/utils.mjs +423 -0
  79. package/lib/cem/validate.js +76 -0
  80. package/lib/chokidar/chokidar.js +28 -0
  81. package/lib/copy-and-watch/index.js +153 -0
  82. package/lib/copy-list/index.js +34 -0
  83. package/lib/create-icons/index.js +131 -54
  84. package/lib/create-illustrations/index.js +204 -0
  85. package/lib/create-new-component/Component.js +74 -0
  86. package/lib/create-new-component/ComponentTemplate.js +12 -0
  87. package/lib/create-new-component/index.js +66 -93
  88. package/lib/css-processors/css-processor-components.mjs +92 -0
  89. package/lib/css-processors/css-processor-themes.mjs +102 -0
  90. package/lib/css-processors/scope-variables.mjs +49 -0
  91. package/lib/css-processors/shared.mjs +46 -0
  92. package/lib/dev-server/custom-hot-update-plugin.js +39 -0
  93. package/lib/dev-server/dev-server.mjs +78 -0
  94. package/lib/dev-server/virtual-index-html-plugin.js +56 -0
  95. package/lib/eslint/eslint.js +44 -0
  96. package/lib/generate-js-imports/illustrations.js +85 -0
  97. package/lib/generate-json-imports/i18n.js +91 -47
  98. package/lib/generate-json-imports/themes.js +63 -19
  99. package/lib/hbs2lit/index.js +2 -4
  100. package/lib/hbs2lit/src/compiler.js +30 -9
  101. package/lib/hbs2lit/src/includesReplacer.js +23 -17
  102. package/lib/hbs2lit/src/litVisitor2.js +125 -26
  103. package/lib/hbs2lit/src/svgProcessor.js +12 -5
  104. package/lib/hbs2ui5/RenderTemplates/LitRenderer.js +40 -7
  105. package/lib/hbs2ui5/index.js +69 -30
  106. package/lib/i18n/defaults.js +79 -46
  107. package/lib/i18n/toJSON.js +54 -16
  108. package/lib/icons-hash/icons-hash.mjs +149 -0
  109. package/lib/postcss-combine-duplicated-selectors/index.js +185 -0
  110. package/lib/remove-dev-mode/remove-dev-mode.mjs +51 -0
  111. package/lib/rimraf/rimraf.js +31 -0
  112. package/lib/scoping/get-all-tags.js +44 -0
  113. package/lib/scoping/lint-src.js +32 -0
  114. package/lib/scoping/missing-dependencies.js +65 -0
  115. package/lib/scoping/report-tags-usage.js +28 -0
  116. package/lib/scoping/scope-test-pages.js +41 -0
  117. package/lib/test-runner/test-runner.js +79 -0
  118. package/lib/vite-bundler/vite-bundler.mjs +35 -0
  119. package/package.json +64 -60
  120. package/tsconfig.json +18 -0
  121. package/bin/init-ui5-package.js +0 -3
  122. package/components-package/rollup.js +0 -134
  123. package/components-package/serve.json +0 -3
  124. package/lib/documentation/index.js +0 -143
  125. package/lib/documentation/templates/api-component-since.js +0 -3
  126. package/lib/documentation/templates/api-css-variables-section.js +0 -24
  127. package/lib/documentation/templates/api-events-section.js +0 -35
  128. package/lib/documentation/templates/api-methods-section.js +0 -26
  129. package/lib/documentation/templates/api-properties-section.js +0 -40
  130. package/lib/documentation/templates/api-slots-section.js +0 -28
  131. package/lib/documentation/templates/template.js +0 -38
  132. package/lib/init-package/index.js +0 -119
  133. package/lib/init-package/resources/.eslintignore +0 -3
  134. package/lib/init-package/resources/bundle.es5.js +0 -25
  135. package/lib/init-package/resources/bundle.esm.js +0 -34
  136. package/lib/init-package/resources/config/.eslintrc.js +0 -1
  137. package/lib/init-package/resources/config/postcss.components/postcss.config.js +0 -1
  138. package/lib/init-package/resources/config/postcss.themes/postcss.config.js +0 -1
  139. package/lib/init-package/resources/config/rollup.config.js +0 -1
  140. package/lib/init-package/resources/config/wdio.conf.js +0 -1
  141. package/lib/init-package/resources/package-scripts.js +0 -11
  142. package/lib/init-package/resources/src/Assets.js +0 -6
  143. package/lib/init-package/resources/src/Demo.hbs +0 -1
  144. package/lib/init-package/resources/src/Demo.js +0 -56
  145. package/lib/init-package/resources/src/i18n/messagebundle.properties +0 -2
  146. package/lib/init-package/resources/src/i18n/messagebundle_de.properties +0 -1
  147. package/lib/init-package/resources/src/i18n/messagebundle_en.properties +0 -1
  148. package/lib/init-package/resources/src/i18n/messagebundle_es.properties +0 -1
  149. package/lib/init-package/resources/src/i18n/messagebundle_fr.properties +0 -1
  150. package/lib/init-package/resources/src/themes/Demo.css +0 -11
  151. package/lib/init-package/resources/src/themes/sap_belize/parameters-bundle.css +0 -3
  152. package/lib/init-package/resources/src/themes/sap_belize_hcb/parameters-bundle.css +0 -3
  153. package/lib/init-package/resources/src/themes/sap_fiori_3/parameters-bundle.css +0 -3
  154. package/lib/init-package/resources/src/themes/sap_fiori_3_dark/parameters-bundle.css +0 -3
  155. package/lib/init-package/resources/test/pages/index.html +0 -51
  156. package/lib/init-package/resources/test/specs/Demo.spec.js +0 -12
  157. package/lib/jsdoc/config.json +0 -29
  158. package/lib/jsdoc/plugin.js +0 -2407
  159. package/lib/jsdoc/template/publish.js +0 -4092
  160. package/lib/postcss-css-to-esm/index.js +0 -33
  161. package/lib/postcss-css-to-json/index.js +0 -20
@@ -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
+ }
@@ -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
+
@@ -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
+ }
@@ -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
+ }