@playcanvas/attribute-parser 1.6.1 → 1.7.1

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 (78) hide show
  1. package/LICENSE.md +19 -0
  2. package/dist/index.js +445 -0
  3. package/dist/libs.d.ts +50978 -0
  4. package/package.json +50 -10
  5. package/types/index.d.ts +55 -0
  6. package/types/parsers/attribute-parser.d.ts +55 -0
  7. package/types/parsers/parsing-error.d.ts +6 -0
  8. package/types/parsers/script-parser.d.ts +124 -0
  9. package/types/utils/attribute-utils.d.ts +5 -0
  10. package/{src/utils/generic-utils.js → types/utils/generic-utils.d.ts} +1 -10
  11. package/types/utils/tag-utils.d.ts +16 -0
  12. package/types/utils/ts-utils.d.ts +103 -0
  13. package/.github/workflows/ci.yml +0 -49
  14. package/eslint.config.mjs +0 -35
  15. package/renovate.json +0 -25
  16. package/src/index.js +0 -273
  17. package/src/parsers/attribute-parser.js +0 -197
  18. package/src/parsers/parsing-error.js +0 -14
  19. package/src/parsers/script-parser.js +0 -432
  20. package/src/utils/attribute-utils.js +0 -53
  21. package/src/utils/tag-utils.js +0 -73
  22. package/src/utils/ts-utils.js +0 -634
  23. package/test/fixtures/asset.invalid.js +0 -27
  24. package/test/fixtures/asset.invalid.ts +0 -24
  25. package/test/fixtures/asset.valid.js +0 -26
  26. package/test/fixtures/asset.valid.ts +0 -21
  27. package/test/fixtures/checkbox.valid.js +0 -23
  28. package/test/fixtures/color.valid.js +0 -23
  29. package/test/fixtures/conditional.valid.js +0 -22
  30. package/test/fixtures/curve.invalid.js +0 -29
  31. package/test/fixtures/curve.valid.js +0 -49
  32. package/test/fixtures/empty.valid.js +0 -0
  33. package/test/fixtures/entity.valid.js +0 -23
  34. package/test/fixtures/enum.valid.js +0 -66
  35. package/test/fixtures/enum.valid.ts +0 -50
  36. package/test/fixtures/example.dep.js +0 -9
  37. package/test/fixtures/export.import.js +0 -8
  38. package/test/fixtures/export.valid.js +0 -26
  39. package/test/fixtures/inherit.valid.js +0 -45
  40. package/test/fixtures/intellisense.valid.js +0 -40
  41. package/test/fixtures/json.invalid.js +0 -23
  42. package/test/fixtures/json.valid.js +0 -115
  43. package/test/fixtures/json.valid.ts +0 -81
  44. package/test/fixtures/misc.invalid.js +0 -24
  45. package/test/fixtures/misc.valid.js +0 -51
  46. package/test/fixtures/numeric.invalid.js +0 -38
  47. package/test/fixtures/numeric.valid.js +0 -63
  48. package/test/fixtures/playcanvas.d.ts +0 -47963
  49. package/test/fixtures/program.invalid.js +0 -12
  50. package/test/fixtures/program.valid.js +0 -27
  51. package/test/fixtures/text.valid.js +0 -31
  52. package/test/fixtures/vector.invalid.js +0 -14
  53. package/test/fixtures/vector.valid.js +0 -24
  54. package/test/tests/invalid/asset.test.js +0 -47
  55. package/test/tests/invalid/curve.test.js +0 -23
  56. package/test/tests/invalid/json.test.js +0 -27
  57. package/test/tests/invalid/misc.test.js +0 -41
  58. package/test/tests/invalid/numeric.test.js +0 -55
  59. package/test/tests/invalid/program.test.js +0 -17
  60. package/test/tests/invalid/vector.test.js +0 -28
  61. package/test/tests/valid/asset.test.js +0 -59
  62. package/test/tests/valid/checkbox.test.js +0 -57
  63. package/test/tests/valid/color.test.js +0 -49
  64. package/test/tests/valid/conditional.test.js +0 -45
  65. package/test/tests/valid/curve.test.js +0 -76
  66. package/test/tests/valid/empty.test.js +0 -17
  67. package/test/tests/valid/entity.test.js +0 -49
  68. package/test/tests/valid/enum.test.js +0 -79
  69. package/test/tests/valid/export.test.js +0 -67
  70. package/test/tests/valid/inherit.test.js +0 -110
  71. package/test/tests/valid/intellisense.test.js +0 -39
  72. package/test/tests/valid/json.test.js +0 -315
  73. package/test/tests/valid/misc.test.js +0 -54
  74. package/test/tests/valid/numeric.test.js +0 -103
  75. package/test/tests/valid/program.test.js +0 -23
  76. package/test/tests/valid/text.test.js +0 -58
  77. package/test/tests/valid/vector.test.js +0 -53
  78. package/test/utils.js +0 -54
