compat-eslint: dogfood-corpus parity sweep + 6 drift fixes it caught#93
Closed
johnsoncodehk wants to merge 1 commit into
Closed
compat-eslint: dogfood-corpus parity sweep + 6 drift fixes it caught#93johnsoncodehk wants to merge 1 commit into
johnsoncodehk wants to merge 1 commit into
Conversation
The 15-fixture parity sweep covers known bug classes; once it passes,
the next drift surface is uncovered slot/wrapper combinations in real
production code. Replay the same node-level invariant across the
dogfood corpus — every TS file in the monorepo, ~65k type asserts and
~64.7k parent asserts.
Six bugs surfaced by the broader sweep, fixed in this PR:
1. PropertyDeclaration / MethodDeclaration / GetAccessor missing from
TYPE_SLOT_TRIGGERS. Bottom-up materialise of a type child of a
class field / method skipped the synthetic TSTypeAnnotation
wrapper, landing parent on PropertyDefinition / MethodDefinition
directly.
2. TypePredicate not in TYPE_SLOT_TRIGGERS. `function f(x): x is T`
has a nested TSTypeAnnotation around the inner type; without the
trigger, bottom-up of T landed parent on TSTypePredicate without
the inner wrapper.
3. AssignmentPatternNode (parameter default value) didn't re-parent
its inner binding. `function f(x = 1)` — the bottom-up Identifier
x reported parent.type === 'FunctionDeclaration' instead of
'AssignmentPattern'. Same fix pattern as
BindingAssignmentPatternNode (which was already correct).
4. NamedExports / TemplateSpan missing from SKIP_AS_PARENT. ESTree
flattens both — the wrappers have no ESTree counterpart — but the
walker built them as GenericTSNode, producing 'TSNamedExports' /
'TSTemplateSpan' parent types.
5. MappedType TypeParameter scaffolding. `type X = { [K in keyof T]: ... }`
— typescript-estree exposes K bare on TSMappedType.key, but lazy
built a TSTypeParameter wrapper from SHAPES dispatch when the
walker climbed through ts.TypeParameter. Skip TypeParameter as
parent when its TS parent is MappedType.
6. ImportType argument LiteralType. `import('foo')` — eager exposes
the bare StringLiteral as TSImportType.argument; lazy wrapped it
in TSLiteralType. Skip the wrapper in SKIP_AS_PARENT when the TS
parent is ImportType, plus flatten the top-down argument getter
to skip the same wrapper. Drill TSTypeQuery.exprName for the
typeof-import case.
Three documented divergences carry forward as accept-skips in the
sweep — each is a known scaffolding choice or missing wrapper that
the rule corpus doesn't observe:
- ChainExpression scaffolding (lazy single outer wrapper vs eager
per-link)
- TSInterfaceHeritage missing (interface extends Y wraps Y in eager;
lazy emits the bare Identifier)
- TSAssertClause missing (import-assertion wraps entries in eager;
lazy emits ImportAttribute children directly)
The skip filter is structural: when a known wrapper is missing on
either side, the comparison is skipped at parent AND grandparent
levels (otherwise the off-by-one ripples). Re-investigating these
gaps later is straightforward — adding the wrapper class +
removing the skip entry.
Tested: predicate-coverage, lazy-estree, scope-compat, selector-
analysis, ts-ast-scan, compat-pipeline, jsx-react-x — all pass.
Bench/dogfood: 0 divergences across 30 files × 107 rules. Dify cold
4.9-5.8s on this branch vs 5.1-5.5s on master — within noise.
6 tasks
Owner
Author
|
Superseded by #95 — squashed and consolidated. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extends the bottom-up parity sweep from the 15-fixture set to the dogfood corpus — every production .ts file in the monorepo, ~65k type asserts and ~64.7k parent asserts. The broader walk surfaced six real drift bugs that the architectural gates (SyntheticLazyNode, KnownEstreeType, navigation tables) couldn't catch on their own; all six are fixed here.
Drift surface caught + fixed
class X { y: T[] }— type child of PropertyDeclaration / MethodDeclaration / GetAccessor missed TSTypeAnnotation wrapperTYPE_SLOT_TRIGGERSfunction f(x): x is T— TypePredicate nested TSTypeAnnotation wasn't materialised on bottom-up walkfunction f(x = 1)— parameter binding insideAssignmentPatternreportedparent.type === 'FunctionDeclaration'AssignmentPatternNodeconstructor (same asBindingAssignmentPatternNode)export { … }/\${x}`— bottom-up walker builtTSNamedExports/TSTemplateSpan` GenericTSNode wrappersSKIP_AS_PARENTtype X = { [K in keyof T]: … }— bottom-up wrapped K inTSTypeParameterfrom SHAPES dispatch; eager exposes it bare onTSMappedType.keyimport('foo')/typeof import('foo')— TSLiteralType wrapper between StringLiteral and TSImportType / TSTypeQueryTSTypeQuery.exprNameDocumented divergences that remain
Three known scaffolding gaps surface but the rule corpus doesn't query them — the sweep filter accepts them with structural reasoning (when a wrapper is missing on one side, parent AND grandparent comparisons are off-by-one and skipped together):
interface X extends Ywraps Y in eager; lazy emits bare Identifierimport x from 'y' assert {…}wraps entries in eager; lazy emits ImportAttribute children directlyAdding either wrapper class is mechanical —
extends SyntheticLazyNode+ nav-table entry + remove the corresponding accept-skip line. The sweep continues to flag any additional gaps as the architecture evolves.Test plan
predicate-coverage(152/152, 16 ignored)lazy-estree.test: 15-fixture parity sweep (169 type / 154 parent asserts) + dogfood sweep (65k type / 64.7k parent asserts) + factory tests + phantom-types invariant — all passscope-compat(24/24 clean),selector-analysis,ts-ast-scan,compat-pipeline,jsx-react-xdogfood.js— 30 files × 107 rules, 0 divergences, 0 crashes