Skip to content

fix: skip members whose names aren't identifiers instead of throwing - #79

Open
willeastcott wants to merge 1 commit into
mainfrom
fix/non-identifier-member-names
Open

willeastcott wants to merge 1 commit into
mainfrom
fix/non-identifier-member-names

Conversation

@willeastcott

Copy link
Copy Markdown
Collaborator

getType() returns null for a class member whose name isn't an identifier: a private field (#secret), or a computed (['computed']), quoted ('quoted') or numeric (42) name. Two callers used the result without checking it:

  1. getAttributes() read type.name for every non-static property of an ESM script, so any script class with such a member threw TypeError: Cannot read properties of null (reading 'name').
  2. AttributeParser.getNodeAsAttribute() destructured the result, so an @attribute tag on such a member, or such a member inside an @interface type, threw TypeError: Cannot destructure property 'type' of 'getType(...)' as it is null. getAttributes() calls parseAttributes() first, so a script with an @interface attribute or a tagged private field hits this one first.

Both threw out of the parser, so the whole file returned no attributes and no diagnostics. The PlayCanvas Editor's code editor runs getAttributes() in a web worker for attribute autofill, so a script with a plain private field crashed that worker on every parse, and these crashes show up in the editor's error reports.

Changes

  • getAttributes() skips a member when getType() returns null.
  • getNodeAsAttribute() returns early in the same case. Both of its callers already treat an empty result as "not an attribute".
  • Add member-names.valid.js regression coverage: one script with a private field, a private field tagged @attribute, computed, quoted and numeric names, an @interface attribute whose type has a private field, and two valid attributes. It checks that parseAttributes() and getAttributes() both succeed with no errors, that only the identifier-named attributes come back, and that the interface's schema leaves out its private field.

Members with these names can't be attributes, so they're skipped silently, which matches how other non-attribute members are treated. An @attribute tag on a private field is ignored rather than reported. That could become an error in a follow-up if it's worth flagging.

Testing

  • npm test: the 5 new tests pass. Before the fix, both before hooks threw the destructuring error; with only the getNodeAsAttribute() change, the getAttributes() test threw the type.name error, so both guards are needed. All other tests are unchanged. On my Windows checkout misc.valid.js "a" fails the same way with and without this change, because core.autocrlf adds a trailing \r to its multi-line description.
  • npm run lint and tsc -p tsconfig.build.json --noEmit are clean.

Manual smoke test

  1. In an ESM script, add #secret = 1; alongside /** @attribute */ speed = 1;, then parse and open attribute autofill in the code editor.
    • Expected: speed is still offered and nothing throws.
  2. Tag the private field: /** @attribute @type {number} */ #secret = 1;.
    • Expected: no exception; #secret isn't listed as an attribute.

🤖 Generated with Claude Code

getType() returns null for a class member whose name isn't an identifier:
a private field (#secret), a computed (['computed']), quoted ('quoted') or
numeric (42) name. Two callers used the result without checking:

- getNodeAsAttribute() destructured it, so an @Attribute tag on such a
  member, or such a member in an @interface type, threw "Cannot destructure
  property 'type' of 'getType(...)' as it is null".
- getAttributes() read type.name, so any script class with such a member
  threw "Cannot read properties of null (reading 'name')".

The editor's code editor runs getAttributes() in its esm-script worker for
attribute autofill, so a script with a private field crashed the worker on
every parse. Both now skip the member, as it can't be an attribute anyway.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@willeastcott willeastcott added the bug Something isn't working label Oct 24, 2026
@willeastcott
willeastcott requested a review from kpal81xd October 24, 2026 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants