Skip to content

Tracking: evaluate decorator metadata values imported from other files #518

Description

@Brooooooklyn

OXC compiles one file at a time. ngtsc has the whole program, so its static evaluator follows an import into the other file and reads the value. OXC can't do that. Since #493 (fix/decorator-metadata-inputs-outputs) and #495 (feat/decorator-metadata-queries), OXC reports a clear error in these cases. Main silently emits wrong metadata.

Error: @Directive.inputs depends on 'INPUTS', which is imported from another module. OXC compiles one file at a time and cannot evaluate values from other files.

This issue tracks the gap and possible ways to close it.

Affected forms (other.ts exports a plain const)

Source ngtsc 22.1.7 OXC #504 tip OXC main
@Directive({inputs: INPUTS}), INPUTS = ['a'] inputs: { a: "a" } error input dropped (no inputs)
@Directive({inputs: [NAME]}), NAME = 'a' inputs: { a: "a" } error input dropped
@Directive({outputs: OUTPUTS}), OUTPUTS = ['o: oo'] outputs: { o: "oo" } error output dropped
@Input(OPTS) a, OPTS = {alias: 'b', required: true} inputs: { a: [0, "b", "a"] } ("required": true in .d.ts) error inputs:{a:"a"} (alias and required ignored)
@Input({alias: ALIAS}) a, ALIAS = 'b' inputs: { a: [0, "b", "a"] } error inputs:{a:"a"}
@Output(ONAME) o, ONAME = 'oo' outputs: { o: "oo" } error outputs:{o:"o"}
@ViewChild('a', {static: STATIC}), STATIC = true ɵɵviewQuery(_c0, 7) error ɵɵviewQuery(_c0,5) (not static)
@Input({transform: T}), T a function in other.ts .d.ts: ngAcceptInputType_a: string ngAcceptInputType_a: unknown unknown
@ViewChild(SEL), SEL = 'a' ɵɵviewQuery(_c0, 5), _c0 = ["a"] ɵɵviewQuery(SEL,5) same as tip

The last row works at runtime (ɵɵviewQuery accepts a string predicate), so only the shape differs.

These are not gaps, because ngtsc rejects them too and the tip matches it:

  • @ViewChild('a', QOPTS) → NG1001: @ViewChild options must be an object literal
  • queries: Q → NG1010: Decorator queries metadata must be an object literal
  • input(0, {alias: ALIAS}) → NG1010: Alias needs to be a string that is statically analyzable. (OXC misses this one; it's in the diagnostics issue)

Example:

// test.ts
import {Directive} from '@angular/core';
import {INPUTS} from './other';
@Directive({selector: '[d]', inputs: INPUTS})
export class D { a: any; }

// other.ts
export const INPUTS = ['a'];

Where

  • The error comes from crates/oxc_angular_compiler/src/directive/decorator.rs (~L706). The static evaluator is directive/evaluator.rs. Both are in the stack.

Possible approaches (not decided)

  1. Resolver hook from the Vite plugin. transformAngularFile takes a callback, or a precomputed map, that returns the value of an imported binding (specifier + exportName). The plugin resolves with Vite's resolver and reads the file. There is already a similar input, TransformOptions::resolved_imports (identifier → path), which only rewrites import paths today.
  2. Reuse component/cross_file_elision.rs. Behind the cross_file_elision feature (off by default, "intended for compare test purposes only") it already resolves imports with oxc_resolver (tsconfig paths included), parses the target with oxc_parser, and walks re-exports. It could be extended to evaluate exported const initializers and feed the result to the evaluator.
  3. Leave it as is. Keep the error and document the workaround: inline the value, or declare it in the same file.

For 1 and 2: the importing file has to be re-transformed when the other file changes. TransformResult::dependencies exists today for template and style files, and the Vite plugin links some of them to this.addWatchFile. A dependency on another file's value would need the same kind of wiring. Cycles, re-exports, export *, values that are not literals, and .d.ts-only packages need a defined fallback (keep today's error).

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions