feat(ast)!: narrow TSInterfaceHeritage::expression to TSTypeName - #24360
Conversation
Merging this PR will not alter performance
Comparing Footnotes
|
Monitor OxcCommit:
|
Oxfmt Ecosystem CI
💥 = panic, |
TSInterfaceHeritage::expression to TSTypeName
dd946fd to
1b185be
Compare
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
1b185be to
9a7f623
Compare
9a7f623 to
13783e9
Compare
|
/monitor-oxc run |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4f3c0c310a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
This PR tightens the Rust AST representation of TypeScript interface heritage clauses by replacing TSInterfaceHeritage::expression: Expression<'a> with TSInterfaceHeritage::type_name: TSTypeName<'a>, making several invalid extends forms structurally unrepresentable in the AST and aligning parsing/serialization behavior accordingly.
Changes:
- Narrow
TSInterfaceHeritagefromExpressiontoTSTypeNameand update traversal/visitor/codegen/formatter/semantic/linter integrations to usetype_name. - Improve parser diagnostics for invalid/empty
extendsclauses (e.g. TS1097 empty list, TS1009 trailing comma, TS2499 invalid heritage target) and add a new negative fixture. - Update JS/NAPI raw-transfer deserializers and walkers to read the new layout and keep TS-ESTree compatibility by converting
TSQualifiedNameintoMemberExpressionfor theexpressionfield.
Reviewed changes
Copilot reviewed 14 out of 43 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tasks/coverage/snapshots/parser_typescript.snap | Updates TypeScript conformance snapshot output for new interface-heritage diagnostics. |
| tasks/coverage/snapshots/parser_misc.snap | Updates misc snapshot counts and adds new expected failures for invalid interface heritage. |
| tasks/coverage/snapshots/parser_babel.snap | Updates Babel snapshot expectations to reflect new diagnostics and recovery. |
| tasks/coverage/misc/fail/ts-interface-invalid-heritage.ts | Adds a new negative fixture covering invalid interface heritage forms. |
| napi/parser/src-js/generated/lazy/walk.js | Lazy walker updated to traverse TSTypeName at the heritage field offset. |
| napi/parser/src-js/generated/lazy/constructors.js | Lazy constructors updated to construct TSTypeName for TSInterfaceHeritage.expression. |
| napi/parser/src-js/generated/deserialize/ts.js | TS deserializer updated to read TSTypeName and convert qualified names to MemberExpression for TS-ESTree expression. |
| napi/parser/src-js/generated/deserialize/ts_range.js | Same as above, with range support. |
| napi/parser/src-js/generated/deserialize/ts_range_parent.js | Same as above, with range + parent support. |
| napi/parser/src-js/generated/deserialize/ts_parent.js | Same as above, with parent support. |
| napi/parser/src-js/generated/deserialize/js.js | JS deserializer updated analogously for the new heritage layout. |
| napi/parser/src-js/generated/deserialize/js_range.js | Same as above, with range support. |
| napi/parser/src-js/generated/deserialize/js_range_parent.js | Same as above, with range + parent support. |
| napi/parser/src-js/generated/deserialize/js_parent.js | Same as above, with parent support. |
| apps/oxlint/src-js/generated/deserialize.js | Oxlint JS deserializer updated to match the new heritage layout and TS-ESTree conversion. |
| crates/oxc_traverse/src/generated/walk.rs | Traverse walker updated to walk TSTypeName instead of Expression in interface heritage. |
| crates/oxc_traverse/src/generated/scopes_collector.rs | Removes visiting the old expression field for TSInterfaceHeritage. |
| crates/oxc_traverse/src/generated/ancestor.rs | Updates ancestor types/offsets/accessors for TSInterfaceHeritage.type_name. |
| crates/oxc_semantic/src/builder.rs | Semantic builder updated to visit type_name as a type reference. |
| crates/oxc_parser/src/ts/statement.rs | Parser updated to parse/validate interface heritage as a TSTypeName and emit TS-aligned diagnostics. |
| crates/oxc_parser/src/js/class.rs | Refactors class heritage parsing wrapper and improves duplicate-extends handling. |
| crates/oxc_parser/src/diagnostics.rs | Adds TS1097 empty-extends and TS1009 trailing-comma diagnostics helpers. |
| crates/oxc_minifier/src/traverse_context/scopes_collector.rs | Removes visiting the old expression field for TSInterfaceHeritage. |
| crates/oxc_minifier/src/generated/walk.rs | Minifier traverse walker updated to walk TSTypeName in interface heritage. |
| crates/oxc_minifier/src/generated/ancestor.rs | Minifier ancestor types/offsets/accessors updated for TSInterfaceHeritage.type_name. |
| crates/oxc_linter/src/snapshots/typescript_no_empty_interface.snap | Snapshot updated to reflect TS1097 diagnostic for empty extends list. |
| crates/oxc_linter/src/rules/typescript/prefer_function_type.rs | Lint rule updated to match on TSInterfaceHeritage.type_name. |
| crates/oxc_linter/src/rules/typescript/no_wrapper_object_types.rs | Lint rule updated to match on TSInterfaceHeritage.type_name. |
| crates/oxc_linter/src/rules/typescript/no_unsafe_function_type.rs | Lint rule updated to match on TSInterfaceHeritage.type_name. |
| crates/oxc_linter/src/rules/typescript/no_invalid_void_type.rs | Updates span extraction to use type_name.span(). |
| crates/oxc_formatter/src/print/mod.rs | Formatter updated to print type_name for interface heritage and adjust grouping heuristic. |
| crates/oxc_formatter/src/ast_nodes/generated/ast_nodes.rs | Formatter AST node accessor renamed from expression() to type_name(). |
| crates/oxc_codegen/src/gen.rs | Codegen updated to print the TSTypeName for interface heritage. |
| crates/oxc_ast/src/serialize/ts.rs | Adds TSInterfaceHeritageExpression adapter to serialize type_name as TS-ESTree expression (MemberExpression conversion). |
| crates/oxc_ast/src/generated/derive_estree.rs | Uses the new adapter when serializing TSInterfaceHeritage.expression. |
| crates/oxc_ast/src/generated/derive_dummy.rs | Dummy impl updated to fill type_name instead of expression. |
| crates/oxc_ast/src/generated/derive_content_eq.rs | Content equality updated to compare type_name. |
| crates/oxc_ast/src/generated/derive_clone_in.rs | CloneIn updated to clone type_name. |
| crates/oxc_ast/src/generated/ast_builder.rs | AST builder updated to accept type_name: TSTypeName. |
| crates/oxc_ast/src/generated/assert_layouts.rs | Layout assertions updated for type_name field offsets. |
| crates/oxc_ast/src/ast/ts.rs | Changes the Rust AST field to type_name and wires TS-ESTree rename/via adapter. |
| crates/oxc_ast_visit/src/generated/visit.rs | Visitor generation updated to visit type_name as a TS type name. |
| crates/oxc_ast_visit/src/generated/visit_mut.rs | Mutable visitor generation updated to visit type_name as a TS type name. |
Merge activity
|
…24360) ## Summary Narrow `TSInterfaceHeritage` from a general JavaScript `Expression` to `TSTypeName`. ```rust pub struct TSInterfaceHeritage<'a> { pub type_name: TSTypeName<'a>, pub type_arguments: Option<Box<'a, TSTypeParameterInstantiation<'a>>>, } ``` ## Breaking Change The Rust AST field changes from: ```rust expression: Expression<'a> ``` to: ```rust type_name: TSTypeName<'a> ``` ## Why? The current AST can represent shapes such as: ```ts interface A extends foo() {} interface A extends A + B {} interface A extends new Foo() {} interface A extends true {} ``` Which is an overly wide type since all of the above variants are invalid. This PR tightens up the AST, making these invalid variants irrepresentable. ## How to migrate? This should be a trivial migration: 1. instead of accessing `expression` on `TSInterfaceHeritage`, now access `type_name` 2. change any pattern matching on the `type_name` field to use `TypeName` (this is a smaller subset so should allow deleting code!) closes https://github.com/oxc-project/backlog/issues/215
b011ad2 to
6b4246d
Compare
…24360) ## Summary Narrow `TSInterfaceHeritage` from a general JavaScript `Expression` to `TSTypeName`. ```rust pub struct TSInterfaceHeritage<'a> { pub type_name: TSTypeName<'a>, pub type_arguments: Option<Box<'a, TSTypeParameterInstantiation<'a>>>, } ``` ## Breaking Change The Rust AST field changes from: ```rust expression: Expression<'a> ``` to: ```rust type_name: TSTypeName<'a> ``` ## Why? The current AST can represent shapes such as: ```ts interface A extends foo() {} interface A extends A + B {} interface A extends new Foo() {} interface A extends true {} ``` Which is an overly wide type since all of the above variants are invalid. This PR tightens up the AST, making these invalid variants irrepresentable. ## How to migrate? This should be a trivial migration: 1. instead of accessing `expression` on `TSInterfaceHeritage`, now access `type_name` 2. change any pattern matching on the `type_name` field to use `TypeName` (this is a smaller subset so should allow deleting code!) closes https://github.com/oxc-project/backlog/issues/215
c28f2f1 to
5c5cdcd
Compare
### 💥 BREAKING CHANGES - a33788e ast: [**BREAKING**] Group class heritage into `ClassHeritage` (#25360) (camc314) - 5c5cdcd ast: [**BREAKING**] Narrow `TSInterfaceHeritage::expression` to TSTypeName (#24360) (camc314) - 6be314f ast: [**BREAKING**] Remove duplicated `VariableDeclarator::kind` (#25319) (camc314) - 44fd320 ast: [**BREAKING**] Split TS external modules & Namespace Declarations (#25284) (camc314) ### 🚀 Features - 9a37c41 napi: Restructure React transform options (#25326) (Boshen) - b3c1b30 allocator: Add `ArenaVec::push_mut` (#25338) (overlookmotel) ### 🐛 Bug Fixes - bbd6ed3 codegen: Wrap string literal in parens after directives (#25435) (overlookmotel) - d07a293 codegen: Preserve cast parentheses in conditional tests (#25115) (camc314) - 8b7d441 codegen: Preserve satisfies parentheses before bitwise operators (#25113) (camc314) - e0fb2d7 minifier: Avoid unsafe return removal in labeled blocks (#25406) (Armano) - c49f4ce parser: Preserve terminal license comments (#25400) (camc314) - 9d19ab3 transform_react: Downgrade nonfatal compiler diagnostics (#25418) (Boshen) - 937825c react_compiler: Disable exhaustive memo validation by default (#25417) (Boshen) - 12937b3 parser: Reject comma expressions in class fields (#25385) (Cameron) - 7d8a9b5 react_compiler: Preserve hook spans for React Refresh (#25393) (Boshen) - 9e93ba6 parser: Reset auto-accessor initializer context (#25384) (camc314) - cc2e28d parser: Reject trailing tokens in `Parser::parse_expression` (#25371) (camc314) - 697c629 minifier: Preserve Annex B labeled-function bindings in implicit-return rewrite (#25349) (Armano) - 4d723ca parser: Report TS1035 for quoted module names (#25305) (camc314) - 0c9b980 semantic: Report module declaration diagnostics (#25285) (camc314) - 2a1058a napi: Omit parser header from WASI declarations (#25254) (camc314) ### ⚡ Performance - dd1430b semantic: Avoid allocation in class overload check (#25440) (camc314) - e420816 parser: Optimize trailing comma tracking (#25376) (camc314) - 6529d1a minifier: Short-circuit scope check when alternate already determines result (#25318) (Armano) ### 📚 Documentation - fe111eb allocator: Improve doc comments for `Arena` methods (#24922) (overlookmotel)
# Oxlint ### 💥 BREAKING CHANGES - a33788e ast: [**BREAKING**] Group class heritage into `ClassHeritage` (#25360) (camc314) - 5c5cdcd ast: [**BREAKING**] Narrow `TSInterfaceHeritage::expression` to TSTypeName (#24360) (camc314) - 6be314f ast: [**BREAKING**] Remove duplicated `VariableDeclarator::kind` (#25319) (camc314) - 44fd320 ast: [**BREAKING**] Split TS external modules & Namespace Declarations (#25284) (camc314) ### 🚀 Features - ccb8fe8 linter/jsdoc: Implement `no-blank-blocks` rule (#25207) (Mikhail Baev) - d4a897c linter/eslint: Implement `one-var` rule (#24470) (Cole Ellison) - 5ab9340 linter/jsx-a11y/anchor-has-content: Add options to match eslint (#24571) (Cole Ellison) ### 🐛 Bug Fixes - b746e00 linter/eslint/no-implicit-coercion: Preserve template coercion whitespace (#25470) (camc314) - a92c541 linter: Preserve source text for JS plugin ignore fixes (#25280) (Norcleeh) - 675c840 linter/eslint/prefer-promise-reject-errors: Handle parenthesized calls (#25378) (camc314) - 1703739 linter/unicorn/new-for-builtins: Ignore optional chains (#25411) (tanakalucky) - 95ece63 linter/unicorn/prefer-code-point: Downgrade the auto-fix to dangerous (#25412) (leemr) - c451a0e linter/vitest: Validate `consistent-test-filename` regex patterns (#25408) (Mikhail Baev) - 937825c react_compiler: Disable exhaustive memo validation by default (#25417) (Boshen) - f0f7dae linter/eslint/no-unused-vars: Report invalid regex options (#25380) (Cameron) - 44e73fd linter/unicorn/prefer-array-flat: Fix `concat.apply` suggestions (#25373) (Cameron) - 6846a9a linter/react/rules-of-hooks: Detect constructor callbacks (#25377) (camc314) - b247a9d linter/unicorn/new-for-builtins: Support `Float16Array` (#25382) (tanakalucky) - 19109cd linter/unicorn/error-message: Support `SuppressedError` messages (#25375) (camc314) - 9c13f5e linter: Assert token lookup invariants (#25368) (camc314) - bc35f83 linter/eslint/no-unused-vars: Bound catch parameter lookup (#25367) (camc314) - c159fb9 linter/unicorn/switch-case-braces: Bound token lookup (#25363) (camc314) - 03b2eb2 linter/unicorn/no-static-only-class: Bound token lookup (#25361) (camc314) - 0afc59e linter/unicorn/empty-brace-spaces: Bound token lookup (#25353) (camc314) - 2963d98 linter/eslint/no-unreachable-loop: Do not report loops whose body has a finally block (#25335) (Todor Andonov) - 589e5fb linter/eslint/no-param-reassign: Validate `ignorePropertyModificationsForRegex` property (#25346) (Mikhail Baev) - aae5d8b linter/eslint/no-throw-literal: False positive on variable declared without initializer (#25275) (cjnoname) - 6b1c479 oxlint: Normalize customized rule names (#25316) (camc314) - d494eb5 linter/unicorn/consistent-existence-index-check: Bound token lookup (#25325) (camc314) - 4266037 linter/typescript/prefer-namespace-keyword: Bound token lookup (#25322) (camc314) - 4745b4e linter/typescript/no-namespace: Bound token lookup (#25321) (camc314) - 648a481 linter/eslint/one-var: Avoid joining exported declarations (#25314) (camc314) - 9573937 linter/typescript: Validate `ban-ts-comment` description_format (#25320) (Mikhail Baev) - ebf7d18 linter/typescript/consistent-type-definitions: Bound token lookup (#25281) (camc314) - 1501ccf linter/typescript/consistent-generic-constructors: Bound token lookup (#25258) (camc314) ### ⚡ Performance - 8f784f3 linter: Reduce rule config dispatch size (#25461) (Boshen) - 2de4ec2 linter: Reduce visitor code size (#25441) (Boshen) - 6fb7f47 linter/unicorn/prefer-export-from: Narrow `ExportFromDeclaration` lookup (#25381) (camc314) - e3f6263 linter/unicorn/prefer-default-parameters: Avoid reference allocation (#25379) (camc314) - d863473 linter/vue/max-props: Narrow AST dispatch (#25372) (camc314) - 273d867 linter: Avoid diagnostic sorting after applying fixes (#25079) (Sysix) - 4ec9189 oxlint/lsp: Avoid second lock for getting/removing unused directives (#25350) (Sysix) - 6c0d01b oxlint/lsp: Preallocate fix-content vec (#25351) (Sysix) - 3a94055 linter: Avoid per-call heap allocations in jest and unicorn helpers (#25210) (Connor Shea) - 4abff11 linter: Avoid redundant message work in the agent reporter (#25315) (Connor Shea) - 6bb5421 linter: Hoist `current_dir` out of the stylish reporter loop (#25313) (Connor Shea) - 9a7c323 linter: Compute diagnostic `Info` once per diagnostic in junit reporter (#25312) (Connor Shea) - 1cf7dde oxlint: Render JSON report into a single buffer (#25295) (connorshea) - 8492cfd linter/typescript/ban-ts-comment: Bail early with substring guard (#25301) (Jacob Asper) - 7607f04 linter/typescript/ban-tslint-comment: Replace regex with manual parser (#25299) (Jacob Asper) # Oxfmt ### 💥 BREAKING CHANGES - a33788e ast: [**BREAKING**] Group class heritage into `ClassHeritage` (#25360) (camc314) - 5c5cdcd ast: [**BREAKING**] Narrow `TSInterfaceHeritage::expression` to TSTypeName (#24360) (camc314) - 6be314f ast: [**BREAKING**] Remove duplicated `VariableDeclarator::kind` (#25319) (camc314) - 44fd320 ast: [**BREAKING**] Split TS external modules & Namespace Declarations (#25284) (camc314) ### 🚀 Features - fd02a89 oxfmt: Dispatch yaml-in-css(frontmatter) to `oxc_formatter_yaml` (#25336) (leaysgur) - ab12665 formatter_core: Add `hardlineWithoutBreakParent` equivalent IR (#25273) (leaysgur) ### 🐛 Bug Fixes - 95dc917 oxfmt: Drop IR Space at line start for js-in-xxx (#25460) (leaysgur) - b63eccc formatter: Keep comments after TS this_param (#25459) (leaysgur) - ab52a59 formatter: Format xxx-in-js inside JSDoc js fence (#25414) (leaysgur) - 1a2c64a formatter,oxfmt: Apply effective print width for JSDoc fence (#25413) (leaysgur) - 2eaede9 formatter_core: Unify leading-BOM handlings (#25340) (leaysgur) - ef1d04b formatter: Break mapped type brackets (#25297) (leaysgur) - 4e6f3f1 formatter: Break index signature brackets (#25296) (leaysgur) - e23dccf formatter_css: Bump oxc-css-parser to accept unknown at-rule with interpolated (#25277) (leaysgur) - c29b587 formatter_core: Measure decided-flat fill separator as flat during group re-measure (#25276) (leaysgur) - f3c6953 formatter_yaml: Don't rewrite overflowing key to implicit (#25274) (leaysgur) ### ⚡ Performance - c9d1a5b oxfmt: Spawn tinypool lazily (#25298) (leaysgur) ### 📚 Documentation - 6eae5c9 formatter,oxfmt: Record embed-layer decisions in place (#25422) (leaysgur) - 51224a7 formatter_yaml: Pin EOF blank lines divergence (#25269) (leaysgur)
Summary
Narrow
TSInterfaceHeritagefrom a general JavaScriptExpressiontoTSTypeName.Breaking Change
The Rust AST field changes from:
to:
Why?
The current AST can represent shapes such as:
Which is an overly wide type since all of the above variants are invalid.
This PR tightens up the AST, making these invalid variants irrepresentable.
How to migrate?
This should be a trivial migration:
expressiononTSInterfaceHeritage, now accesstype_nametype_namefield to useTypeName(this is a smaller subset so should allow deleting code!)closes #25687