Skip to content

Commit 08c4f06

Browse files
authored
Add support for external references (#61)
* feat: enhance enum handling and add playcanvas dependency - Updated the attribute parser to correctly handle TypeScript enums, including imported constants. - Enhanced the getLiteralValue function to prioritize type checking for imported constants. - Added support for enums in the test fixtures, validating the integration with playcanvas. - Introduced playcanvas as a dependency in package.json and package-lock.json. This update improves the parsing of enums and ensures compatibility with the latest playcanvas features. * refactor: update enum handling and improve type resolution - Replaced the fallback in `resolveIdentifier` to return `undefined` instead of a literal value. - Refactored enum definitions in test fixtures to utilize new tone mapping constants from playcanvas. - Updated tests to validate the new enum structure and ensure correct default values for tone mapping attributes. This change enhances the clarity and functionality of enum handling in the codebase. * feat: add Playcanvas types loading and remove fixture file - Introduced a new function `getPlaycanvasTypes` to load Playcanvas type definitions directly from `node_modules`. - Updated `parseAttributes` and `getAttributes` functions to utilize the loaded Playcanvas types instead of relying on a local fixture file. - Removed the `playcanvas.d.ts` fixture file as it is no longer needed. This change streamlines type handling and ensures that the latest Playcanvas definitions are used in the project.
1 parent 9985c7e commit 08c4f06

File tree

9 files changed

+637
-47989
lines changed

9 files changed

+637
-47989
lines changed

package-lock.json

Lines changed: 515 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,9 @@
4242
"chai": "5.2.1",
4343
"globals": "16.3.0",
4444
"mocha": "11.7.1",
45-
"rollup": "4.46.2",
46-
"publint": "0.3.12"
45+
"playcanvas": "^2.12.3",
46+
"publint": "0.3.12",
47+
"rollup": "4.46.2"
4748
},
4849
"dependencies": {
4950
"@playcanvas/eslint-config": "^2.0.0",

src/parsers/attribute-parser.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,14 @@ export class AttributeParser {
213213

214214
// Check if the declaration is a TypeScript enum
215215
if (ts.isEnumDeclaration(declaration)) {
216-
members = declaration.members.map(member => ({ [member.name.text]: member.initializer.text }));
216+
members = declaration.members.map((member) => {
217+
const name = member.name.text;
218+
let value;
219+
if (member.initializer) {
220+
value = getLiteralValue(member.initializer, this.typeChecker);
221+
}
222+
return { [name]: value };
223+
});
217224
}
218225

219226
// Additionally check for JSDoc enum tag

src/utils/ts-utils.js

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ function getSuperClasses(node, typeChecker) {
195195
currentClass = superClassDeclaration;
196196
}
197197

198-
return superClasses; // .reverse(); // To return the array in order from the base class to the top-level class
198+
return superClasses;
199199
}
200200

201201
/**
@@ -293,20 +293,38 @@ export function isEnum(node) {
293293
*/
294294
export function getPrimitiveEnumType(type, typeChecker) {
295295
// Check if the type is an enum type
296-
if (!type.symbol?.declarations?.some(decl => ts.isEnumDeclaration(decl))) return null;
296+
const isEnumType = type.symbol?.declarations?.some(decl => ts.isEnumDeclaration(decl));
297297

298-
// Get the type of enum members
299-
const enumMembers = type.symbol.declarations[0].members;
300-
const firstMemberValue = typeChecker.getConstantValue(enumMembers[0]);
298+
// If not directly an enum, check if it's an enum member (which means it's part of an enum)
299+
let isEnumMember = false;
300+
if (!isEnumType) {
301+
isEnumMember = type.symbol?.declarations?.some(decl => ts.isEnumMember(decl));
302+
if (!isEnumMember) return null;
303+
}
304+
305+
// Get the enum members
306+
let enumMembers;
307+
if (isEnumType) {
308+
enumMembers = type.symbol.declarations[0].members;
309+
} else if (isEnumMember) {
310+
const enumMember = type.symbol.declarations[0];
311+
const parentEnum = enumMember.parent;
312+
if (ts.isEnumDeclaration(parentEnum)) {
313+
enumMembers = parentEnum.members;
314+
} else {
315+
return null;
316+
}
317+
}
301318

302-
const validEnumType = [
303-
'number',
304-
'string',
305-
'boolean'
306-
];
319+
// Get the value of the first enum member using our centralized logic
320+
const firstMember = enumMembers[0];
321+
const firstMemberValue = firstMember.initializer ?
322+
getLiteralValue(firstMember.initializer, typeChecker) :
323+
getLiteralValue(firstMember, typeChecker);
307324

325+
const validEnumTypes = ['number', 'string', 'boolean'];
308326
const typeOf = typeof firstMemberValue;
309-
return validEnumType.includes(typeOf) ? typeOf : null;
327+
return validEnumTypes.includes(typeOf) ? typeOf : null;
310328
}
311329

312330
/**
@@ -484,6 +502,8 @@ function resolveIdentifier(node, typeChecker) {
484502
// Handle other kinds of declarations if needed
485503
}
486504
}
505+
506+
// Fallback to getLiteralValue which now handles typeChecker approach
487507
return undefined;
488508
}
489509

@@ -514,6 +534,12 @@ const resolvePropertyAccess = (node, typeChecker) => {
514534
}
515535
}
516536

537+
// Try getLiteralValue first (which now handles typeChecker approach)
538+
const result = getLiteralValue(node, typeChecker);
539+
if (result !== undefined) {
540+
return result;
541+
}
542+
517543
// If symbol not found directly, attempt to resolve the object first
518544
const objValue = getLiteralValue(node.expression, typeChecker);
519545
if (objValue && typeof objValue === 'object') {
@@ -575,6 +601,14 @@ function handleObjectLiteral(node, typeChecker) {
575601
export function getLiteralValue(node, typeChecker) {
576602
if (!node) return undefined;
577603

604+
// Try typeChecker approach first for imported constants and other complex cases
605+
if (typeChecker) {
606+
const type = typeChecker.getTypeAtLocation(node);
607+
if (type && type.isLiteral()) {
608+
return type.value;
609+
}
610+
}
611+
578612
if (ts.isLiteralExpression(node) || ts.isBooleanLiteral(node)) {
579613
if (ts.isStringLiteral(node)) {
580614
return node.text;

test/fixtures/enum.valid.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Script } from 'playcanvas';
1+
import { Script, TONEMAP_ACES, TONEMAP_ACES2, TONEMAP_FILMIC, TONEMAP_HEJL, TONEMAP_LINEAR, TONEMAP_NEUTRAL } from 'playcanvas';
22

33
/**
44
* @enum {number}
@@ -9,6 +9,18 @@ const NumberEnum = {
99
C: 23
1010
};
1111

12+
/**
13+
* @enum {number}
14+
*/
15+
const ToneMapping = {
16+
LINEAR: TONEMAP_LINEAR,
17+
FILMIC: TONEMAP_FILMIC,
18+
HEJL: TONEMAP_HEJL,
19+
ACES: TONEMAP_ACES,
20+
ACES2: TONEMAP_ACES2,
21+
NEUTRAL: TONEMAP_NEUTRAL
22+
};
23+
1224
/**
1325
* @enum {string}
1426
*/
@@ -63,6 +75,12 @@ class Example extends Script {
6375
* @type {NumberNumberEnum}
6476
*/
6577
i = 2;
78+
79+
/**
80+
* @attribute
81+
* @type {ToneMapping}
82+
*/
83+
j = ToneMapping.LINEAR;
6684
}
6785

6886
export { Example };

test/fixtures/enum.valid.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Script, Vec3 } from 'playcanvas';
1+
import { Script, Vec3, BODYGROUP_DEFAULT, TONEMAP_LINEAR, TONEMAP_NEUTRAL, TONEMAP_ACES2, TONEMAP_ACES, TONEMAP_HEJL, TONEMAP_FILMIC } from 'playcanvas';
22

33
enum NumberEnum {
44
A = 13,
@@ -19,6 +19,15 @@ enum NumberNumberEnum {
1919
C = NumberEnum.C
2020
};
2121

22+
enum ToneMapping {
23+
LINEAR = TONEMAP_LINEAR,
24+
FILMIC = TONEMAP_FILMIC,
25+
HEJL = TONEMAP_HEJL,
26+
ACES = TONEMAP_ACES,
27+
ACES2 = TONEMAP_ACES2,
28+
NEUTRAL = TONEMAP_NEUTRAL
29+
};
30+
2231
class Example extends Script {
2332
static scriptName = 'example';
2433

@@ -47,6 +56,11 @@ class Example extends Script {
4756
* @attribute
4857
*/
4958
i : NumberNumberEnum = 2;
59+
60+
/**
61+
* @attribute
62+
*/
63+
j : ToneMapping = ToneMapping.LINEAR;
5064
}
5165

5266
export { Example };

0 commit comments

Comments
 (0)