Oxc linker rejects parenthesized resolveMetadata return in deferred class metadata
まだ誰も着手していません。
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 76/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- angular, typescript
- 領域
- build-system, tooling
調査の方向性
npm run build で最小再現を実行し、npm run build:babel と比較します。OxcAstHost.parseReturnValue() と PartialClassMetadataAsyncLinkerVersion1.linkPartialDeclaration から調査を開始し、fixture/index.mjs を使って、括弧で囲まれた簡潔な arrow body と、動作する block-body 形式を比較します。デフォルトの Oxc linker で、同等の callback 形式の両方が正常にリンクされれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Command
build
Description
With @angular/build@22.2.0-rc.0, the default Oxc linker fails to process a partial ɵɵngDeclareClassMetadataAsync declaration whose resolveMetadata callback returns a parenthesized object literal. The same input builds successfully with NG_BUILD_BABEL_LINKER=1.
The fixture below is hand-reduced from Angular 22.1.7 output for a library component containing @defer; it removes the original application's dependencies and UI. It exercises the real ng build pipeline, not a mock linker.
Is this a regression?
The original library artifact passes our stable Angular 20/21/22 CI matrix and fails the 22.2.0-rc.0 canary. I have not bisected the first affected version using this reduced reproduction.
Minimal Reproduction
Create an empty directory with the following files, then run:
npm install
npm run build
# Fails: Unsupported syntax, expected an object literal.
npm run build:babel
# Succeeds: same input, Babel linker.
The build cache is disabled in this reproduction.
Complete minimal project files
package.json
{
"name": "angular-oxc-deferred-metadata-repro",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"build": "ng build",
"build:babel": "NG_BUILD_BABEL_LINKER=1 ng build"
},
"dependencies": {
"@angular/core": "22.2.0-rc.0",
"@angular/common": "22.2.0-rc.0",
"@angular/compiler": "22.2.0-rc.0",
"@angular/platform-browser": "22.2.0-rc.0",
"rxjs": "7.8.2",
"tslib": "2.8.1",
"deferred-metadata-fixture": "file:./fixture"
},
"devDependencies": {
"@angular/build": "22.2.0-rc.0",
"@angular/cli": "22.2.0-rc.0",
"@angular/compiler-cli": "22.2.0-rc.0",
"typescript": "6.0.3"
}
}
angular.json
{
"version": 1,
"cli": {
"cache": {
"enabled": false
},
"analytics": false
},
"projects": {
"repro": {
"projectType": "application",
"root": "",
"architect": {
"build": {
"builder": "@angular/build:application",
"options": {
"browser": "src/main.ts",
"tsConfig": "tsconfig.json",
"index": "src/index.html",
"outputPath": "dist",
"optimization": false
}
}
}
}
}
}
tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "preserve",
"moduleResolution": "bundler",
"experimentalDecorators": true,
"skipLibCheck": true,
"strict": true,
"lib": [
"ES2022",
"DOM"
]
},
"files": [
"src/main.ts"
]
}
src/main.ts
import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { DeferredFixture } from 'deferred-metadata-fixture';
@Component({ selector: 'app-root', template: 'Linker reproduction' })
class App {
constructor() { console.log(DeferredFixture); }
}
bootstrapApplication(App).catch(console.error);
src/index.html
<!doctype html><html><head><title>Reproduction</title><base href="/"></head><body><app-root></app-root></body></html>
fixture/package.json
{
"name": "deferred-metadata-fixture",
"version": "1.0.0",
"type": "module",
"main": "index.mjs",
"types": "index.d.ts"
}
fixture/index.mjs
import * as i0 from '@angular/core';
export class DeferredFixture {}
// Reduced from Angular 22.1.7 output for a component containing @defer.
// The parenthesized object returned by resolveMetadata triggers the failure.
i0.ɵɵngDeclareClassMetadataAsync({
minVersion: '18.0.0',
version: '22.1.7',
ngImport: i0,
type: DeferredFixture,
resolveDeferredDeps: () => [],
resolveMetadata: () => ({
decorators: [],
ctorParameters: null,
propDecorators: null,
}),
});
fixture/index.d.ts
export declare class DeferredFixture {}
Additional control: in fixture/index.mjs, replace resolveMetadata: () => ({ ... }) with the equivalent resolveMetadata: () => { return { ... }; }. Running npm run build then succeeds with the default Oxc linker. This was verified locally, in addition to the Babel comparison.
Expected: both equivalent callback forms link successfully with the default builder.
Actual: only the parenthesized expression form fails.
Exception or Error
Unsupported syntax, expected an object literal. [plugin angular-compiler]
at OxcAstHost.parseObjectLiteral (.../oxc-ast-host.js:95:19)
at _AstObject.parse
at _AstValue.getObject
at PartialClassMetadataAsyncLinkerVersion1.linkPartialDeclaration
at FileLinker.linkPartialDeclaration
at OxcLinker.linkCallExpression
Your Environment
Angular CLI: 22.2.0-rc.0
Angular: 22.2.0-rc.0
@angular/build: 22.2.0-rc.0
@angular/compiler-cli: 22.2.0-rc.0
TypeScript: 6.0.3
Node.js: 26.5.0
npm: 11.17.0
OS: darwin arm64
The original failure also occurs on Ubuntu CI with Node 24.17.0.
Anything else relevant?
The parser represents the concise arrow body as ParenthesizedExpression(ObjectExpression). OxcAstHost.parseReturnValue() returns the body unchanged; the subsequent object-literal check only accepts ObjectExpression. Unwrapping the parenthesized return expression before interpreting the metadata appears to be the required fix.
Related PR #33769 addresses parentheses when emitting JavaScript, whereas this failure occurs when reading the callback's return value.
- 主要言語
- TypeScript
- スター
- 27k
- フォーク
- 11.8k
- 平均マージ
- 16時間 21分
- マージ済み PR(30日)
- 170
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
angular/angular-cli のほかの issue
-
area: @angular/build gemini-triaged
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
angular/angular-cli#33955 ·
-
area: @angular/cli gemini-triaged
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
angular/angular-cli#33055 · コメント 1 件 · リアクション 3 件 ·
-
angular/build:library area: @angular/build gemini-triaged
angular/angular-cli#34131 · 担当者 1 名 ·
-
angular/build:library area: @angular/build gemini-triaged
angular/angular-cli#34130 · 担当者 1 名 ·
-
angular/build:library area: @angular/build gemini-triaged
angular/angular-cli#34128 · 担当者 1 名 ·
angular/angular-cli の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 91/100
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
難易度 1/5 1時間未満 初心者へのやさしさ 95/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
Automattic/studio#4908 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 90/100
-
help wanted
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
hemilabs/ui-monorepo#2332 ·