Skip to content

fix(linter/plugins): make spreading Token instances keep loc property#22947

Merged
overlookmotel merged 5 commits into
oxc-project:mainfrom
KuSh:spread-tokens
Jun 6, 2026
Merged

fix(linter/plugins): make spreading Token instances keep loc property#22947
overlookmotel merged 5 commits into
oxc-project:mainfrom
KuSh:spread-tokens

Conversation

@KuSh

@KuSh KuSh commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Follow-up of #22238, same logic applied to Token class

Problem

Token instances are object-pooled and reused across files, similar to Comment.
Their loc property is defined as a prototype getter, which means it is not an own
property and is therefore invisible to the spread operator:

const spread = { ...token };
"loc" in spread; // false ❌

This silently drops loc whenever a JS plugin (or rule) spreads a token — e.g. when
building a diagnostic from { ...token, message: "…" }.

JSON.stringify had the same problem and was patched with a toJSON() workaround.
A separate Object.defineProperty(Token.prototype, "loc", { enumerable: true }) call
was used to make loc show up in for…in iteration, but it still didn't fix spread.

Fix

Define loc as an own accessor property on every Token instance using
__defineGetter__. Own properties are visible to spread, JSON.stringify, and
for…in iteration, so all three work without any extra workarounds.

The getter function is defined in the class static block and captured in a const
(getTokenLoc). Using a const rather than a let lets V8 skip reassignment checks
at the defineGetter(this, "loc", getTokenLoc) call site — a pattern already
established in the codebase for resetLoc.

As a result:

  • toJSON() is removed — JSON.stringify now works via the own property directly.
  • Object.defineProperty(Token.prototype, "loc", { enumerable: true }) is removed —
    no longer needed.

Test

A spread assertion is added to the existing tokens fixture:

const spread = { ...firstToken };
assert("loc" in spread);           // was false before this fix
assert.deepEqual(spread.loc, firstToken.loc);

@overlookmotel overlookmotel self-assigned this Jun 3, 2026
@overlookmotel overlookmotel added the A-linter-plugins Area - Linter JS plugins label Jun 3, 2026
@KuSh KuSh force-pushed the spread-tokens branch from e3c2e3f to 8f0ce60 Compare June 5, 2026 22:17
@KuSh KuSh marked this pull request as draft June 5, 2026 22:25
@KuSh KuSh force-pushed the spread-tokens branch from 8f0ce60 to 87f063f Compare June 5, 2026 22:25
@KuSh

KuSh commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

Require #22238 to be merged and a rebase for the tests to pass

@KuSh KuSh force-pushed the spread-tokens branch from 87f063f to 314d66b Compare June 5, 2026 22:28
@overlookmotel overlookmotel requested a review from Copilot June 6, 2026 01:16
@overlookmotel overlookmotel marked this pull request as ready for review June 6, 2026 01:16

@overlookmotel overlookmotel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Rebased on main, and made same tweaks as in #22947. Merging as soon as CI passes.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the oxlint JS plugin Token implementation so that spreading a Token instance (e.g. { ...token }) preserves the loc property, matching the earlier fix applied to Comment in #22238 and preventing loc from being silently dropped in diagnostics and other plugin/rule code.

Changes:

  • Define loc as an own accessor property on each Token instance via __defineGetter__ (through a shared bound defineGetter helper).
  • Remove the toJSON() workaround and the Object.defineProperty(Token.prototype, "loc", { enumerable: true }) tweak, since loc becomes enumerable on the instance.
  • Extend the existing tokens fixture plugin to assert that { ...tokenOrComment } includes an own loc property and that it matches the original value.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
apps/oxlint/src-js/plugins/tokens.ts Changes Token.loc from a prototype getter to an own accessor property so spread/JSON/iteration keep loc.
apps/oxlint/test/fixtures/tokens/plugin.ts Adds an assertion that spreading tokens/comments retains loc as an own property.

Comment thread apps/oxlint/src-js/plugins/tokens.ts Outdated
@overlookmotel overlookmotel changed the title fix(linter/plugins): make spreading Token instances keep loc property fix(linter/plugins): make spreading Token instances keep loc property Jun 6, 2026
@overlookmotel overlookmotel merged commit 6cb34b8 into oxc-project:main Jun 6, 2026
30 checks passed
@KuSh KuSh deleted the spread-tokens branch June 6, 2026 13:19
Boshen added a commit that referenced this pull request Jun 8, 2026
# Oxlint
### 🚀 Features

