Skip to content

Dynamic host attribute values are rejected (and two local-compilation-only transform cases) #627

Open

Description

@edbzn

Summary

Three Angular ngtsc specs compile with ngtsc but get a compile error from oxc, so a Vite build fails. Found by running Angular v22.0.0's ngtsc emit specs against oxc main (04cb3b2). Only case 1 is a bug in oxc. Cases 2 and 3 compile only in ngtsc's local compilation mode. That mode skips these checks because a separate full build checks them, and oxc already matches the full-mode diagnostics on purpose (#494).

1. Dynamic host attribute value (bug)

ngtsc_spec.ts: "should accept dynamic host attribute bindings"

// other.d.ts
export declare const foo: any;
// test.ts
import {Component} from '@angular/core';
import {foo} from './other';

const test = foo.bar();

@Component({selector: 'test', template: '', host: {'test': test}})
export class TestCmp {}

Actual

@Component.host depends on 'foo', which is imported from another module. OXC compiles one file at a time and cannot evaluate values from other files.

The error is the same with and without resolveImportedValues. A same-file dynamic value (host: {role: make()}) is also rejected: ... could not be determined statically. OXC does not support dynamic host attribute values.

Expected (ngc)

hostAttrs: ["test", test]

Cause

evaluateHostExpressionBindings (annotations/directive/src/shared.ts) turns a DynamicValue into new WrappedNodeExpr(value.node). parseHostBindings then emits it as is for a plain attribute, and rejects it only for [prop], (event), class and style. oxc stores host attribute values as strings, so it has no way to emit an expression.

2. Input transform from a namespace import (not a bug)

local_compilation_spec.ts: "should generate input info for transform function imported externally using namespace"

import * as n from './some_where';
// ...
@Input({transform: n.externalFunc}) x: string = '';

Actual: Input transform function could not be referenced Value is a reference to 'externalFunc'. Local mode emits inputs: { x: [2, "x", "x", n.externalFunc] }.

3. Inline transform with an untyped parameter (not a bug)

local_compilation_spec.ts: "should not check inline function param type"

@Input({transform: v => v + 'TRANSFORMED!'}) x: string = '';

Actual: Input transform function first parameter must have a type Value could not be determined statically. Local mode emits inputs: { x: [2, "x", "x", v => v + 'TRANSFORMED!'] }.

Why 2 and 3 are not bugs

parseDecoratorInputTransformFunction skips every transform check when compilationMode === LOCAL, "because usually the type check is done in a separate build which runs in full compilation mode". In full mode, which is what ng build uses, ngtsc reports both errors:

  • case 3 matches ngtsc_spec.ts "should produce a diangostic if the transform function first parameter has no arguments" (transform: (val) => 1);
  • for case 2, a namespace member has no identity in the file (getIdentityIn returns null), and feat(directive): validate input transforms like ngtsc #494 checked this against ngtsc 22.1.7 (namespace_imported_transform_cannot_be_referenced).

oxc is the only compiler in a Vite build, so no other build would check these. Dropping the checks would let code through that ng build rejects. I left both cases as they are.

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

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions