@ui5/webcomponents-tools 0.0.0-3790e6927 → 0.0.0-38861c872

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 (39) hide show
  1. package/CHANGELOG.md +348 -0
  2. package/README.md +2 -1
  3. package/assets-meta.js +16 -7
  4. package/components-package/eslint.js +2 -0
  5. package/components-package/nps.js +37 -30
  6. package/components-package/postcss.components.js +1 -21
  7. package/components-package/postcss.themes.js +1 -36
  8. package/components-package/vite.config.js +0 -3
  9. package/components-package/wdio.js +6 -2
  10. package/icons-collection/nps.js +6 -4
  11. package/lib/cem/custom-elements-manifest.config.mjs +463 -0
  12. package/lib/cem/event.mjs +114 -0
  13. package/lib/cem/schema-internal.json +1354 -0
  14. package/lib/cem/schema.json +1098 -0
  15. package/lib/cem/types-internal.d.ts +1032 -0
  16. package/lib/cem/types.d.ts +871 -0
  17. package/lib/cem/utils.mjs +355 -0
  18. package/lib/cem/validate.js +63 -0
  19. package/lib/create-illustrations/index.js +32 -28
  20. package/lib/create-new-component/index.js +1 -1
  21. package/lib/create-new-component/tsFileContentTemplate.js +2 -11
  22. package/lib/css-processors/css-processor-components.mjs +77 -0
  23. package/lib/css-processors/css-processor-themes.mjs +79 -0
  24. package/lib/css-processors/scope-variables.mjs +46 -0
  25. package/lib/{postcss-css-to-esm/index.js → css-processors/shared.mjs} +36 -50
  26. package/lib/dev-server/custom-hot-update-plugin.js +39 -0
  27. package/lib/esm-abs-to-rel/index.js +4 -1
  28. package/lib/generate-custom-elements-manifest/index.js +1 -1
  29. package/lib/generate-js-imports/illustrations.js +78 -64
  30. package/lib/generate-json-imports/i18n.js +10 -5
  31. package/lib/generate-json-imports/themes.js +10 -5
  32. package/lib/jsdoc/preprocess.js +1 -1
  33. package/lib/postcss-combine-duplicated-selectors/index.js +12 -5
  34. package/lib/scoping/get-all-tags.js +1 -1
  35. package/lib/scoping/scope-test-pages.js +2 -1
  36. package/package.json +9 -10
  37. package/lib/postcss-css-to-json/index.js +0 -47
  38. package/lib/postcss-new-files/index.js +0 -36
  39. package/lib/postcss-p/postcss-p.mjs +0 -14
@@ -0,0 +1,355 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ let JSDocErrors = [];
5
+
6
+ const getDeprecatedStatus = (jsdocComment) => {
7
+ const deprecatedTag = findTag(jsdocComment, "deprecated");
8
+ return deprecatedTag?.name
9
+ ? deprecatedTag.description
10
+ ? `${deprecatedTag.name} ${deprecatedTag.description}`
11
+ : deprecatedTag.name
12
+ : deprecatedTag
13
+ ? true
14
+ : undefined;
15
+ };
16
+
17
+ const normalizeDescription = (description) => {
18
+ return typeof description === 'string' ? description.replaceAll(/^-\s+|^(\n)+|(\n)+$/g, ""): description;
19
+ }
20
+
21
+ const getTypeRefs = (ts, classNodeMember, member) => {
22
+ const extractTypeRefs = (type) => {
23
+ if (type?.kind === ts.SyntaxKind.TypeReference) {
24
+ return type.typeArguments?.length
25
+ ? type.typeArguments.map((typeRef) => typeRef.typeName?.text)
26
+ : [type.typeName?.text];
27
+ } else if (type?.kind === ts.SyntaxKind.UnionType) {
28
+ return type.types
29
+ .map((type) => extractTypeRefs(type))
30
+ .flat(1);
31
+ } else if (type?.kind === ts.SyntaxKind.TemplateLiteralType) {
32
+ if (member.type) {
33
+ member.type.text = member.type.text.replaceAll?.(/`|\${|}/g, "");
34
+ }
35
+
36
+ return type.templateSpans?.length
37
+ ? type.templateSpans.map((typeRef) => typeRef.type?.typeName?.text)
38
+ : [type.typeName?.text];
39
+ }
40
+ };
41
+
42
+ let typeRefs = extractTypeRefs(classNodeMember.type);
43
+
44
+ if (typeRefs) {
45
+ typeRefs = typeRefs.filter((e) => !!e);
46
+ }
47
+
48
+ return typeRefs?.length ? typeRefs : undefined;
49
+ };
50
+
51
+ const getSinceStatus = (jsdocComment) => {
52
+ const sinceTag = findTag(jsdocComment, "since");
53
+ return sinceTag
54
+ ? sinceTag.description
55
+ ? `${sinceTag.name} ${sinceTag.description}`
56
+ : sinceTag.name
57
+ : undefined;
58
+ };
59
+
60
+ const getPrivacyStatus = (jsdocComment) => {
61
+ const privacyTag = findTag(jsdocComment, ["public", "private", "protected"]);
62
+ return privacyTag?.tag || "private";
63
+ };
64
+
65
+ const findPackageName = (ts, sourceFile, typeName, packageJSON) => {
66
+ const localStatements = [
67
+ ts.SyntaxKind.EnumDeclaration,
68
+ ts.SyntaxKind.InterfaceDeclaration,
69
+ ts.SyntaxKind.ClassDeclaration,
70
+ ts.SyntaxKind.TypeAliasDeclaration,
71
+ ];
72
+
73
+ const isLocalDeclared = sourceFile.statements.some(
74
+ (statement) =>
75
+ localStatements.includes(statement.kind) && statement?.name?.text === typeName
76
+ );
77
+
78
+ if (isLocalDeclared) {
79
+ return packageJSON?.name;
80
+ } else {
81
+ const importStatements = sourceFile.statements?.filter(
82
+ (statement) => statement.kind === ts.SyntaxKind.ImportDeclaration
83
+ );
84
+ const currentModuleSpecifier = importStatements.find((statement) => {
85
+ if (statement.importClause?.name?.text === typeName) {
86
+ return true;
87
+ }
88
+
89
+ return statement.importClause?.namedBindings?.elements?.some(
90
+ (element) => element.name?.text === typeName
91
+ );
92
+ })?.moduleSpecifier;
93
+
94
+ if (currentModuleSpecifier?.text?.startsWith(".")) {
95
+ return packageJSON?.name;
96
+ } else {
97
+ return Object.keys(packageJSON?.dependencies || {}).find(
98
+ (dependency) =>
99
+ currentModuleSpecifier?.text?.startsWith(`${dependency}/`)
100
+ );
101
+ }
102
+ }
103
+ };
104
+
105
+ const findImportPath = (ts, sourceFile, typeName, packageJSON, modulePath) => {
106
+ const localStatements = [
107
+ ts.SyntaxKind.EnumDeclaration,
108
+ ts.SyntaxKind.InterfaceDeclaration,
109
+ ts.SyntaxKind.ClassDeclaration,
110
+ ts.SyntaxKind.TypeAliasDeclaration,
111
+ ];
112
+
113
+ const isLocalDeclared = sourceFile.statements.some(
114
+ (statement) =>
115
+ localStatements.includes(statement.kind) && statement?.name?.text === typeName
116
+ );
117
+
118
+ if (isLocalDeclared) {
119
+ return (
120
+ modulePath?.replace("src", "dist")?.replace(".ts", ".js") || undefined
121
+ );
122
+ } else {
123
+ const importStatements = sourceFile.statements?.filter(
124
+ (statement) => statement.kind === ts.SyntaxKind.ImportDeclaration
125
+ );
126
+ const currentModuleSpecifier = importStatements.find((statement) => {
127
+ if (statement.importClause?.name?.text === typeName) {
128
+ return true;
129
+ }
130
+
131
+ return statement.importClause?.namedBindings?.elements?.some(
132
+ (element) => element.name?.text === typeName
133
+ );
134
+ })?.moduleSpecifier;
135
+
136
+ if (currentModuleSpecifier?.text?.startsWith(".")) {
137
+ return (
138
+ path.join(path.dirname(modulePath), currentModuleSpecifier.text)
139
+ ?.replace("src", "dist")?.replace(".ts", ".js") || undefined
140
+ );
141
+ } else {
142
+ const packageName = Object.keys(packageJSON?.dependencies || {}).find(
143
+ (dependency) =>
144
+ currentModuleSpecifier?.text?.startsWith(dependency)
145
+ );
146
+ return currentModuleSpecifier?.text
147
+ ?.replace(`${packageName}/`, "") || undefined;
148
+ }
149
+ }
150
+ };
151
+
152
+
153
+ const isClass = text => {
154
+ return text.includes("@abstract") || text.includes("@class") || text.includes("@constructor");
155
+ };
156
+
157
+ const normalizeTagType = (type) => {
158
+ return type?.trim();
159
+ }
160
+
161
+ const getReference = (ts, type, classNode, modulePath) => {
162
+ let sourceFile = classNode.parent;
163
+
164
+ while (sourceFile && sourceFile.kind !== ts.SyntaxKind.SourceFile) {
165
+ sourceFile = sourceFile.parent;
166
+ }
167
+
168
+ const packageJSON = JSON.parse(fs.readFileSync("./package.json"));
169
+
170
+ const typeName =
171
+ typeof type === "string"
172
+ ? normalizeTagType(type)
173
+ : type.class?.expression?.text ||
174
+ type.typeExpression?.type?.getText() ||
175
+ type.typeExpression?.type?.elementType?.typeName?.text;
176
+ const packageName = findPackageName(ts, sourceFile, typeName, packageJSON);
177
+ const importPath = findImportPath(
178
+ ts,
179
+ sourceFile,
180
+ typeName,
181
+ packageJSON,
182
+ modulePath
183
+ );
184
+
185
+ return packageName && {
186
+ name: typeName,
187
+ package: packageName,
188
+ module: importPath,
189
+ };
190
+ };
191
+
192
+ const getType = (type) => {
193
+ const typeName = typeof type === "string" ? normalizeTagType(type) : type?.type;
194
+
195
+ const multiple =
196
+ typeName?.endsWith("[]") || typeName?.startsWith("Array<");
197
+ const name = multiple
198
+ ? typeName?.replace("[]", "")?.replace("Array<", "")?.replace(">", "")
199
+ : typeName;
200
+
201
+ return typeName ? { typeName: multiple ? `Array<${name}>` : typeName, name, multiple } : undefined;
202
+ };
203
+
204
+ const commonTags = ["public", "protected", "private", "since", "deprecated"];
205
+
206
+ const allowedTags = {
207
+ field: [...commonTags, "formEvents", "formProperty", "default"],
208
+ slot: [...commonTags, "default"],
209
+ event: [...commonTags, "param", "allowPreventDefault", "native"],
210
+ eventParam: [...commonTags],
211
+ method: [...commonTags, "param", "returns", "override"],
212
+ class: [...commonTags, "constructor", "class", "abstract", "implements", "extends", "slot", "csspart"],
213
+ enum: [...commonTags],
214
+ enumMember: [...commonTags],
215
+ interface: [...commonTags],
216
+ };
217
+ allowedTags.getter = [...allowedTags.field, "override"]
218
+
219
+ const tagMatchCallback = (tag, tagName) => {
220
+ const currentTagName = tag.tag;
221
+
222
+ return typeof tagName === "string"
223
+ ? currentTagName === tagName
224
+ : tagName.includes(currentTagName);
225
+ };
226
+
227
+ const findDecorator = (node, decoratorName) => {
228
+ return node?.decorators?.find(
229
+ (decorator) =>
230
+ decorator?.expression?.expression?.text === decoratorName
231
+ );
232
+ };
233
+
234
+ const findAllDecorators = (node, decoratorName) => {
235
+ return (
236
+ node?.decorators?.filter(
237
+ (decorator) =>
238
+ decorator?.expression?.expression?.text === decoratorName
239
+ ) || []
240
+ );
241
+ };
242
+
243
+ const hasTag = (jsDoc, tagName) => {
244
+ if (!jsDoc) {
245
+ return;
246
+ }
247
+
248
+ return jsDoc?.tags?.some((tag) => tagMatchCallback(tag, tagName));
249
+ };
250
+
251
+ const findTag = (jsDoc, tagName) => {
252
+ if (!jsDoc) {
253
+ return;
254
+ }
255
+
256
+ return jsDoc?.tags?.find((tag) => tagMatchCallback(tag, tagName));
257
+ };
258
+
259
+ const findAllTags = (jsDoc, tagName) => {
260
+ if (!jsDoc) {
261
+ return [];
262
+ }
263
+
264
+ const foundTags = jsDoc?.tags?.filter((tag) => tagMatchCallback(tag, tagName));
265
+
266
+ return foundTags || [];
267
+ };
268
+
269
+ const validateJSDocTag = (tag) => {
270
+ const booleanTags = ["private", "protected", "public", "abstract", "allowPreventDefault", "native", "formProperty", "constructor", "override"];
271
+ let tagName = tag.tag;
272
+
273
+ if (booleanTags.includes(tag.tag)) {
274
+ tagName = "boolean";
275
+ }
276
+
277
+ switch (tagName) {
278
+ case "boolean":
279
+ return !tag.name && !tag.type && !tag.description;
280
+ case "deprecated":
281
+ return !tag.type;
282
+ case "extends":
283
+ return !tag.type && tag.name && !tag.description;
284
+ case "implements":
285
+ return tag.type && !tag.name && !tag.description;
286
+ case "slot":
287
+ return tag.type && tag.name && tag.description;
288
+ case "csspart":
289
+ return !tag.type && tag.name && tag.description;
290
+ case "since":
291
+ return !tag.type && tag.name;
292
+ case "returns":
293
+ return !tag.type && tag.name;
294
+ case "default":
295
+ return !tag.type && !tag.description;
296
+ case "class":
297
+ return !tag.type;
298
+ case "param":
299
+ return !tag.type && tag.name;
300
+ case "eventparam":
301
+ return tag.type && tag.name;
302
+ case "formEvents":
303
+ return !tag.type && tag.name;
304
+ default:
305
+ return false;
306
+ }
307
+ };
308
+
309
+ const validateJSDocComment = (fieldType, jsdocComment, node, moduleDoc) => {
310
+ return !!jsdocComment?.tags?.every((tag) => {
311
+ let isValid = false
312
+
313
+ if (fieldType === "event" && tag?.tag === "param") {
314
+ isValid = allowedTags[fieldType]?.includes(tag.tag) && validateJSDocTag({...tag, tag: "eventparam"});
315
+ } else {
316
+ isValid = allowedTags[fieldType]?.includes(tag.tag) && validateJSDocTag(tag);
317
+ }
318
+
319
+ if (!isValid) {
320
+ JSDocErrors.push(
321
+ `=== ERROR: Problem found with ${node}'s JSDoc comment in ${moduleDoc.path}: \n\t- @${tag.tag} tag is being used wrong or it's not part of ${fieldType} JSDoc tags`
322
+ );
323
+ }
324
+
325
+ return !!isValid;
326
+ });
327
+ };
328
+
329
+ const getJSDocErrors = () => {
330
+ return JSDocErrors;
331
+ };
332
+
333
+ const formatArrays = (typeText) => {
334
+ return typeText.replaceAll(/(\S+)\[\]/g, "Array<$1>")
335
+ }
336
+
337
+ export {
338
+ getPrivacyStatus,
339
+ getSinceStatus,
340
+ getDeprecatedStatus,
341
+ getType,
342
+ getReference,
343
+ validateJSDocComment,
344
+ findDecorator,
345
+ findAllDecorators,
346
+ hasTag,
347
+ findTag,
348
+ findAllTags,
349
+ getJSDocErrors,
350
+ getTypeRefs,
351
+ normalizeDescription,
352
+ formatArrays,
353
+ isClass,
354
+ normalizeTagType
355
+ };
@@ -0,0 +1,63 @@
1
+ const fs = require('fs');
2
+ const Ajv = require('ajv');
3
+ const path = require('path');
4
+
5
+ // Load your JSON schema
6
+ const extenalSchema = require('./schema.json');
7
+ const internalSchema = require('./schema-internal.json');
8
+
9
+ // Load your JSON data from the input file
10
+ const inputFilePath = path.join(process.cwd(), "dist/custom-elements.json"); // Update with your file path
11
+ const customManifest = fs.readFileSync(inputFilePath, 'utf8');
12
+ const inputDataInternal = JSON.parse(customManifest);
13
+
14
+ const clearProps = (data) => {
15
+ if (Array.isArray(data)) {
16
+ for (let i = 0; i < data.length; i++) {
17
+ if (typeof data[i] === "object") {
18
+ if (["enum", "interface"].includes(data[i].kind)) {
19
+ data.splice(i, 1);
20
+ i--;
21
+ } else {
22
+ clearProps(data[i]);
23
+ }
24
+ }
25
+ }
26
+ } else if (typeof data === "object") {
27
+ Object.keys(data).forEach(prop => {
28
+ if (prop.startsWith("_ui5")) {
29
+ delete data[prop];
30
+ } else if (typeof data[prop] === "object") {
31
+ clearProps(data[prop]);
32
+ }
33
+ });
34
+ }
35
+
36
+ return data;
37
+ }
38
+
39
+ const inputDataExternal = clearProps(JSON.parse(JSON.stringify(inputDataInternal)));
40
+
41
+ const ajv = new Ajv({ allowUnionTypes: true, allError: true })
42
+
43
+ let validate = ajv.compile(internalSchema)
44
+
45
+ // Validate the JSON data against the schema
46
+ if (validate(inputDataInternal)) {
47
+ console.log('Validation internal custom-elements successful');
48
+ } else {
49
+ console.error('Validation of internal custom-elements failed');
50
+ // console.error('Validation of internal custom-elements failed:', validate.errors);
51
+ }
52
+
53
+ validate = ajv.compile(extenalSchema)
54
+
55
+ // Validate the JSON data against the schema
56
+ if (validate(inputDataExternal)) {
57
+ console.log('Validation external custom-elements successful');
58
+ fs.writeFileSync(inputFilePath, JSON.stringify(inputDataExternal, null, 2), 'utf8');
59
+ fs.writeFileSync(inputFilePath.replace("custom-elements", "custom-elements-internal"), JSON.stringify(inputDataInternal, null, 2), 'utf8');
60
+ } else {
61
+ console.error('Validation of external custom-elements failed:');
62
+ // console.error('Validation of external custom-elements failed:', ajv.errorsText(validate.errors));
63
+ }
@@ -57,15 +57,25 @@ const generate = async () => {
57
57
  const illustrationsPrefix = process.argv[4];
58
58
  const illustrationSet = process.argv[5];
59
59
  const destPath = process.argv[6];
60
+ const collection = process.argv[7];
60
61
  const fileNamePattern = new RegExp(`${illustrationsPrefix}-.+-(.+).svg`);
61
- // collect each illustration name because each one should have Sample.js file
62
+ // collect each illustration name because each one should have Sample.js file
62
63
  const fileNames = new Set();
63
64
 
65
+ try {
66
+ await fs.access(srcPath);
67
+ } catch (error) {
68
+ console.log(`The path ${srcPath} does not exist.`);
69
+ return Promise.resolve(null);
70
+ }
71
+
72
+ console.log(`Generating illustrations from ${srcPath} to ${destPath}`)
73
+
64
74
  const svgImportTemplate = svgContent => {
65
75
  return `export default \`${svgContent}\`;`
66
76
  };
67
77
  const svgToJs = async fileName => {
68
- const svg = await fs.readFile(path.join(srcPath, fileName), {encoding: "utf-8"});
78
+ const svg = await fs.readFile(path.join(srcPath, fileName), { encoding: "utf-8" });
69
79
  const fileContent = svgImportTemplate(svg);
70
80
  fileName = fileName.replace(/\.svg$/, ".js");
71
81
 
@@ -84,54 +94,47 @@ const generate = async () => {
84
94
 
85
95
  const illustrationNameUpperCase = illustrationNameForTranslation.toUpperCase();
86
96
 
87
- return defaultText ? `import { registerIllustration } from "@ui5/webcomponents-base/dist/asset-registries/Illustrations.js";
97
+ return `import { registerIllustration } from "@ui5/webcomponents-base/dist/asset-registries/Illustrations.js";
88
98
  import dialogSvg from "./${illustrationsPrefix}-Dialog-${illustrationName}.js";
89
99
  import sceneSvg from "./${illustrationsPrefix}-Scene-${illustrationName}.js";
90
- import spotSvg from "./${illustrationsPrefix}-Spot-${illustrationName}.js";
91
- import {
100
+ import spotSvg from "./${illustrationsPrefix}-Spot-${illustrationName}.js";${
101
+ defaultText ? `import {
92
102
  IM_TITLE_${illustrationNameUpperCase},
93
103
  IM_SUBTITLE_${illustrationNameUpperCase},
94
- } from "../generated/i18n/i18n-defaults.js";
104
+ } from "../generated/i18n/i18n-defaults.js";` : ``}
95
105
 
96
106
  const name = "${illustrationName}";
97
107
  const set = "${illustrationSet}";
108
+ const collection = "${collection}";${defaultText ? `
98
109
  const title = IM_TITLE_${illustrationNameUpperCase};
99
- const subtitle = IM_SUBTITLE_${illustrationNameUpperCase};
110
+ const subtitle = IM_SUBTITLE_${illustrationNameUpperCase};` : ``}
100
111
 
101
112
  registerIllustration(name, {
102
113
  dialogSvg,
103
114
  sceneSvg,
104
- spotSvg,
115
+ spotSvg,${defaultText ? `
105
116
  title,
106
- subtitle,
117
+ subtitle,` : ``}
107
118
  set,
119
+ collection,
108
120
  });
109
121
 
122
+ export default "${illustrationSet === "fiori" ? "" : `${illustrationSet}/`}${illustrationName}";
110
123
  export {
111
124
  dialogSvg,
112
125
  sceneSvg,
113
126
  spotSvg,
114
- };` :
115
- `import { registerIllustration } from "@ui5/webcomponents-base/dist/asset-registries/Illustrations.js";
116
- import dialogSvg from "./${illustrationsPrefix}-Dialog-${illustrationName}.js";
117
- import sceneSvg from "./${illustrationsPrefix}-Scene-${illustrationName}.js";
118
- import spotSvg from "./${illustrationsPrefix}-Spot-${illustrationName}.js";
119
-
120
- const name = "${illustrationName}";
121
- const set = "${illustrationSet}";
127
+ };`
128
+ };
122
129
 
123
- registerIllustration(name, {
124
- dialogSvg,
125
- sceneSvg,
126
- spotSvg,
127
- set,
128
- });
130
+ const illustrationTypeDefinition = illustrationName => {
131
+ return `declare const dialogSvg: string;
132
+ declare const sceneSvg: string;
133
+ declare const spotSvg: string;
134
+ declare const _default: "${illustrationSet === "fiori" ? "" : `${illustrationSet}/`}${illustrationName}";
129
135
 
130
- export {
131
- dialogSvg,
132
- sceneSvg,
133
- spotSvg,
134
- };`
136
+ export default _default;
137
+ export { dialogSvg, sceneSvg, spotSvg };`
135
138
  };
136
139
 
137
140
  await fs.mkdir(destPath, { recursive: true });
@@ -151,6 +154,7 @@ export {
151
154
 
152
155
  for (let illustrationName of fileNames) {
153
156
  promises.push(fs.writeFile(path.join(destPath, `${illustrationName}.js`), illustrationImportTemplate(illustrationName)));
157
+ promises.push(fs.writeFile(path.join(destPath, `${illustrationName}.d.ts`), illustrationTypeDefinition(illustrationName)));
154
158
  }
155
159
 
156
160
  return Promise.all(promises);
@@ -83,7 +83,7 @@ const generateFiles = (componentName, tagName, library, packageName, isTypeScrip
83
83
  // Change the color of the output
84
84
  console.warn('\x1b[33m%s\x1b[0m', `
85
85
  Make sure to import the component in your bundle by using:
86
- import ${componentName} from "./dist/${componentName}.js";`);
86
+ import "./dist/${componentName}.js";`);
87
87
  }
88
88
 
89
89
  // Main function
@@ -25,10 +25,7 @@ import ${componentName}Css from "./generated/themes/${componentName}.css.js";
25
25
  * <code>import ${packageName}/dist/${componentName}.js";</code>
26
26
  *
27
27
  * @constructor
28
- * @author SAP SE
29
- * @alias sap.ui.webc.${library}.${componentName}
30
- * @extends sap.ui.webc.base.UI5Element
31
- * @tagname ${tagName}
28
+ * @extends UI5Element
32
29
  * @public
33
30
  */
34
31
  @customElement({
@@ -43,7 +40,6 @@ import ${componentName}Css from "./generated/themes/${componentName}.css.js";
43
40
  * Example custom event.
44
41
  * Please keep in mind that all public events should be documented in the API Reference as shown below.
45
42
  *
46
- * @event sap.ui.webc.${library}.${componentName}#interact
47
43
  * @public
48
44
  */
49
45
  @event("interact", { detail: { /* event payload ( optional ) */ } })
@@ -51,9 +47,7 @@ class ${componentName} extends UI5Element {
51
47
  /**
52
48
  * Defines the value of the component.
53
49
  *
54
- * @type {string}
55
- * @name sap.ui.webc.${library}.${componentName}.prototype.value
56
- * @defaultvalue ""
50
+ * @default ""
57
51
  * @public
58
52
  */
59
53
  @property()
@@ -62,9 +56,6 @@ class ${componentName} extends UI5Element {
62
56
  /**
63
57
  * Defines the text of the component.
64
58
  *
65
- * @type {Node[]}
66
- * @name sap.ui.webc.${library}.${componentName}.prototype.default
67
- * @slot
68
59
  * @public
69
60
  */
70
61
  @slot({ type: Node, "default": true })
@@ -0,0 +1,77 @@
1
+ import { globby } from "globby";
2
+ import * as esbuild from 'esbuild'
3
+ import * as fs from "fs";
4
+ import * as path from "path";
5
+ import { writeFile, mkdir } from "fs/promises";
6
+ import chokidar from "chokidar";
7
+ import scopeVariables from "./scope-variables.mjs";
8
+ import { writeFileIfChanged, getFileContent } from "./shared.mjs";
9
+
10
+ const tsMode = process.env.UI5_TS === "true";
11
+ const extension = tsMode ? ".css.ts" : ".css.js";
12
+
13
+ const packageJSON = JSON.parse(fs.readFileSync("./package.json"))
14
+ const inputFilesGlob = "src/themes/*.css";
15
+ const restArgs = process.argv.slice(2);
16
+
17
+ let customPlugin = {
18
+ name: 'ui5-tools',
19
+ setup(build) {
20
+ build.initialOptions.write = false;
21
+
22
+ build.onEnd(result => {
23
+ result.outputFiles.forEach(async f => {
24
+ // scoping
25
+ const newText = scopeVariables(f.text, packageJSON);
26
+ await mkdir(path.dirname(f.path), {recursive: true});
27
+ writeFile(f.path, newText);
28
+
29
+ // JS/TS
30
+ const jsPath = f.path.replace(/dist[\/\\]css/, "src/generated/").replace(".css", extension);
31
+ const jsContent = getFileContent(tsMode, jsPath, packageJSON.name, "\`" + newText + "\`", true);
32
+ writeFileIfChanged(jsPath, jsContent);
33
+ });
34
+ })
35
+ },
36
+ }
37
+
38
+ const getConfig = async () => {
39
+ const config = {
40
+ entryPoints: await globby(inputFilesGlob),
41
+ bundle: true,
42
+ minify: true,
43
+ outdir: 'dist/css',
44
+ outbase: 'src',
45
+ plugins: [
46
+ customPlugin,
47
+ ]
48
+ };
49
+ return config;
50
+ }
51
+
52
+ if (restArgs.includes("-w")) {
53
+ let ready;
54
+ let config = await getConfig();
55
+ let ctx = await esbuild.context(config);
56
+ await ctx.watch()
57
+ console.log('watching...')
58
+
59
+ // when new component css files are added, they do not trigger a build as no one directly imports them
60
+ // restart the watch mode with the new entry points if a css file is added.
61
+ const watcher = chokidar.watch(inputFilesGlob);
62
+ watcher.on("ready", () => {
63
+ ready = true; // Initial scan is over -> waiting for new files
64
+ });
65
+ watcher.on("add", async path => {
66
+ if (ready) {
67
+ // new file
68
+ ctx.dispose();
69
+ config = await getConfig();
70
+ ctx = await esbuild.context(config);
71
+ ctx.watch();
72
+ }
73
+ });
74
+ } else {
75
+ const config = await getConfig();
76
+ const result = await esbuild.build(config);
77
+ }