Oxc linker rejects parenthesized resolveMetadata return in deferred class metadata
還沒有人認領這個 Issue。
評估
- 難度
- 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 形式。完成的判定標準是兩種等價的 callback 形式都能透過預設的 Oxc linker 成功連結。
由索引模型根據 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
- 平均合併
- 17 小時 25 分鐘
- 30 天內合併 PR
- 183
貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 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 個 reaction ·
-
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
-
blocklist removal
難度 2/5 1-3 小時 新手友好度 65/100
MetaMask/eth-phishing-detect#296544 ·
-
難度 2/5 1-3 小時 新手友好度 70/100
pastelsky/bundlephobia#1122 ·
-
難度 2/5 1-3 小時 新手友好度 70/100
-
category/development priority/P2 scope/file-operations scope/testing type/enhancement
難度 2/5 1-3 小時 新手友好度 75/100
-
難度 2/5 1-3 小時 新手友好度 75/100