- e805174 linter: Add schema for `jest/vitest/max-expects` (#23105)
(Sysix)
- 7850577 linter: Add schema for `jest/vitest/expect-expect` (#23104)
(Sysix)
- 75f641a linter: Add schema for `jest/vitest/consistent-test-it`
(#23103) (Sysix)
- 5125f89 linter/unicorn: Support no-null `checkArguments` option
(#23098) (camc314)
- b8b9797 linter: Add schema for `import-max-dependencies` (#23096)
(Sysix)
- 65cb47a linter/eslint: Support no-unused-expressions
`ignoreDirectives` option (#23097) (camc314)
- f6c36d5 linter: Add schema for `import/prefer-default-export` (#23091)
(Sysix)
- 0d4a5d1 linter: Add schema for `eslint/sort-vars` (#23090) (Sysix)
- fdb5bf5 linter: Add schema for `eslint/radix` (#23082) (Sysix)
- 05b4dcf linter: Add schema for `eslint/prefer-const` (#23081) (Sysix)
- 5a06c4d linter/vue: Implement next-tick-style rule (#23041) (Alex
Peshkov)
- e38a36a linter: Add schema for `eslint/operator-assignment` (#23080)
(Sysix)
- 907cee7 linter: Add schema for `eslint/no-warning-comments` (#23075)
(Sysix)
- 9470bb2 linter: Add schema for `eslint/no-unused-vars` (#23073)
(Sysix)
- 234b5cf linter: Add schema for `eslint/no-shadow` (#23072) (Sysix)
- de0dd8b linter: Add schema for `eslint/no-restricted-exports` (#23020)
(Sysix)
- faa3e0d linter: Add schema for `eslint/no-param-reassign` (#23018)
(Sysix)
- dbc9c27 linter: Add schema for `eslint/no-magic-numbers` (#23017)
(Sysix)
- 38d3569 linter: Add schema for `eslint/no-inner-declarations` (#23016)
(Sysix)
- 008fa41 linter: Add schema for `eslint/no-constant-condition` (#22991)
(Sysix)
- ca44623 linter: Add schema for `eslint/no-empty-function` (#22988)
(Sysix)
- 43eb04d linter: Add schema for `eslint/id-match` (#22987) (Sysix)
- a800f27 linter: Add schema for `eslint/capitalized-comments` (#22984)
(Sysix)
- 96e2d32 linter: Add schema for `eslint/id-length` (#22963) (Sysix)
- 545493f linter: Add schema for `eslint/complexity` (#22960) (Sysix)
- 5f0b558 linter: Add schema for `eslint/class-methods-use-this`
(#22959) (Sysix)
- 719b720 linter: Add schema for simple rule configurations (#22948)
(Sysix)
- fd00966 linter: Add right schema for `eslint/max-*` rules (#22923)
(Sysix)
- 1226d78 linter: Fill schema with rule configurations (#22907) (Sysix)
- 8f423c1 linter/vue: Implement `require-direct-export` rule (#17623)
(yefan)
- 78e915b linter/vue: Implement no-reserved-props rule (#22914) (bab)
- 0f200a9 linter/vue: Implement require-prop-types rule (#22083) (Alex
Peshkov)
- 5da9da9 linter/vue: Implement no-reserved-keys rule (#21780) (bab)
- 75e14a8 linter/vue: Implement prop-name-casing rule (#22892) (bab)
- 85efabf semantic: Make building the class table optional, off by
default (#22862) (Boshen)

### 🐛 Bug Fixes

- a49b0cf linter/no-map-spread: Remove ineffective autofix (#22956)
(camc314)
- cf53285 parser: Report reserved type-declaration names in the parser
(#23035) (Boshen)
- 0383e61 linter: Fix schema for rules without a config (#22946) (Sysix)
- 4d722e0 parser: Report duplicate switch `default` clause in the parser
(#23012) (Boshen)
- 6cb34b8 linter/plugins: Make spreading `Token` instances keep `loc`
property (#22947) (Nicolas Le Cam)
- 27de044 linter/plugins: Make spreading `Comment` instances keep `loc`
property (#22238) (Nicolas Le Cam)
- 742fd0b linter/double-comparisons: Make fixer a suggestion (#22968)
(camc314)
- 93f4494 linter: Respect default child config plugin when extending
parent config (#22903) (Sysix)
- 594ed86 linter: Deny unknown options for some rules (#22924) (Sysix)
- 3253038 linter/expect-expect: Align default rule options (#22890)
(camc314)
- bbe44ea linter: Respect default plugins from extended config (#22896)
(Sysix)

### ⚡ Performance

- 0b7ce7e linter/plugins: Create global prop vars at top level of
modules (#22928) (overlookmotel)
- 0f7c319 linter/plugins: Define class `#loc` setter functions as
`const`s (#22919) (overlookmotel)

### 📚 Documentation

- 7b0380d linter: Remove preserve-caught-error note (#22994) (camc314)
- dadafe3 oxlint, oxfmt: Mention migrate skills in npm READMEs (#22965)
(Boshen)
# Oxfmt
### 🚀 Features

- 3da77e0 oxfmt: Format `parser:json5` files by `oxc_formatter_json`
(#22990) (leaysgur)
- c786f0d oxfmt: Format `parser:jsonc` files by `oxc_formatter_json`
(#22913) (leaysgur)
- 27a6db8 formatter_json: Implement jsonc variant (#22912) (leaysgur)

### 🐛 Bug Fixes

- 2aedd52 oxfmt: Avoid JS promise rejects for all TSFN call sites
(#23107) (leaysgur)
- 01e0871 formatter,formatter_json: Handle PS/LS as line terminator
(#22978) (leaysgur)
- 23902d9 formatter_json: Handle CR only line breaks (#22977) (leaysgur)
- 136b72b formatter_json: Use line_suffix for line comment outside array
(#22931) (leaysgur)
- 44e40fa formatter_json: Expand line comment inside array (#22911)
(leaysgur)
- 2c86896 formatter_json: Avoid example binary name collision (#22904)
(camc314)

### 📚 Documentation

- cc69d8d formatter_json: Update AGENTS.md (#22981) (leaysgur)
- 0490721 formatter_json: Update AGENTS.md (#22976) (leaysgur)
- dadafe3 oxlint, oxfmt: Mention migrate skills in npm READMEs (#22965)
(Boshen)
- f88961a oxfmt: Annotate each config option with supported languages
(#22953) (leaysgur)
- 7e514bf formatter_json: Update AGENTS.md (#22930) (leaysgur)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-linter-plugins Area - Linter JS plugins

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants