@ui5/webcomponents-tools 0.0.0-dcd8e5389 → 0.0.0-ddc5fe31b

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 (43) hide show
  1. package/CHANGELOG.md +413 -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 +38 -31
  6. package/components-package/postcss.components.js +1 -21
  7. package/components-package/postcss.themes.js +1 -26
  8. package/components-package/wdio.js +15 -3
  9. package/components-package/wdio.sync.js +9 -1
  10. package/icons-collection/nps.js +8 -6
  11. package/lib/amd-to-es6/index.js +104 -0
  12. package/lib/cem/custom-elements-manifest.config.mjs +482 -0
  13. package/lib/cem/event.mjs +131 -0
  14. package/lib/cem/schema-internal.json +1357 -0
  15. package/lib/cem/schema.json +1098 -0
  16. package/lib/cem/types-internal.d.ts +802 -0
  17. package/lib/cem/types.d.ts +736 -0
  18. package/lib/cem/utils.mjs +379 -0
  19. package/lib/cem/validate.js +65 -0
  20. package/lib/create-illustrations/index.js +32 -28
  21. package/lib/create-new-component/index.js +1 -1
  22. package/lib/create-new-component/tsFileContentTemplate.js +2 -11
  23. package/lib/css-processors/css-processor-components.mjs +77 -0
  24. package/lib/css-processors/css-processor-themes.mjs +79 -0
  25. package/lib/css-processors/scope-variables.mjs +46 -0
  26. package/lib/{postcss-css-to-esm/index.js → css-processors/shared.mjs} +36 -50
  27. package/lib/dev-server/custom-hot-update-plugin.js +39 -0
  28. package/lib/generate-custom-elements-manifest/index.js +51 -107
  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/hbs2lit/src/litVisitor2.js +1 -1
  33. package/lib/hbs2ui5/RenderTemplates/LitRenderer.js +4 -4
  34. package/lib/jsdoc/preprocess.js +1 -1
  35. package/lib/postcss-combine-duplicated-selectors/index.js +12 -5
  36. package/lib/scoping/get-all-tags.js +1 -1
  37. package/lib/scoping/scope-test-pages.js +2 -1
  38. package/package.json +9 -9
  39. package/lib/esm-abs-to-rel/index.js +0 -58
  40. package/lib/postcss-css-to-json/index.js +0 -47
  41. package/lib/postcss-new-files/index.js +0 -36
  42. package/lib/postcss-p/postcss-p.mjs +0 -14
  43. package/lib/replace-global-core/index.js +0 -25
