Skip to content

feat: add enum support to Explorer - #606

Open
rasadregmi wants to merge 1 commit into
freeCodeCamp:mainfrom
rasadregmi:feat/explorer-enums
Open

rasadregmi wants to merge 1 commit into
freeCodeCamp:mainfrom
rasadregmi:feat/explorer-enums

Conversation

@rasadregmi

Copy link
Copy Markdown

Checklist:

Closes #605

This PR adds enum support to Explorer, which currently has no way to see TypeScript enums at all.

Because of that, curriculum tests have to assert enums with regular expressions. A concrete example is the Digital Pet Game lab:

https://github.com/freeCodeCamp/freeCodeCamp/blob/main/curriculum/challenges/english/blocks/lab-digital-pet-game/68c362b379059c388d3874f2.md

Eight assertions in that lab (lines 360-402) each check one member like this:

assert.match(code, /\s*enum\s+PetMood\s*{[\s*\w+,\s*]*HAPPY[\s*\w+,\s*]*}/);

The character class [\s*\w+,\s*] only allows word characters, commas and *, so this passes for HAPPY, but rejects the equally valid HAPPY = 'HAPPY', — the =, the quotes and the spaces around them all fall outside the class.

With enum support the same check becomes a single assertion:

const explorer = new Explorer(code);
assert.deepEqual(Object.keys(explorer.enums.PetMood.enumMembers), ["HAPPY"]);

Why this is better in practice:

  • accepts any valid enum member, including HAPPY = 'HAPPY'
  • no duplicated regex per member
  • scope is handled for you, so an enum declared inside a function won't produce a false pass
  • value exposes the initializer, so enumMembers.HAPPY.value.matches("'HAPPY'") works

Implementation notes:

  • findMembers now returns EnumDeclaration.members; its return type is widened to include EnumMember, which does not extend ClassElement
  • new enums and enumMembers accessors, mirroring classes and methods
  • value returns an enum member's initializer, or an empty Explorer
  • a new enumMember parse context so matches() works

That last one is required rather than incidental. An EnumMember is neither a TypeNode nor an Expression, so it falls through every existing CONTEXT_GUARDS entry to "source", where it gets compared against an ExpressionStatement — which never matches.

Regular, const and exported enums are all EnumDeclaration statements, so all three are found. Members are keyed with name.getText() rather than the (name as Identifier).text cast used elsewhere in the file, because ComputedPropertyName has no text property and would collapse every computed member onto a single bogus undefined key.

Tests cover regular/const/exported enums, initialized and uninitialized members, string, numeric and computed initializers, scope isolation, non-identifier member names, and the exact HAPPY = 'HAPPY' case the lab regex rejects. The new tests were confirmed to fail before the fix and pass after it.

pnpm test:unit (344 tests) and pnpm test:python (137 tests) pass, along with pnpm lint and pnpm build.

On documentation: I documented the new accessors using the same inline comment convention every other accessor in explorer.ts follows. I did not add a docs page because Explorer doesn't have one today — docs/ has no Explorer references at all and docs/javascript.md is a 3-line stub. Happy to add one if you'd prefer that, though it would mean a new file plus a SUMMARY.md nav entry.

Closes freeCodeCamp#605

`Explorer` could not see TypeScript enums at all, so curriculum tests had
to fall back on regular expressions. Those regexes reject valid code --
for example the Digital Pet Game lab asserts

  /\s*enum\s+PetMood\s*{[\s*\w+,\s*]*HAPPY[\s*\w+,\s*]*}

which matches `HAPPY,` but fails on `HAPPY = 'HAPPY',` because the
character class excludes `=` and quotes.

Adds the same treatment the other node kinds already receive:

- `findMembers` returns `EnumDeclaration.members`, so `getAll()` can reach
  enum members
- `enums` maps enum declarations by name, mirroring `classes`/`interfaces`
- `enumMembers` maps members of a single enum, mirroring `methods`
- `value` returns an enum member's initializer, or an empty `Explorer`
- a new `enumMember` parse context so `matches()` works

The parse context is required, not incidental: an `EnumMember` is neither
a `TypeNode` nor an `Expression`, so it falls through every existing
`CONTEXT_GUARDS` entry to `"source"` and gets compared against an
`ExpressionStatement`, which never matches.

Regular, `const` and exported enums are all `EnumDeclaration` statements,
so all three are found. Members are keyed with `name.getText()` rather
than the `(name as Identifier).text` cast used elsewhere, because
`ComputedPropertyName` has no `text` property and would collapse onto a
single bogus `undefined` key.
@rasadregmi
rasadregmi requested a review from a team as a code owner September 29, 2026 15:14
@majestic-owl448

Copy link
Copy Markdown
Contributor

the issue is not open for contributors, please look at issues with the help wanted label

at this time we will not be able to review your PR

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request]: Add enum support to Explorer

2 participants