Skip to content

js_interop_gen: many fixes moving towards supporting large, complex D.TS files#549

Merged
kevmoo merged 49 commits into
mainfrom
just_the_work
May 28, 2026
Merged

js_interop_gen: many fixes moving towards supporting large, complex D.TS files#549
kevmoo merged 49 commits into
mainfrom
just_the_work

Conversation

@kevmoo

@kevmoo kevmoo commented May 13, 2026

Copy link
Copy Markdown
Member
  • fix: resolve namespace flattening type resolution mismatch in js_interop_gen
  • fix(js_interop_gen): traverse generic type arguments in ReferredType dependency resolver
  • refactor(js_interop_gen): eliminate GlobalOptions mutable state in favor of options propagation
  • refactor(js_interop_gen): decompose transformer.dart by extracting DependencyWalker
  • refactor(js_interop_gen): decompose transformer.dart by extracting NamespaceFlattener
  • fix(js_interop_gen): prevent self-import and prefixing when importUrl matches file
  • fix(js_interop_gen): deduplicate collected generic parameters by name in unions
  • fix(js_interop_gen): distinguish generic builtins by type arguments and cast distinct union array getters
  • fix(js_interop_gen): map void generic type arguments to JSAny to conform to JSAny? bounds
  • feat(js_interop_gen): support string-literal module declarations
  • feat(js_interop_gen): prevent infinite recursion crashes on mutually recursive types
  • feat(js_interop_gen): support generic type parameter resolution inside module namespaces
  • feat(js_interop_gen): resolve enum member type references to parent EnumDeclaration
  • feat(js_interop_gen): add formatter try-catch recovery and document next steps
  • feat(js_interop_gen): resolve literal union casts and refactor AST Node type safety
  • chore: move type resolver into its own file
  • feat: cache transformed AST nodes to resolve mismatched unique-suffix references
  • fix: deduplicate types in union/intersection declarations to resolve duplicate definition errors
  • fix: resolve unchecked use of nullable value errors for JSAny and void in union getters
  • fix: uniquely identify generic type references in dependency walking to prevent missing generic unions
  • fix: pad generic type arguments in ReferredType emit to match declaration bounds count
  • fix: prevent parent nullability leaking into generic type arguments during referred type emit
  • fix: always emit Deprecated annotation with a default message argument
  • fix: dynamically resolve and enforce non-JSObject representation types for interfaces
  • fix: resolve all static analysis lints and line-length limits in lib/
  • fix: automatically detect and redeclare conflicting inherited members inside intersection types
  • fix: cast generic ReferredTypes using intermediate JSAny cast in union getters
  • test: replace global Object inheritance with custom Parent interface in representation type test to avoid TS warning
  • fix: support object literal types in intersection member conflict resolution
  • fix: recursively unwrap and walk inside type parameters of BuiltinTypes inside DependencyWalker
  • fix: pass typeArg: true when resolving type parameters of referred BuiltinTypes and PackageWebTypes
  • fix: propagate typeArg and parameter flags recursively inside UnionType and IntersectionType transformations
  • fix: dynamically propagate and resolve specific type parameter bounds constraints inside ReferredType and getGenericTypes
  • feat: add lines_longer_than_80_chars ignore rule to all generated interop files
  • fix: escape JS properties/methods starting with _ to public Dart names starting with $

kevmoo added 30 commits May 8, 2026 20:13
…rop_gen

- Introduce a static lookup map `declarationToEmittedName` in `ReferredType` to map every parsed AST `Declaration` to its final merged/unique declaration name assigned by the namer.
- Populate the lookup map in `processAndReturn()` within `transformer.dart` during the merging/rescoping phase.
- Consult the lookup map in `ReferredType.emit()` to emit the correct final/unique names for type references, resolving name conflicts and flattening resolution mismatches.
- Add a comprehensive integration test `vscode_flattening` verifying that Namespaced/Flattened Type Reference Resolution compiles with zero static errors.
- Clean up minor formatting in `analysis_options.yaml` and wrap code to comply with standard 80-character limits and unused cast warnings.
…de type safety

- Fix invalid runtime casts in union getters for literal types (e.g., true, string, int, double) by correctly looking up their JS alternatives and generating safe .toDart / .toDartInt / .toDartDouble conversions.
- Resolve mixed union LCA (Lowest Common Ancestor) resolution to properly widen to JSAny by correcting _getSharedPrimitiveTypeIfAny to fall through to the full topological sorting pass.
- Refactor Node in base.dart to be generic (Node<T>) to enforce compile-time type safety for AST emit() return types.
- Update ConstructorDeclaration to implement Node<Constructor> and update merger generic helper methods to T extends Node.
- Expand integration test suite (boolean_literal_union) to comprehensively cover literal type conversion.
# Conflicts:
#	js_interop_gen/lib/src/ast/documentation.dart
…in representation type test to avoid TS warning

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request refactors the js_interop_gen tool to improve type resolution, namespace handling, and code generation consistency. It replaces global configuration with a scoped Options system and introduces modular components like TypeResolver, NamespaceFlattener, and DependencyWalker. Enhancements include signature-based member deduplication during interface merging, improved handling of generic type constraints, and better support for union types and deprecated annotations. Review feedback suggests enhancing type safety by avoiding dynamic member access in NamedDeclaration, reducing global state in ReferredType, and simplifying redundant type checks in union getter logic.

Comment thread js_interop_gen/lib/src/ast/base.dart Outdated
Comment thread js_interop_gen/lib/src/ast/types.dart Outdated
Comment thread js_interop_gen/lib/src/ast/types.dart Outdated

@nikeokoronkwo nikeokoronkwo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is awesome. Thank you!