@@ -0,0 +1,379 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ let documentationErrors = new Map();
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, node, 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.ArrayType) {
28
+ return [type.elementType?.typeName?.text];
29
+ } else if (type?.kind === ts.SyntaxKind.UnionType) {
30
+ return type.types
31
+ .map((type) => extractTypeRefs(type))
32
+ .flat(1);
33
+ } else if (type?.kind === ts.SyntaxKind.TemplateLiteralType) {
34
+ if (member?.type) {
35
+ member.type.text = member.type.text.replaceAll?.(/`|\${|}/g, "");
36
+ }
37
+
38
+ return type.templateSpans?.length
39
+ ? type.templateSpans.map((typeRef) => typeRef.type?.typeName?.text)
40
+ : [type.typeName?.text];
41
+ }
42
+ };
43
+
44
+ let typeRefs = extractTypeRefs(node.type) || node?.typeArguments?.map(n => extractTypeRefs(n)).flat(2);
45
+
46
+ if (typeRefs) {
47
+ typeRefs = typeRefs.filter((e) => !!e);
48
+ }
49
+
50
+ return typeRefs?.length ? typeRefs : undefined;
51
+ };
52
+
53
+ const getSinceStatus = (jsdocComment) => {
54
+ const sinceTag = findTag(jsdocComment, "since");
55
+ return sinceTag
56
+ ? sinceTag.description
57
+ ? `${sinceTag.name} ${sinceTag.description}`
58
+ : sinceTag.name
59
+ : undefined;
60
+ };
61
+
62
+ const getPrivacyStatus = (jsdocComment) => {
63
+ const privacyTag = findTag(jsdocComment, ["public", "private", "protected"]);
64
+ return privacyTag?.tag || "private";
65
+ };
66
+
67
+ const findPackageName = (ts, sourceFile, typeName) => {
68
+ const localStatements = [
69
+ ts.SyntaxKind.EnumDeclaration,
70
+ ts.SyntaxKind.InterfaceDeclaration,
71
+ ts.SyntaxKind.ClassDeclaration,
72
+ ts.SyntaxKind.TypeAliasDeclaration,
73
+ ];
74
+
75
+ const isLocalDeclared = sourceFile.statements.some(
76
+ (statement) =>
77
+ localStatements.includes(statement.kind) && statement?.name?.text === typeName
78
+ );
79
+
80
+ if (isLocalDeclared) {
81
+ return packageJSON?.name;
82
+ } else {
83
+ const importStatements = sourceFile.statements?.filter(
84
+ (statement) => statement.kind === ts.SyntaxKind.ImportDeclaration
85
+ );
86
+ const currentModuleSpecifier = importStatements.find((statement) => {
87
+ if (statement.importClause?.name?.text === typeName) {
88
+ return true;
89
+ }
90
+
91
+ return statement.importClause?.namedBindings?.elements?.some(
92
+ (element) => element.name?.text === typeName
93
+ );
94
+ })?.moduleSpecifier;
95
+
96
+ if (currentModuleSpecifier?.text?.startsWith(".")) {
97
+ return packageJSON?.name;
98
+ } else {
99
+ return Object.keys(packageJSON?.dependencies || {}).find(
100
+ (dependency) =>
101
+ currentModuleSpecifier?.text?.startsWith(`${dependency}/`)
102
+ );
103
+ }
104
+ }
105
+ };
106
+
107
+ const findImportPath = (ts, sourceFile, typeName, modulePath) => {
108
+ const localStatements = [
109
+ ts.SyntaxKind.EnumDeclaration,
110
+ ts.SyntaxKind.InterfaceDeclaration,
111
+ ts.SyntaxKind.ClassDeclaration,
112
+ ts.SyntaxKind.TypeAliasDeclaration,
113
+ ];
114
+
115
+ const isLocalDeclared = sourceFile.statements.some(
116
+ (statement) =>
117
+ localStatements.includes(statement.kind) && statement?.name?.text === typeName
118
+ );
119
+
120
+ if (isLocalDeclared) {
121
+ return (
122
+ modulePath?.replace("src", "dist")?.replace(".ts", ".js") || undefined
123
+ );
124
+ } else {
125
+ const importStatements = sourceFile.statements?.filter(
126
+ (statement) => statement.kind === ts.SyntaxKind.ImportDeclaration
127
+ );
128
+ const currentModuleSpecifier = importStatements.find((statement) => {
129
+ if (statement.importClause?.name?.text === typeName) {
130
+ return true;
131
+ }
132
+
133
+ return statement.importClause?.namedBindings?.elements?.some(
134
+ (element) => element.name?.text === typeName
135
+ );
136
+ })?.moduleSpecifier;
137
+
138
+ if (currentModuleSpecifier?.text?.startsWith(".")) {
139
+ return (
140
+ path.join(path.dirname(modulePath), currentModuleSpecifier.text)
141
+ ?.replace("src", "dist")?.replace(".ts", ".js") || undefined
142
+ );
143
+ } else {
144
+ const packageName = Object.keys(packageJSON?.dependencies || {}).find(
145
+ (dependency) =>
146
+ currentModuleSpecifier?.text?.startsWith(dependency)
147
+ );
148
+ return currentModuleSpecifier?.text
149
+ ?.replace(`${packageName}/`, "") || undefined;
150
+ }
151
+ }
152
+ };
153
+
154
+
155
+ const isClass = text => {
156
+ return text.includes("@abstract") || text.includes("@class") || text.includes("@constructor");
157
+ };
158
+
159
+ const normalizeTagType = (type) => {
160
+ return type?.trim();
161
+ }
162
+
163
+ const packageJSON = JSON.parse(fs.readFileSync("./package.json"));
164
+
165
+ const getReference = (ts, type, classNode, modulePath) => {
166
+ let sourceFile = classNode.parent;
167
+
168
+ while (sourceFile && sourceFile.kind !== ts.SyntaxKind.SourceFile) {
169
+ sourceFile = sourceFile.parent;
170
+ }
171
+
172
+ const typeName =
173
+ typeof type === "string"
174
+ ? normalizeTagType(type)
175
+ : type.class?.expression?.text ||
176
+ type.typeExpression?.type?.getText() ||
177
+ type.typeExpression?.type?.elementType?.typeName?.text;
178
+ const packageName = findPackageName(ts, sourceFile, typeName);
179
+ const importPath = findImportPath(
180
+ ts,
181
+ sourceFile,
182
+ typeName,
183
+ modulePath
184
+ )?.replace(`${packageName}/`, "");
185
+
186
+ return packageName && {
187
+ name: typeName,
188
+ package: packageName,
189
+ module: importPath,
190
+ };
191
+ };
192
+
193
+ const getType = (type) => {
194
+ const typeName = typeof type === "string" ? normalizeTagType(type) : type?.type;
195
+
196
+ const multiple =
197
+ typeName?.endsWith("[]") || typeName?.startsWith("Array<");
198
+ const name = multiple
199
+ ? typeName?.replace("[]", "")?.replace("Array<", "")?.replace(">", "")
200
+ : typeName;
201
+
202
+ return typeName ? { typeName: multiple ? `Array<${name}>` : typeName, name, multiple } : undefined;
203
+ };
204
+
205
+ const commonTags = ["public", "protected", "private", "since", "deprecated"];
206
+
207
+ const allowedTags = {
208
+ field: [...commonTags, "formEvents", "formProperty", "default"],
209
+ slot: [...commonTags, "default"],
210
+ event: [...commonTags, "param", "allowPreventDefault", "native"],
211
+ eventParam: [...commonTags],
212
+ method: [...commonTags, "param", "returns", "override"],
213
+ class: [...commonTags, "constructor", "class", "abstract", "implements", "extends", "slot", "csspart"],
214
+ enum: [...commonTags],
215
+ enumMember: [...commonTags],
216
+ interface: [...commonTags],
217
+ };
218
+ allowedTags.getter = [...allowedTags.field, "override"]
219
+
220
+ const tagMatchCallback = (tag, tagName) => {
221
+ const currentTagName = tag.tag;
222
+
223
+ return typeof tagName === "string"
224
+ ? currentTagName === tagName
225
+ : tagName.includes(currentTagName);
226
+ };
227
+
228
+ const findDecorator = (node, decoratorName) => {
229
+ return node?.decorators?.find(
230
+ (decorator) =>
231
+ decorator?.expression?.expression?.text === decoratorName
232
+ );
233
+ };
234
+
235
+ const findAllDecorators = (node, decoratorName) => {
236
+ return (
237
+ node?.decorators?.filter(
238
+ (decorator) =>
239
+ decorator?.expression?.expression?.text === decoratorName
240
+ ) || []
241
+ );
242
+ };
243
+
244
+ const hasTag = (jsDoc, tagName) => {
245
+ if (!jsDoc) {
246
+ return;
247
+ }
248
+
249
+ return jsDoc?.tags?.some((tag) => tagMatchCallback(tag, tagName));
250
+ };
251
+
252
+ const findTag = (jsDoc, tagName) => {
253
+ if (!jsDoc) {
254
+ return;
255
+ }
256
+
257
+ return jsDoc?.tags?.find((tag) => tagMatchCallback(tag, tagName));
258
+ };
259
+
260
+ const findAllTags = (jsDoc, tagName) => {
261
+ if (!jsDoc) {
262
+ return [];
263
+ }
264
+
265
+ const foundTags = jsDoc?.tags?.filter((tag) => tagMatchCallback(tag, tagName));
266
+
267
+ return foundTags || [];
268
+ };
269
+
270
+ const validateJSDocTag = (tag) => {
271
+ const booleanTags = ["private", "protected", "public", "abstract", "allowPreventDefault", "native", "formProperty", "constructor", "override"];
272
+ let tagName = tag.tag;
273
+
274
+ if (booleanTags.includes(tag.tag)) {
275
+ tagName = "boolean";
276
+ }
277
+
278
+ switch (tagName) {
279
+ case "boolean":
280
+ return !tag.name && !tag.type && !tag.description;
281
+ case "deprecated":
282
+ return !tag.type;
283
+ case "extends":
284
+ return !tag.type && tag.name && !tag.description;
285
+ case "implements":
286
+ return tag.type && !tag.name && !tag.description;
287
+ case "slot":
288
+ return tag.type && tag.name && tag.description;
289
+ case "csspart":
290
+ return !tag.type && tag.name && tag.description;
291
+ case "since":
292
+ return !tag.type && tag.name;
293
+ case "returns":
294
+ return !tag.type && tag.name;
295
+ case "default":
296
+ return !tag.type && !tag.description;
297
+ case "class":
298
+ return !tag.type;
299
+ case "param":
300
+ return !tag.type && tag.name;
301
+ case "eventparam":
302
+ return tag.type && tag.name;
303
+ case "formEvents":
304
+ return !tag.type && tag.name;
305
+ default:
306
+ return false;
307
+ }
308
+ };
309
+
310
+ const validateJSDocComment = (fieldType, jsdocComment, node, moduleDoc) => {
311
+ return !!jsdocComment?.tags?.every((tag) => {
312
+ let isValid = false
313
+
314
+ if (fieldType === "event" && tag?.tag === "param") {
315
+ isValid = allowedTags[fieldType]?.includes(tag.tag) && validateJSDocTag({...tag, tag: "eventparam"});
316
+ } else {
317
+ isValid = allowedTags[fieldType]?.includes(tag.tag) && validateJSDocTag(tag);
318
+ }
319
+
320
+ if (!isValid) {
321
+ logDocumentationError(moduleDoc.path, `Incorrect use of @${tag.tag}. Ensure it is part of ${fieldType} JSDoc tags.`)
322
+ }
323
+
324
+ return !!isValid;
325
+ });
326
+ };
327
+
328
+ const logDocumentationError = (modulePath, message) => {
329
+ let moduleErrors = documentationErrors.get(modulePath);
330
+
331
+ if (!moduleErrors) {
332
+ documentationErrors.set(modulePath, []);
333
+ moduleErrors = documentationErrors.get(modulePath);
334
+ }
335
+
336
+ moduleErrors.push(message);
337
+ }
338
+
339
+ const displayDocumentationErrors = () => {
340
+ let errorsCount = 0;
341
+ [...documentationErrors.keys()].forEach(modulePath => {
342
+ const moduleErrors = documentationErrors.get(modulePath);
343
+
344
+ console.log(`=== ERROR: ${moduleErrors.length > 1 ? `${moduleErrors.length} problems` : "Problem"} found in file: ${modulePath}:`)
345
+ moduleErrors.forEach(moduleError => {
346
+ errorsCount++;
347
+ console.log(`\t- ${moduleError}`)
348
+ })
349
+ })
350
+
351
+ if(errorsCount) {
352
+ throw new Error(`Found ${errorsCount} errors in the description of the public API.`);
353
+ }
354
+ }
355
+
356
+ const formatArrays = (typeText) => {
357
+ return typeText?.replaceAll(/(\S+)\[\]/g, "Array<$1>")
358
+ }
359
+
360
+ export {
361
+ getPrivacyStatus,
362
+ getSinceStatus,
363
+ getDeprecatedStatus,
364
+ getType,
365
+ getReference,
366
+ validateJSDocComment,
367
+ findDecorator,
368
+ findAllDecorators,
369
+ hasTag,
370
+ findTag,
371
+ findAllTags,
372
+ getTypeRefs,
373
+ normalizeDescription,
374
+ formatArrays,
375
+ isClass,
376
+ normalizeTagType,
377
+ displayDocumentationErrors,
378
+ logDocumentationError,
379
+ };
@@ -0,0 +1,65 @@
1
+ const fs = require('fs');
2
+ const Ajv = require('ajv');
3
+ const path = require('path');
4
+ const yargs = require('yargs/yargs')
5
+ const { hideBin } = require('yargs/helpers')
6
+ const argv = yargs(hideBin(process.argv))
7
+ .argv;
8
+
9
+ // Load your JSON schema
10
+ const extenalSchema = require('./schema.json');
11
+ const internalSchema = require('./schema-internal.json');
12
+
13
+ // Load your JSON data from the input file
14
+ const inputFilePath = path.join(process.cwd(), "dist/custom-elements.json"); // Update with your file path
15
+ const customManifest = fs.readFileSync(inputFilePath, 'utf8');
16
+ const inputDataInternal = JSON.parse(customManifest);
17
+
18
+ const clearProps = (data) => {
19
+ if (Array.isArray(data)) {
20
+ for (let i = 0; i < data.length; i++) {
21
+ if (typeof data[i] === "object") {
22
+ if (["enum", "interface"].includes(data[i].kind)) {
23
+ data.splice(i, 1);
24
+ i--;
25
+ } else {
26
+ clearProps(data[i]);
27
+ }
28
+ }
29
+ }
30
+ } else if (typeof data === "object") {
31
+ Object.keys(data).forEach(prop => {
32
+ if (prop.startsWith("_ui5")) {
33
+ delete data[prop];
34
+ } else if (typeof data[prop] === "object") {
35
+ clearProps(data[prop]);
36
+ }
37
+ });
38
+ }
39
+
40
+ return data;
41
+ }
42
+
43
+ const ajv = new Ajv({ allowUnionTypes: true, allError: true })
44
+ let validate = ajv.compile(internalSchema)
45
+
46
+ // Validate the JSON data against the schema
47
+ if (argv.dev) {
48
+ if (validate(inputDataInternal)) {
49
+ console.log('Internal custom element manifest is validated successfully');
50
+ } else {
51
+ throw new Error(`Validation of internal custom elements manifest failed: ${validate.errors}`);
52
+ }
53
+ }
54
+
55
+ const inputDataExternal = clearProps(JSON.parse(JSON.stringify(inputDataInternal)));
56
+ validate = ajv.compile(extenalSchema)
57
+
58
+ // Validate the JSON data against the schema
59
+ if (validate(inputDataExternal)) {
60
+ console.log('Custom element manifest is validated successfully');
61
+ fs.writeFileSync(inputFilePath, JSON.stringify(inputDataExternal, null, 2), 'utf8');
62
+ fs.writeFileSync(inputFilePath.replace("custom-elements", "custom-elements-internal"), JSON.stringify(inputDataInternal, null, 2), 'utf8');
63
+ } else if (argv.dev) {
64
+ throw new Error(`Validation of public custom elements manifest failed: ${validate.errors}`);
65
+ }
@@ -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
+ }