Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
515 changes: 515 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@
"chai": "5.2.1",
"globals": "16.3.0",
"mocha": "11.7.1",
"rollup": "4.46.2",
"publint": "0.3.12"
"playcanvas": "^2.12.3",
"publint": "0.3.12",
"rollup": "4.46.2"
},
"dependencies": {
"@playcanvas/eslint-config": "^2.0.0",
Expand Down
9 changes: 8 additions & 1 deletion src/parsers/attribute-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,14 @@ export class AttributeParser {

// Check if the declaration is a TypeScript enum
if (ts.isEnumDeclaration(declaration)) {
members = declaration.members.map(member => ({ [member.name.text]: member.initializer.text }));
members = declaration.members.map((member) => {
const name = member.name.text;
let value;
if (member.initializer) {
value = getLiteralValue(member.initializer, this.typeChecker);
}
return { [name]: value };
});
}

// Additionally check for JSDoc enum tag
Expand Down
56 changes: 45 additions & 11 deletions src/utils/ts-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ function getSuperClasses(node, typeChecker) {
currentClass = superClassDeclaration;
}

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

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

// Get the type of enum members
const enumMembers = type.symbol.declarations[0].members;
const firstMemberValue = typeChecker.getConstantValue(enumMembers[0]);
// If not directly an enum, check if it's an enum member (which means it's part of an enum)
let isEnumMember = false;
if (!isEnumType) {
isEnumMember = type.symbol?.declarations?.some(decl => ts.isEnumMember(decl));
if (!isEnumMember) return null;
}

// Get the enum members
let enumMembers;
if (isEnumType) {
enumMembers = type.symbol.declarations[0].members;
} else if (isEnumMember) {
const enumMember = type.symbol.declarations[0];
const parentEnum = enumMember.parent;
if (ts.isEnumDeclaration(parentEnum)) {
enumMembers = parentEnum.members;
} else {
return null;
}
}

const validEnumType = [
'number',
'string',
'boolean'
];
// Get the value of the first enum member using our centralized logic
const firstMember = enumMembers[0];
const firstMemberValue = firstMember.initializer ?
getLiteralValue(firstMember.initializer, typeChecker) :
getLiteralValue(firstMember, typeChecker);

const validEnumTypes = ['number', 'string', 'boolean'];
const typeOf = typeof firstMemberValue;
return validEnumType.includes(typeOf) ? typeOf : null;
return validEnumTypes.includes(typeOf) ? typeOf : null;
}

/**
Expand Down Expand Up @@ -484,6 +502,8 @@ function resolveIdentifier(node, typeChecker) {
// Handle other kinds of declarations if needed
}
}

// Fallback to getLiteralValue which now handles typeChecker approach
return undefined;
}

Expand Down Expand Up @@ -514,6 +534,12 @@ const resolvePropertyAccess = (node, typeChecker) => {
}
}

// Try getLiteralValue first (which now handles typeChecker approach)
const result = getLiteralValue(node, typeChecker);
if (result !== undefined) {
return result;
}

// If symbol not found directly, attempt to resolve the object first
const objValue = getLiteralValue(node.expression, typeChecker);
if (objValue && typeof objValue === 'object') {
Expand Down Expand Up @@ -575,6 +601,14 @@ function handleObjectLiteral(node, typeChecker) {
export function getLiteralValue(node, typeChecker) {
if (!node) return undefined;

// Try typeChecker approach first for imported constants and other complex cases
if (typeChecker) {
const type = typeChecker.getTypeAtLocation(node);
if (type && type.isLiteral()) {
return type.value;
}
}

if (ts.isLiteralExpression(node) || ts.isBooleanLiteral(node)) {
if (ts.isStringLiteral(node)) {
return node.text;
Expand Down
20 changes: 19 additions & 1 deletion test/fixtures/enum.valid.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Script } from 'playcanvas';
import { Script, TONEMAP_ACES, TONEMAP_ACES2, TONEMAP_FILMIC, TONEMAP_HEJL, TONEMAP_LINEAR, TONEMAP_NEUTRAL } from 'playcanvas';

/**
* @enum {number}
Expand All @@ -9,6 +9,18 @@ const NumberEnum = {
C: 23
};

/**
* @enum {number}
*/
const ToneMapping = {
LINEAR: TONEMAP_LINEAR,
FILMIC: TONEMAP_FILMIC,
HEJL: TONEMAP_HEJL,
ACES: TONEMAP_ACES,
ACES2: TONEMAP_ACES2,
NEUTRAL: TONEMAP_NEUTRAL
};

/**
* @enum {string}
*/
Expand Down Expand Up @@ -63,6 +75,12 @@ class Example extends Script {
* @type {NumberNumberEnum}
*/
i = 2;

/**
* @attribute
* @type {ToneMapping}
*/
j = ToneMapping.LINEAR;
}

export { Example };
16 changes: 15 additions & 1 deletion test/fixtures/enum.valid.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Script, Vec3 } from 'playcanvas';
import { Script, Vec3, BODYGROUP_DEFAULT, TONEMAP_LINEAR, TONEMAP_NEUTRAL, TONEMAP_ACES2, TONEMAP_ACES, TONEMAP_HEJL, TONEMAP_FILMIC } from 'playcanvas';

enum NumberEnum {
A = 13,
Expand All @@ -19,6 +19,15 @@ enum NumberNumberEnum {
C = NumberEnum.C
};

enum ToneMapping {
LINEAR = TONEMAP_LINEAR,
FILMIC = TONEMAP_FILMIC,
HEJL = TONEMAP_HEJL,
ACES = TONEMAP_ACES,
ACES2 = TONEMAP_ACES2,
NEUTRAL = TONEMAP_NEUTRAL
};

class Example extends Script {
static scriptName = 'example';

Expand Down Expand Up @@ -47,6 +56,11 @@ class Example extends Script {
* @attribute
*/
i : NumberNumberEnum = 2;

/**
* @attribute
*/
j : ToneMapping = ToneMapping.LINEAR;
}

export { Example };
Loading