@ui5/builder 4.0.4 → 4.0.5

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.
@@ -0,0 +1,489 @@
1
+ /**
2
+ * Node script to parse type strings.
3
+ *
4
+ * (c) Copyright 2009-2024 SAP SE or an SAP affiliate company.
5
+ * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
6
+ */
7
+
8
+ "use strict";
9
+ class ASTBuilder {
10
+ literal(str) {
11
+ return {
12
+ type: "literal",
13
+ value: str
14
+ };
15
+ }
16
+ simpleType(type) {
17
+ return {
18
+ type: "simpleType",
19
+ name: type
20
+ };
21
+ }
22
+ array(componentType) {
23
+ return {
24
+ type: "array",
25
+ component: componentType
26
+ };
27
+ }
28
+ object(keyType, valueType) {
29
+ return {
30
+ type: "object",
31
+ key: keyType,
32
+ value: valueType
33
+ };
34
+ }
35
+ set(elementType) {
36
+ return {
37
+ type: "set",
38
+ element: elementType
39
+ };
40
+ }
41
+ promise(fulfillmentType) {
42
+ return {
43
+ type: "promise",
44
+ fulfill: fulfillmentType
45
+ };
46
+ }
47
+ "function"(paramTypes, returnType, thisType, constructorType) {
48
+ return {
49
+ "type": "function",
50
+ "params": paramTypes,
51
+ "return": returnType,
52
+ "this": thisType,
53
+ "constructor": constructorType
54
+ };
55
+ }
56
+ structure(structure) {
57
+ return {
58
+ type: "structure",
59
+ fields: structure
60
+ };
61
+ }
62
+ union(types) {
63
+ return {
64
+ type: "union",
65
+ types: types
66
+ };
67
+ }
68
+ synthetic(type) {
69
+ type.synthetic = true;
70
+ return type;
71
+ }
72
+ nullable(type) {
73
+ type.nullable = true;
74
+ return type;
75
+ }
76
+ mandatory(type) {
77
+ type.mandatory = true;
78
+ return type;
79
+ }
80
+ optional(type) {
81
+ type.optional = true;
82
+ return type;
83
+ }
84
+ repeatable(type) {
85
+ type.repeatable = true;
86
+ return type;
87
+ }
88
+ typeApplication(type, templateTypes) {
89
+ return {
90
+ type: "typeApplication",
91
+ baseType: type,
92
+ templateTypes: templateTypes
93
+ };
94
+ }
95
+ }
96
+
97
+ function TypeParser(defaultBuilder = new ASTBuilder()) {
98
+ const rLexer = /\s*(Array\.?<|Object\.?<|Set\.?<|Promise\.?<|function\(|\{|:|\(|\||\}|\.?<|>|\)|,|\[\]|\*|\?|!|=|\.\.\.)|\s*(false|true|(?:\+|-)?(?:\d+(?:\.\d+)?|NaN|Infinity)|'[^']*'|"[^"]*"|null|undefined)|\s*((?:module:)?\w+(?:[/.#~][$\w_]+)*)|./g;
99
+
100
+ let input;
101
+ let builder;
102
+ let token;
103
+ let tokenStr;
104
+
105
+ function next(expected) {
106
+ if ( expected !== undefined && token !== expected ) {
107
+ throw new SyntaxError(
108
+ `TypeParser: expected '${expected}', but found '${tokenStr}' ` +
109
+ `(pos: ${rLexer.lastIndex}, input='${input}')`
110
+ );
111
+ }
112
+ const match = rLexer.exec(input);
113
+ if ( match ) {
114
+ tokenStr = match[1] || match[2] || match[3];
115
+ token = match[1] || (match[2] && "literal") || (match[3] && "symbol");
116
+ if ( !token ) {
117
+ throw new SyntaxError(`TypeParser: unexpected '${match[0]}' (pos: ${match.index}, input='${input}')`);
118
+ }
119
+ } else {
120
+ tokenStr = token = null;
121
+ }
122
+ }
123
+
124
+ function parseType() {
125
+ let nullable = false;
126
+ let mandatory = false;
127
+ if ( token === "?" ) {
128
+ next();
129
+ nullable = true;
130
+ } else if ( token === "!" ) {
131
+ next();
132
+ mandatory = true;
133
+ }
134
+
135
+ let type;
136
+
137
+ if ( token === "literal" ) {
138
+ type = builder.literal(tokenStr);
139
+ next();
140
+ } else if ( token === "Array.<" || token === "Array<" ) {
141
+ next();
142
+ const componentType = parseTypes();
143
+ next(">");
144
+ type = builder.array(componentType);
145
+ } else if ( token === "Object.<" || token === "Object<" ) {
146
+ next();
147
+ let keyType;
148
+ let valueType = parseTypes();
149
+ if ( token === "," ) {
150
+ next();
151
+ keyType = valueType;
152
+ valueType = parseTypes();
153
+ } else {
154
+ keyType = builder.synthetic(builder.simpleType("string"));
155
+ }
156
+ next(">");
157
+ type = builder.object(keyType, valueType);
158
+ } else if ( token === "Set.<" || token === "Set<" ) {
159
+ next();
160
+ const elementType = parseTypes();
161
+ next(">");
162
+ type = builder.set(elementType);
163
+ } else if ( token === "Promise.<" || token === "Promise<" ) {
164
+ next();
165
+ const resultType = parseTypes();
166
+ next(">");
167
+ type = builder.promise(resultType);
168
+ } else if ( token === "function(" ) {
169
+ next();
170
+ let thisType;
171
+ let constructorType;
172
+ const paramTypes = [];
173
+ let returnType;
174
+ if ( tokenStr === "this" ) {
175
+ next();
176
+ next(":");
177
+ thisType = parseType();
178
+ if ( token !== ")" ) {
179
+ next(",");
180
+ }
181
+ } else if ( tokenStr === "new" ) {
182
+ next();
183
+ next(":");
184
+ constructorType = parseType();
185
+ if ( token !== ")" ) {
186
+ next(",");
187
+ }
188
+ }
189
+ while ( token !== ")" ) {
190
+ const repeatable = token === "...";
191
+ if ( repeatable ) {
192
+ next();
193
+ }
194
+ let paramType = parseTypes();
195
+ if ( repeatable ) {
196
+ paramType = builder.repeatable(paramType);
197
+ }
198
+ const optional = token === "=";
199
+ if ( optional ) {
200
+ paramType = builder.optional(paramType);
201
+ next();
202
+ }
203
+ paramTypes.push(paramType);
204
+
205
+ // exit if there are no more parameters
206
+ if ( token !== "," ) {
207
+ break;
208
+ }
209
+
210
+ if ( repeatable ) {
211
+ throw new SyntaxError(
212
+ `TypeParser: only the last parameter of a function can be repeatable ` +
213
+ `(pos: ${rLexer.lastIndex}, input='${input}')`
214
+ );
215
+ }
216
+
217
+ // consume the comma
218
+ next();
219
+ }
220
+ next(")");
221
+ if ( token === ":" ) {
222
+ next(":");
223
+ returnType = parseType();
224
+ }
225
+ type = builder.function(paramTypes, returnType, thisType, constructorType);
226
+ } else if ( token === "{" ) {
227
+ const structure = Object.create(null);
228
+ next();
229
+ do {
230
+ const propName = tokenStr;
231
+ if ( !/^\w+$/.test(propName) ) {
232
+ throw new SyntaxError(
233
+ `TypeParser: structure field must have a simple name ` +
234
+ `(pos: ${rLexer.lastIndex}, input='${input}', field:'${propName}')`
235
+ );
236
+ }
237
+ next("symbol");
238
+ let propType;
239
+ const optional = token === "=";
240
+ if ( optional ) {
241
+ next();
242
+ }
243
+ if ( token === ":" ) {
244
+ next();
245
+ propType = parseTypes();
246
+ } else {
247
+ propType = builder.synthetic(builder.simpleType("any"));
248
+ }
249
+ if ( optional ) {
250
+ propType = builder.optional(propType);
251
+ }
252
+ structure[propName] = propType;
253
+ if ( token === "}" ) {
254
+ break;
255
+ }
256
+ next(",");
257
+ } while (token);
258
+ next("}");
259
+ type = builder.structure(structure);
260
+ } else if ( token === "(" ) {
261
+ next();
262
+ type = parseTypes();
263
+ next(")");
264
+ } else if ( token === "*" ) {
265
+ next();
266
+ type = builder.simpleType("*");
267
+ } else {
268
+ type = builder.simpleType(tokenStr);
269
+ next("symbol");
270
+ // check for suffix operators: either 'type application' (generics) or 'array', but not both of them
271
+ if ( token === "<" || token === ".<" ) {
272
+ next();
273
+ const templateTypes = [];
274
+ do {
275
+ const templateType = parseTypes();
276
+ templateTypes.push(templateType);
277
+ if ( token === ">" ) {
278
+ break;
279
+ }
280
+ next(",");
281
+ } while (token);
282
+ next(">");
283
+ type = builder.typeApplication(type, templateTypes);
284
+ } else {
285
+ while ( token === "[]" ) {
286
+ next();
287
+ type = builder.array(type);
288
+ }
289
+ }
290
+ }
291
+ if ( builder.normalizeType ) {
292
+ type = builder.normalizeType(type);
293
+ }
294
+ if ( nullable ) {
295
+ type = builder.nullable(type);
296
+ }
297
+ if ( mandatory ) {
298
+ type = builder.mandatory(type);
299
+ }
300
+ return type;
301
+ }
302
+
303
+ function parseTypes() {
304
+ const types = [];
305
+ do {
306
+ types.push(parseType());
307
+ if ( token !== "|" ) {
308
+ break;
309
+ }
310
+ next();
311
+ } while (token);
312
+ return types.length === 1 ? types[0] : builder.union(types);
313
+ }
314
+
315
+ this.parse = function(typeStr, tempBuilder = defaultBuilder) {
316
+ /*
317
+ try {
318
+ const r = catharsis.parse(typeStr, { jsdoc: true});
319
+ console.log(JSON.stringify(typeStr, null, "\t"), r);
320
+ } catch (err) {
321
+ console.log(typeStr, err);
322
+ }
323
+ */
324
+ builder = tempBuilder;
325
+ input = String(typeStr);
326
+ rLexer.lastIndex = 0;
327
+ next();
328
+ const type = parseTypes();
329
+ next(null);
330
+ return type;
331
+ };
332
+
333
+ /**
334
+ * Parses a string representing a complex type and returns an object with 2 fields:
335
+ * (1) simpleTypes: an array of the identified simple types inside the complex type;
336
+ * (2) template: a string indicating the position of the simple types in the original string.
337
+ *
338
+ * Examples:
339
+ *
340
+ * parseSimpleTypes("sap.ui.core.Control | null") returns
341
+ * {
342
+ * template: "${0} | ${1}",
343
+ * simpleTypes: ["sap.ui.core.Control", "null"]
344
+ * }
345
+ *
346
+ * parseSimpleTypes("Array<string>|Array<number>") returns
347
+ * {
348
+ * template: "Array<${0}>|Array<${1}>"
349
+ * simpleTypes: ["string", "number"],
350
+ * }
351
+ *
352
+ * parseSimpleTypes("Object<string, number>") returns
353
+ * {
354
+ * template: "Object<${0},${1}>"
355
+ * simpleTypes: ["string", "number"],
356
+ * }
357
+ *
358
+ * parseSimpleTypes("function(sap.ui.base.Event, number): boolean") returns
359
+ * {
360
+ * template: "function(${0},${1}): ${2}"
361
+ * simpleTypes: ["sap.ui.base.Event", "number", "boolean"],
362
+ * }
363
+ *
364
+ * parseSimpleTypes("Promise<string>") returns
365
+ * {
366
+ * template: "Promise<${0}>"
367
+ * simpleTypes: ["string"],
368
+ * }
369
+ *
370
+ * @param {string} sComplexType
371
+ * @param {function} [fnFilter] optional filter function to be called for each simple type found. If a type is filtered out, it will not be added to the list of simple types, but will be present in its original form in the template.
372
+ * @returns {{simpleTypes: string[], template: string}} an object with the properties template and simpleTypes
373
+ */
374
+ this.parseSimpleTypes = function(sComplexType, fnFilter) {
375
+ const parsed = this.parse(sComplexType , new ASTBuilder() );
376
+ let iIndexOfNextSimpleType = 0;
377
+
378
+ function processSimpleType(sType) {
379
+ var bSkip = fnFilter && !fnFilter(sType);
380
+ if (bSkip) {
381
+ return {
382
+ template: sType,
383
+ simpleTypes: [] // do not add this type to the list of parsed types
384
+ };
385
+ }
386
+
387
+ return {
388
+ template: "${" + iIndexOfNextSimpleType++ + "}",
389
+ simpleTypes: [sType] // add this type to the list of parsed types
390
+ };
391
+ }
392
+
393
+ function findSimpleTypes(parsed) {
394
+
395
+ /* eslint-disable no-case-declarations */
396
+ switch (parsed.type) {
397
+ case "simpleType":
398
+ return processSimpleType(parsed.name);
399
+ case "literal":
400
+ return processSimpleType(parsed.value);
401
+ case "array":
402
+ const component = findSimpleTypes(parsed.component);
403
+ return {
404
+ template: "Array<" + component.template + ">",
405
+ simpleTypes: component.simpleTypes
406
+ };
407
+ case "object":
408
+ const key = findSimpleTypes(parsed.key);
409
+ const value = findSimpleTypes(parsed.value);
410
+ return {
411
+ template: "Object<" + key.template + "," + value.template + ">",
412
+ simpleTypes: key.simpleTypes.concat(value.simpleTypes)
413
+ };
414
+ case "function":
415
+ const aParamTemplates = [];
416
+ let aParamsimpleTypes = [];
417
+ parsed.params.forEach(function(paramType) {
418
+ const types = findSimpleTypes(paramType);
419
+ aParamTemplates.push(types.template);
420
+ aParamsimpleTypes = aParamsimpleTypes.concat(types.simpleTypes);
421
+ });
422
+ const returnType = parsed.return ? findSimpleTypes(parsed.return) : {simpleTypes: []};
423
+ const returnTemplate = returnType.template ? " : " + returnType.template : "";
424
+ const finalTemplate = "function(" + aParamTemplates.join(",") + ")" + returnTemplate;
425
+ return {
426
+ template: finalTemplate,
427
+ simpleTypes: aParamsimpleTypes.concat(returnType.simpleTypes)
428
+ };
429
+ case "union":
430
+ const unionParts = parsed.types, aPartsTemplates = [];
431
+ let aPartsSimpleTypes = [];
432
+ unionParts.forEach(function (part) {
433
+ const types = findSimpleTypes(part);
434
+ aPartsTemplates.push(types.template);
435
+ aPartsSimpleTypes = aPartsSimpleTypes.concat(types.simpleTypes);
436
+ });
437
+ return {
438
+ template: aPartsTemplates.join(" | "),
439
+ simpleTypes: aPartsSimpleTypes
440
+ };
441
+ case "promise":
442
+ const fulfill = findSimpleTypes(parsed.fulfill);
443
+ return {
444
+ template: "Promise<" + fulfill.template + ">",
445
+ simpleTypes: fulfill.simpleTypes
446
+ };
447
+ case "set":
448
+ const element = findSimpleTypes(parsed.element);
449
+ return {
450
+ template: "Set<" + element.template + ">",
451
+ simpleTypes: element.simpleTypes
452
+ };
453
+ case "typeApplication":
454
+ const baseType = findSimpleTypes(parsed.baseType);
455
+ const templateTypes = parsed.templateTypes.map(findSimpleTypes);
456
+ return {
457
+ template: baseType.template + "<" + templateTypes.map(function (type) {
458
+ return type.template;
459
+ }).join(",") + ">",
460
+ simpleTypes: baseType.simpleTypes.concat(templateTypes.reduce(function (a, b) {
461
+ return a.concat(b.simpleTypes);
462
+ }, []))
463
+ };
464
+ case "structure":
465
+ const aFields = [];
466
+ let aSimpleTypes = [];
467
+ Object.keys(parsed.fields).forEach(function (sKey) {
468
+ const oField = parsed.fields[sKey];
469
+ const types = findSimpleTypes(oField);
470
+ aFields.push(sKey + ":" + types.template);
471
+ aSimpleTypes = aSimpleTypes.concat(types.simpleTypes);
472
+ });
473
+ return {
474
+ template: "{" + aFields.join(",") + "}",
475
+ simpleTypes: aSimpleTypes
476
+ };
477
+ }
478
+ /* eslint-enable no-case-declarations */
479
+ }
480
+
481
+ return findSimpleTypes(parsed);
482
+ };
483
+ }
484
+
485
+
486
+ module.exports = {
487
+ ASTBuilder,
488
+ TypeParser
489
+ };
@@ -1,4 +1,4 @@
1
-
1
+ "use strict";
2
2
 
3
3
  const rSinceVersion = /^([0-9]+(?:\.[0-9]+(?:\.[0-9]+)?)?([-.][0-9A-Z]+)?)(\.$|\.\s+|[,:;]\s*|\s-\s*|\s|$)/i;
4
4
  function _parseVersion(value) {
@@ -11,8 +11,9 @@ function _parseVersion(value) {
11
11
  version: m[1],
12
12
  versionFollowedBySpace: versionFollowedBySpace,
13
13
  nextPosition: m[0].length
14
- }
14
+ };
15
15
  }