@@ -1,634 +0,0 @@
1
- import { knownLibFilesForCompilerOptions } from '@typescript/vfs';
2
- import * as ts from 'typescript';
3
-
4
- import { ParsingError } from '../parsers/parsing-error.js';
5
-
6
- export function createDefaultMapFromCDN(options, prefix, ts) {
7
- const fsMap = new Map();
8
- const files = knownLibFilesForCompilerOptions(options, ts);
9
-
10
- async function uncached() {
11
- const contentPromises = files.map((lib) => {
12
- return fetch(prefix + lib).then((resp) => {
13
- if (!resp.ok) {
14
- throw new Error(`Failed to fetch ${prefix + lib}: ${resp.statusText}`);
15
- }
16
- return resp.text();
17
- });
18
- });
19
-
20
- const contents = await Promise.all(contentPromises);
21
-
22
- contents.forEach((text, index) => fsMap.set(`/${files[index]}`, text));
23
-
24
- return fsMap;
25
- }
26
-
27
- return uncached();
28
- }
29
-
30
- /**
31
- * Resolves the original symbol in case of alias.
32
- * @param {import('typescript').TypeChecker} typeChecker - The TypeScript type checker
33
- * @param {import('typescript').Symbol} symbol - The TypeScript symbol
34
- * @returns {import('typescript').Symbol} - The resolved symbol
35
- */
36
- function resolveAliasedSymbol(typeChecker, symbol) {
37
- while (symbol.flags & ts.SymbolFlags.Alias) {
38
- symbol = typeChecker.getAliasedSymbol(symbol);
39
- }
40
- return symbol;
41
- }
42
-
43
- /**
44
- * Returns an array of exported nodes from a TypeScript source file.
45
- * @param {import('typescript').Program} program - The TypeScript program
46
- * @param {import('typescript').SourceFile} sourceFile - The TypeScript source file
47
- * @returns {let map: Map<string, Set<import('typescript').Node>>} - A Map of exported nodes
48
- */
49
- export function getExportedNodes(program, sourceFile) {
50
- if (!program || !sourceFile) {
51
- return [];
52
- }
53
-
54
- const typeChecker = program.getTypeChecker();
55
- const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
56
-
57
- if (!moduleSymbol) {
58
- return [];
59
- }
60
-
61
- const exportedSymbols = typeChecker.getExportsOfModule(moduleSymbol);
62
-
63
- // Find the actual declaration nodes for each exported symbol
64
- const exportedNodes = new Map();
65
-
66
- exportedSymbols.forEach((symbol) => {
67
- const resolvedSymbol = resolveAliasedSymbol(typeChecker, symbol);
68
- if (resolvedSymbol.declarations) {
69
- const node = resolvedSymbol.declarations[0];
70
- const name = symbol.name === 'default' ? node.name.getText() : symbol.name;
71
- exportedNodes.set(name, node);
72
- }
73
- });
74
-
75
- return exportedNodes;
76
- }
77
-
78
- /**
79
- * Checks if the node or its aliased symbol is a class declaration.
80
- *
81
- * @param {import('typescript').Node} node - The TypeScript node
82
- * @param {import('typescript').TypeChecker} typeChecker - The TypeScript type checker
83
- * @returns {boolean} - True if the node or its original declaration is a class declaration, false otherwise
84
- */
85
- export function isAliasedClassDeclaration(node, typeChecker) {
86
- if (ts.isClassDeclaration(node)) {
87
- return true;
88
- }
89
- // Try to resolve the original declaration
90
- if (node?.name && ts.isIdentifier(node.name)) {
91
- const symbol = typeChecker.getSymbolAtLocation(node.name);
92
- if (symbol) {
93
- const resolvedSymbol = resolveAliasedSymbol(typeChecker, symbol);
94
- if (resolvedSymbol.declarations) {
95
- return resolvedSymbol.declarations.some(ts.isClassDeclaration);
96
- }
97
- }
98
- }
99
- return false;
100
- }
101
-
102
- /**
103
- * Determines if a TypeScript node inherits from a specific base class.
104
- * @param {ts.ClassDeclaration} node - The TypeScript node to analyze
105
- * @param {ts.TypeChecker} typeChecker - The TypeScript type checker
106
- * @param {ts.Symbol} baseClassSymbol - The base class symbol to check inheritance against
107
- * @returns {boolean} - True if the node inherits from the base class
108
- */
109
- export function inheritsFrom(node, typeChecker, baseClassSymbol) {
110
- if (node.heritageClauses) {
111
- for (const clause of node.heritageClauses) {
112
- for (const type of clause.types) {
113
- // Get the symbol of the expression
114
- const symbol = typeChecker.getTypeAtLocation(type.expression).getSymbol();
115
-
116
- // Check if the symbol is the base class symbol
117
- if (symbol === baseClassSymbol) {
118
- return true;
119
- }
120
-
121
- // Get the declaration of the symbol to check its heritage clauses
122
- if (symbol?.declarations.length > 0) {
123
- const declaration = symbol.declarations[0];
124
- if (inheritsFrom(declaration, typeChecker, baseClassSymbol)) {
125
- return true;
126
- }
127
- }
128
- }
129
- }
130
- }
131
- return false;
132
- }
133
-
134
- /**
135
- * Recursively gathers and flat maps and nodes that meet a specific filter.
136
- * @param {import('typescript').Node} node - The TypeScript node to analyze
137
- * @param {function} filter - A function to filter the nodes
138
- * @returns {import('typescript').Node[]} - An array of exported class declarations
139
- */
140
- export function flatMapAnyNodes(node, filter = () => true) {
141
- const results = [];
142
-
143
- function visit(node) {
144
- // Check if this node is an exported class declaration
145
- if (filter(node)) {
146
- results.push(node);
147
- }
148
-
149
- // Visit each child node
150
- ts.forEachChild(node, visit);
151
- }
152
-
153
- // Start the search with the root node
154
- visit(node);
155
-
156
- return results;
157
- }
158
-
159
- /**
160
- * Takes a AST Node, and if it's a class declaration, it will return it's super classes
161
- *
162
- * @param {import('typescript').Node} node - The node to check
163
- * @param {import('typescript').TypeChecker} typeChecker - The programs typechecker
164
- * @returns {import('typescript').Node[]} - The analyzed node and any super classes in the inheritance chain
165
- */
166
- function getSuperClasses(node, typeChecker) {
167
- const superClasses = [node];
168
-
169
- let currentClass = node;
170
-
171
- while (currentClass) {
172
- const heritageClauses = currentClass.heritageClauses;
173
- if (!heritageClauses) {
174
- break;
175
- }
176
-
177
- const extendsClause = heritageClauses.find(clause => clause.token === ts.SyntaxKind.ExtendsKeyword);
178
- if (!extendsClause || extendsClause.types.length === 0) {
179
- break;
180
- }
181
-
182
- const superClassType = typeChecker.getTypeAtLocation(extendsClause.types[0]);
183
- const superClassSymbol = superClassType.getSymbol();
184
-
185
- if (!superClassSymbol) {
186
- break;
187
- }
188
-
189
- const superClassDeclaration = superClassSymbol.declarations.find(ts.isClassDeclaration);
190
- if (!superClassDeclaration) {
191
- break;
192
- }
193
-
194
- superClasses.push(superClassDeclaration);
195
- currentClass = superClassDeclaration;
196
- }
197
-
198
- return superClasses; // .reverse(); // To return the array in order from the base class to the top-level class
199
- }
200
-
201
- /**
202
- * Retrieves the JSDoc-style comments associated with a specific AST node.
203
- *
204
- * @param {import('typescript').Node} node - The TypeScript node to analyze
205
- * @param {string} text - The full text content of the source file
206
- * @param {import('typescript').TypeChecker} typeChecker - The TypeScript type checker
207
- * @returns {{ memberName: string, member: Node, range: import('typescript').CommentRange}[]} - An array of comment ranges
208
- */
209
- export function getJSDocTags(node, typeChecker) {
210
- const tags = [];
211
-
212
- // check if class interface of initialized object
213
- if (ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node)) {
214
- // get an array of the class an all parent classed
215
- const heritageChain = getSuperClasses(node, typeChecker)
216
- .filter(classNode => !classNode.getSourceFile().isDeclarationFile);
217
-
218
- // iterate over the heritance chain
219
- heritageChain.forEach((classNode) => {
220
- // for each class iterate over it's class members
221
- classNode.members.forEach((member) => {
222
- const isSetter = ts.isSetAccessor(member);
223
- if (ts.isPropertyDeclaration(member) || isSetter || ts.isPropertySignature(member)) {
224
- const memberName = member.name && ts.isIdentifier(member.name) ? member.name.text : 'unnamed';
225
-
226
- let hasJsDoc = member.jsDoc?.length > 0;
227
-
228
- // If we are a setter with no jsdoc block, check any associated getter
229
- if (isSetter && !hasJsDoc) {
230
- const symbol = typeChecker.getSymbolAtLocation(member.name);
231
- member = symbol.declarations.find(accessor => accessor.jsDoc?.length > 0);
232
- hasJsDoc = !!member;
233
- }
234
-
235
- if (hasJsDoc) {
236
- tags.push({
237
- memberName,
238
- member
239
- });
240
- }
241
- }
242
- });
243
- });
244
- } else if (ts.isObjectLiteralExpression(node)) {
245
- // Handle object literals
246
- node.properties.forEach((property) => {
247
- if (ts.isPropertyAssignment(property)) {
248
- const memberName = property.name &&
249
- (ts.isIdentifier(property.name) || ts.isStringLiteral(property.name)) ?
250
- property.name.text :
251
- 'unnamed';
252
-
253
- if (property.jsDoc?.length > 0) {
254
- tags.push({
255
- memberName,
256
- member: property
257
- });
258
- }
259
- }
260
- });
261
- }
262
-
263
- return tags;
264
- }
265
-
266
- /**
267
- * Determines if a TypeScript node is an enum.
268
- * @param {import('typescript').Node} node - The TypeScript node to analyze
269
- * @returns {boolean} - True if the node is an enum
270
- */
271
- export function isEnum(node) {
272
- // Check for TypeScript native enum
273
- if (ts.isEnumDeclaration(node)) {
274
- return true; // The node is a TypeScript enum
275
- }
276
-
277
- // Check for JSDoc @enum tag in a variable declaration
278
- if (ts.isVariableDeclaration(node)) {
279
- const jsDocs = ts.getJSDocTags(node);
280
- const hasEnumTag = jsDocs.some(doc => doc.tagName.text === 'enum');
281
- return hasEnumTag;
282
- }
283
-
284
- return false;
285
- }
286
-
287
- /**
288
- * Determines the primitive type for enums, or falls back to the actual type name.
289
- *
290
- * @param {ts.Type} type - The type to inspect.
291
- * @param {ts.TypeChecker} typeChecker - The TypeScript type checker.
292
- * @returns {'string' | 'boolean' | 'number' | null} - The primitive type of the enum or the type's name.
293
- */
294
- export function getPrimitiveEnumType(type, typeChecker) {
295
- // Check if the type is an enum type
296
- if (!type.symbol?.declarations?.some(decl => ts.isEnumDeclaration(decl))) return null;
297
-
298
- // Get the type of enum members
299
- const enumMembers = type.symbol.declarations[0].members;
300
- const firstMemberValue = typeChecker.getConstantValue(enumMembers[0]);
301
-
302
- const validEnumType = [
303
- 'number',
304
- 'string',
305
- 'boolean'
306
- ];
307
-
308
- const typeOf = typeof firstMemberValue;
309
- return validEnumType.includes(typeOf) ? typeOf : null;
310
- }
311
-
312
- /**
313
- * Gets the inferred type of a TypeScript node.
314
- *
315
- * @param {ts.Node} node - The TypeScript node to analyze
316
- * @param {ts.TypeChecker} typeChecker - The TypeScript type checker
317
- * @returns {{ array: boolean, name: string | undefined, type: Type | null }} - The inferred type of the node
318
- */
319
- export function getType(node, typeChecker) {
320
- if (node?.name?.kind === ts.SyntaxKind.Identifier) {
321
- const type = typeChecker.getTypeAtLocation(node);
322
- const array = typeChecker.isArrayType(type);
323
- const actualType = array ? typeChecker.getElementTypeOfArrayType(type) : type;
324
- const name = getPrimitiveEnumType(actualType, typeChecker) ?? typeChecker.typeToString(actualType);
325
-
326
- return { type: actualType, name, array };
327
- }
328
-
329
- return null;
330
- }
331
-
332
- /**
333
- * Parses a numerical string into a number. Handles hexadecimal, binary,
334
- * octal, exponential notation and underscore notation
335
- *
336
- * @param {string} input - The string to parse
337
- * @returns {number} The parsed number, or NaN if the input is not a number
338
- */
339
- export function parseNumber(input) {
340
- // Remove underscores from the string to handle underscore notation
341
- let cleanedInput = input.replace(/_/g, '').toLowerCase();
342
-
343
- // Identify and isolate unary operators
344
- let unaryOperator = null;
345
- if (cleanedInput.startsWith('+') || cleanedInput.startsWith('-') || cleanedInput.startsWith('~')) {
346
- unaryOperator = cleanedInput[0];
347
- cleanedInput = cleanedInput.slice(1).trim();
348
- }
349
-
350
- // Check for different bases and handle appropriately
351
- let result;
352
- if (cleanedInput === 'NaN' || cleanedInput === '') {
353
- result = NaN;
354
- } else if (cleanedInput.startsWith('0b')) {
355
- result = parseInt(cleanedInput.slice(2), 2);
356
- } else if (cleanedInput.startsWith('0o')) {
357
- result = parseInt(cleanedInput.slice(2), 8);
358
- } else if (cleanedInput.startsWith('0x')) {
359
- result = parseInt(cleanedInput.slice(2), 16);
360
- } else if (cleanedInput.includes('e')) {
361
- result = parseFloat(cleanedInput); // Exponential notation
362
- } else if (!isNaN(Number(cleanedInput))) {
363
- result = Number(cleanedInput); // Decimal, including floating-point
364
- } else {
365
- result = NaN;
366
- }
367
-
368
- // Apply unary operator if present
369
- if (unaryOperator === '+') {
370
- result = +result; // Positive sign can be ignored, but explicitly using for clarity
371
- } else if (unaryOperator === '-') {
372
- result = -result;
373
- } else if (unaryOperator === '~') {
374
- result = ~result; // Bitwise NOT
375
- }
376
-
377
- return result;
378
- }
379
-
380
- /**
381
- * Parses a string representation of a numerical array into an array of numbers.
382
- *
383
- * @param {string} input - The string to parse
384
- * @returns {number[]} - The parsed array of numbers
385
- * @throws {Error} - If the input contains invalid characters or is not a valid array
386
- */
387
- export function parseStringToNumericalArray(input) {
388
- // Remove unnecessary whitespace
389
- const sanitizedInput = input.replace(/\s+/g, '');
390
-
391
- // Check if the input still contains valid array format
392
- if (!sanitizedInput.startsWith('[') || !sanitizedInput.endsWith(']')) {
393
- throw new Error('Invalid input string');
394
- }
395
-
396
- // Remove the brackets and split the string into an array
397
- const arrayString = sanitizedInput.slice(1, -1);
398
- const elements = arrayString.split(',');
399
-
400
- // Parse each element using the parseNumber function
401
- const parsedArray = elements.map((element) => {
402
- return parseNumber(element.trim());
403
- });
404
-
405
- // Validate if the result is an array and contains only valid numbers
406
- if (parsedArray.some(isNaN)) {
407
- throw new Error('Parsed result contains invalid numbers');
408
- }
409
-
410
- return parsedArray;
411
- }
412
-
413
- /**
414
- * Checks if the given node is a numerical literal or a unary expression.
415
- * @param {import('typescript').Node} node - The node to check
416
- * @returns {boolean} - True if the node is a numeric literal
417
- */
418
- export const isNumericLiteral = (node) => {
419
- // Is the node a numeric literal '10'
420
- const isNumericLiteral = ts.isNumericLiteral(node);
421
-
422
- // Or is it a +/- unary expression '-10' or '+10'
423
- const isUnaryExpression =
424
- ts.isUnaryExpression(node) && //
425
- (node.operator === ts.SyntaxKind.MinusToken || node.operator === ts.SyntaxKind.PlusToken) &&
426
- node.operand.kind === ts.SyntaxKind.NumericLiteral;
427
-
428
- return isNumericLiteral || isUnaryExpression;
429
- };
430
-
431
- /**
432
- * If the given node is a numeric literal, returns the parsed number.
433
- * @param {import('typescript').Node} node - The node to check
434
- * @param {boolean} [isArgument] - True if the node is an argument in a parameter list
435
- * @returns {number} - The parsed number
436
- * @throws {ParsingError} - If the node is not a numeric literal
437
- */
438
- export const parseFloatNode = (node, isArgument = false) => {
439
- if (!isNumericLiteral(node)) {
440
- if (ts.isPropertyAssignment(node.parent) || ts.isPropertyDeclaration(node.parent) || isArgument) {
441
- throw new ParsingError(node, `"${node.parent.getText()}" must be defined with a numeric literal.`);
442
- }
443
- return 0;
444
- }
445
- return parseNumber(node.getText());
446
- };
447
-
448
- /**
449
- * If the given node is a boolean literal, returns the parsed boolean.
450
- * @param {import('typescript').Node} node - The node to check
451
- * @returns {boolean} - The parsed boolean
452
- */
453
- export const parseBooleanNode = (node) => {
454
- if (node.kind !== ts.SyntaxKind.TrueKeyword && node.kind !== ts.SyntaxKind.FalseKeyword) {
455
- if (ts.isPropertyAssignment(node.parent) || ts.isPropertyDeclaration(node.parent)) {
456
- throw new ParsingError(node, `"${node.parent.getText()}" must be defined with a boolean literal.`);
457
- }
458
- return false;
459
- }
460
- return node.kind === ts.SyntaxKind.TrueKeyword;
461
- };
462
-
463
- function resolveIdentifier(node, typeChecker) {
464
- const symbol = typeChecker.getSymbolAtLocation(node);
465
- if (symbol && symbol.declarations) {
466
- for (const declaration of symbol.declarations) {
467
- if (ts.isVariableDeclaration(declaration) && declaration.initializer) {
468
- return getLiteralValue(declaration.initializer, typeChecker);
469
- }
470
- // Handle other kinds of declarations if needed
471
- }
472
- }
473
- return undefined;
474
- }
475
-
476
- /**
477
- * Resolve the value of a property access expression. Limited to simple cases like
478
- * object literals and variable declarations.
479
- *
480
- * @param {import('typescript').Node} node - The property access expression node
481
- * @param {import('typescript')} typeChecker - The TypeScript type checker
482
- * @returns {any} - The resolved value of the property access
483
- */
484
- const resolvePropertyAccess = (node, typeChecker) => {
485
- const symbol = typeChecker.getSymbolAtLocation(node);
486
- if (symbol && symbol.declarations) {
487
- for (const declaration of symbol.declarations) {
488
- if (ts.isPropertyAssignment(declaration) && declaration.initializer) {
489
- return getLiteralValue(declaration.initializer, typeChecker);
490
- }
491
-
492
- if (ts.isVariableDeclaration(declaration) && declaration.initializer) {
493
- return getLiteralValue(declaration.initializer, typeChecker);
494
- }
495
-
496
- if (ts.isEnumMember(declaration)) {
497
- return declaration.initializer ? getLiteralValue(declaration.initializer, typeChecker) : declaration.name.getText();
498
- }
499
-
500
- }
501
- }
502
-
503
- // If symbol not found directly, attempt to resolve the object first
504
- const objValue = getLiteralValue(node.expression, typeChecker);
505
- if (objValue && typeof objValue === 'object') {
506
- const propName = node.name.text;
507
- return objValue[propName];
508
- }
509
-
510
- return undefined;
511
- };
512
-
513
- /**
514
- * Evaluates unary prefixes like +, -, !, ~, and returns the result.
515
- * @param {import('typescript').Node} node - The AST node to evaluate
516
- * @param {import('typescript').TypeChecker} typeChecker - The TypeScript type checker
517
- * @returns {number | boolean | undefined} - The result of the evaluation
518
- */
519
- const evaluatePrefixUnaryExpression = (node, typeChecker) => {
520
- const operandValue = getLiteralValue(node.operand, typeChecker);
521
- if (operandValue !== undefined) {
522
- switch (node.operator) {
523
- case ts.SyntaxKind.PlusToken:
524
- return +operandValue;
525
- case ts.SyntaxKind.MinusToken:
526
- return -operandValue;
527
- case ts.SyntaxKind.ExclamationToken:
528
- return !operandValue;
529
- case ts.SyntaxKind.TildeToken:
530
- return ~operandValue;
531
- }
532
- }
533
- return undefined;
534
- };
535
-
536
- function handleObjectLiteral(node, typeChecker) {
537
- const obj = {};
538
- node.properties.forEach((prop) => {
539
- if (ts.isPropertyAssignment(prop)) {
540
- const key = prop.name.getText();
541
- const value = getLiteralValue(prop.initializer, typeChecker);
542
- obj[key] = value;
543
- } else if (ts.isShorthandPropertyAssignment(prop)) {
544
- const key = prop.name.getText();
545
- const value = resolveIdentifier(prop.name, typeChecker);
546
- obj[key] = value;
547
- }
548
- });
549
- return obj;
550
- }
551
-
552
- /**
553
- * Attempts to extract a literal value from a TypeScript node. This function
554
- * supports various types of literals and expressions, including object literals,
555
- * array literals, identifiers, and unary expressions.
556
- *
557
- * @param {import('typescript').Node} node - The AST node to evaluate
558
- * @param {import('typescript').TypeChecker} typeChecker - The TypeScript type checker
559
- * @returns {any} - The extracted literal value
560
- */
561
- export function getLiteralValue(node, typeChecker) {
562
- if (!node) return undefined;
563
-
564
- if (ts.isLiteralExpression(node) || ts.isBooleanLiteral(node)) {
565
- if (ts.isStringLiteral(node)) {
566
- return node.text;
567
- }
568
- if (ts.isNumericLiteral(node)) {
569
- return Number(node.text);
570
- }
571
- if (node.kind === ts.SyntaxKind.TrueKeyword) {
572
- return true;
573
- }
574
- if (node.kind === ts.SyntaxKind.FalseKeyword) {
575
- return false;
576
- }
577
- }
578
-
579
- switch (node.kind) {
580
- case ts.SyntaxKind.NullKeyword:
581
- return null;
582
- case ts.SyntaxKind.ArrayLiteralExpression:
583
- return (node).elements.map(element => getLiteralValue(element, typeChecker));
584
- case ts.SyntaxKind.ObjectLiteralExpression:
585
- return handleObjectLiteral(node, typeChecker);
586
- case ts.SyntaxKind.Identifier:
587
- return resolveIdentifier(node, typeChecker);
588
- case ts.SyntaxKind.PropertyAccessExpression:
589
- return resolvePropertyAccess(node, typeChecker);
590
- case ts.SyntaxKind.ParenthesizedExpression:
591
- return getLiteralValue((node).expression, typeChecker);
592
- case ts.SyntaxKind.PrefixUnaryExpression:
593
- return evaluatePrefixUnaryExpression(node, typeChecker);
594
- default:
595
- return undefined;
596
- }
597
- }
598
-
599
- /**
600
- * If the given node is a string literal, returns the parsed string.
601
- * @param {import('typescript').Node} node - The node to check
602
- * @returns {string} - The parsed string
603
- */
604
- export const parseStringNode = (node) => {
605
- if (node.kind !== ts.SyntaxKind.StringLiteral) {
606
- if (ts.isPropertyAssignment(node.parent) || ts.isPropertyDeclaration(node.parent)) {
607
- throw new ParsingError(node, `"${node.parent.getText()}" must be defined with a string literal.`);
608
- }
609
- return '';
610
- }
611
- return node.getText().slice(1, -1);
612
- };
613
-
614
- export const parseArrayLiteralNode = (node, isArgument = false) => {
615
- if (node.kind !== ts.SyntaxKind.ArrayLiteralExpression) {
616
- if (ts.isPropertyAssignment(node.parent) || ts.isPropertyDeclaration(node.parent) || isArgument) {
617
- throw new ParsingError(node, `"${node.parent.getText()}" must be defined with an array literal.`);
618
- }
619
- return [];
620
- }
621
- return JSON.parse(node.getText());
622
- };
623
-
624
- /**
625
- * Parses the first argument as an array literal.
626
- * @param {ts.Node[]} args - The arguments to parse
627
- * @returns {number[]} - The parsed array
628
- */
629
- export const parseArrayLiteral = (args) => {
630
- if (args.length > 0) {
631
- return parseArrayLiteralNode(args[0], true);
632
- }
633
- return [];
634
- };
@@ -1,27 +0,0 @@
1
- // eslint-disable-next-line
2
- import { Script, Asset } from 'playcanvas';
3
-
4
- class Example extends Script {
5
- /**
6
- * @attribute
7
- * @type {Asset}
8
- * @resource nothing
9
- */
10
- a;
11
-
12
- /**
13
- * @attribute
14
- * @type {Asset}
15
- * @resource 1
16
- */
17
- b;
18
-
19
- /**
20
- * @attribute
21
- * @type {Asset}
22
- * @resource
23
- */
24
- c;
25
- }
26
-
27
- export { Example };
@@ -1,24 +0,0 @@
1
- // eslint-disable-next-line
2
- import { Script, Asset } from 'playcanvas';
3
-
4
- class Example extends Script {
5
- /**
6
- * @attribute
7
- * @resource nothing
8
- */
9
- a: Asset;
10
-
11
- /**
12
- * @attribute
13
- * @resource 1
14
- */
15
- b : Asset;
16
-
17
- /**
18
- * @attribute
19
- * @resource
20
- */
21
- c : Asset;
22
- }
23
-
24
- export { Example };