A few general notes:

  • I noticed a lot of conflict resolution handling (i.e. deduping) in your code: technically we should not need to do most of that, either because at the point in the codebase it should be handled, or the TypeScript compiler should not allow such code to be generated or successfully pass through the parser anyways. We are not expecting people to write these .d.ts files so we should expect correct inputs.

cc @srujzs if you have the time to.

Comment thread js_interop_gen/lib/src/ast/base.dart Outdated
Comment thread js_interop_gen/lib/src/interop_gen/transform/dependency_walker.dart Outdated
Comment thread js_interop_gen/lib/src/ast/types.dart
Comment thread js_interop_gen/lib/src/ast/types.dart Outdated
Comment thread js_interop_gen/lib/src/ast/declarations.dart
Comment thread js_interop_gen/lib/src/ast/types.dart
Comment thread js_interop_gen/lib/src/ast/base.dart Outdated
Comment thread js_interop_gen/test/integration/vscode_test_notes.md Outdated
@kevmoo

kevmoo commented May 16, 2026

Copy link
Copy Markdown
Member Author

@nikeokoronkwo PTAL 😄

@nikeokoronkwo nikeokoronkwo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Some more things...


Another issue is I ran this:

export interface SharedItem {
    value: number;
}

export declare namespace API {
    interface Container {
        item: SharedItem;
    }
}

// Re-export the same symbol that was referenced inside the namespace.
export { SharedItem as ReshapedItem };

And the generator did not expose SharedItem but instead only ReshapedItem (due to the export statement) and the API namespace.

Comment thread js_interop_gen/lib/src/ast/types.dart
Comment thread js_interop_gen/lib/src/ast/types.dart Outdated
Comment thread js_interop_gen/lib/src/ast/types.dart
Comment thread js_interop_gen/lib/src/ast/helpers.dart
kevmoo added 2 commits May 26, 2026 19:11
- Map aliased re-exports to type alias (typedef Alias = Original) instead of mutating AST declarations in place.

- Copy and propagate custom @js annotations to conflicting dynamic getters/setters in intersections.

- Resolve property member conflicts in intersections (primitives simplify to bottom type never/JSAny).

- Map TS generic default type parameter values to padding fallbacks using default$.

- Fix ReferredDeclarationType constructor nullability runtime exceptions under web targets.

- Format and wrap comments to conform to 80-character line limits, resolving analyze warnings.

- Update and expand integration test suites for generic padding, intersections, and re-export aliases.
@kevmoo

kevmoo commented May 27, 2026

Copy link
Copy Markdown
Member Author

take another look!

Comment thread js_interop_gen/test/integration/interop_gen/project/output/a.dart
Comment thread js_interop_gen/lib/src/ast/builtin.dart
Comment thread js_interop_gen/lib/src/interop_gen/transform/dependency_walker.dart
@nikeokoronkwo

Copy link
Copy Markdown
Collaborator

Can gemini review one last time?

@kevmoo

kevmoo commented May 27, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request refactors the js_interop_gen package by replacing global configuration options with instance-based options, improving type resolution, and introducing helper classes such as DependencyWalker, NamespaceFlattener, and TypeResolver to handle namespace flattening and dependency resolution. The review feedback highlights several critical issues and improvement opportunities: ensuring GenericType.id uses a stable identifier to prevent duplicate member definitions during interface merging, replacing an unsafe .reduce call with .fold in TypeResolver to avoid runtime StateErrors on empty iterables, removing a redundant cache check, and adding an explicit null check for the nullable symbol parameter in getTypeFromSymbol to prevent potential runtime null pointer exceptions.

Comment thread js_interop_gen/lib/src/ast/types.dart
Comment thread js_interop_gen/lib/src/interop_gen/transform/type_resolver.dart Outdated
Comment thread js_interop_gen/lib/src/interop_gen/transform/type_resolver.dart Outdated
Comment thread js_interop_gen/lib/src/interop_gen/transform/type_resolver.dart
Comment thread js_interop_gen/test/integration/interop_gen/functions_input.d.ts Outdated
kevmoo added 4 commits May 27, 2026 15:43
- Enhance GenericType.id stability by using parent qualifiedName (or name) instead of namer-suffixed parent.id. This guarantees identical IDs for the same type parameters across separate declarations of a merged generic interface, resolving signature-based member deduplication failures.

- Protect the type resolver against StateError on empty declarations maps by replacing the unsafe .reduce iterable call with a robust, high-performance .expand().toList() flattener.

- Remove redundant manual transformedCache lookups before calling transformAndReturn (which already checks the cache internally).

- Prevent NullThrownError during symbol resolution by inserting a descriptive null-safety diagnostic check at the start of getTypeFromSymbol, enabling static type promotion of the symbol.
Add integration test case under `generic_interface_merge_input.d.ts` and its generated expected output `generic_interface_merge_expected.dart` to verify that overlapping generic property declarations inside merged generic interfaces are successfully and robustly deduplicated under `GenericType.id` name-invariant lookup mapping.
…xample

Relocate the ErrorReporter test case interface containing a never-returning method to `interfaces_input.d.ts` (and its expected golden `interfaces_expected.dart`) from `functions_input.d.ts`. This addresses Nike's nit by keeping the functions test suite strictly focused on top-level function declarations, moving interface mappings to their dedicated test file.
@kevmoo kevmoo merged commit a0d3ad1 into main May 28, 2026
26 checks passed
@kevmoo kevmoo deleted the just_the_work branch May 28, 2026 18:31
@kevmoo

kevmoo commented May 28, 2026

Copy link
Copy Markdown
Member Author

Thank you @nikeokoronkwo !

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.

2 participants