16
+ return undefined;
16
17
  }
17
18
 
18
19
  /**
@@ -38,9 +39,10 @@ function extractVersion(value) {
38
39
  if (parseResult && parseResult.versionFollowedBySpace) {
39
40
  return parseResult.version;
40
41
  }
42
+ return undefined;
41
43
  }
42
44
 
43
- const rSinceIndicator = /^(?:as\s+of|since)(?:\s+version)?\s*/i
45
+ const rSinceIndicator = /^(?:as\s+of|since)(?:\s+version)?\s*/i;
44
46
 
45
47
  /**
46
48
  * Extracts since information from given value.
@@ -115,4 +117,4 @@ function extractSince(value) {
115
117
  module.exports = {
116
118
  extractSince,
117
119
  extractVersion
118
- }
120
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ui5/builder",
3
- "version": "4.0.4",
3
+ "version": "4.0.5",
4
4
  "description": "UI5 Tooling - Builder",
5
5
  "author": {
6
6
  "name": "SAP SE",
@@ -133,7 +133,7 @@
133
133
  "less-openui5": "^0.11.6",
134
134
  "pretty-data": "^0.40.0",
135
135
  "semver": "^7.6.3",
136
- "terser": "^5.36.0",
136
+ "terser": "^5.37.0",
137
137
  "workerpool": "^9.2.0",
138
138
  "xml2js": "^0.6.2"
139
139
  },
@@ -141,18 +141,18 @@
141
141
  "@eslint/js": "^9.14.0",
142
142
  "@istanbuljs/esm-loader-hook": "^0.2.0",
143
143
  "@jridgewell/trace-mapping": "^0.3.25",
144
- "@ui5/project": "^4.0.3",
144
+ "@ui5/project": "^4.0.4",
145
145
  "ava": "^6.2.0",
146
146
  "chokidar-cli": "^3.0.0",
147
147
  "cross-env": "^7.0.3",
148
148
  "depcheck": "^1.4.7",
149
149
  "docdash": "^2.0.2",
150
- "eslint": "^9.15.0",
150
+ "eslint": "^9.16.0",
151
151
  "eslint-config-google": "^0.14.0",
152
152
  "eslint-plugin-ava": "^15.0.1",
153
- "eslint-plugin-jsdoc": "^50.5.0",
153
+ "eslint-plugin-jsdoc": "^50.6.0",
154
154
  "esmock": "^2.6.9",
155
- "globals": "^15.12.0",
155
+ "globals": "^15.13.0",
156
156
  "line-column": "^1.0.2",
157
157
  "nyc": "^17.1.0",
158
158
  "open-cli": "^8.0.0",