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
- 平均合并
- 16 小时 21 分钟
- 30 天内合并 PR
- 170
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
angular/angular-cli 的其他 Issue
-
area: @angular/cli gemini-triaged
难度 2/5 1-3 小时 新手友好度 84/100
angular/angular-cli#34057 ·
-
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/angular-cli 的全部 Issue
相似的 Issue
-
bug
难度 2/5 1-3 小时 新手友好度 72/100
-
难度 1/5 1 小时以内 新手友好度 85/100
-
check:passed streams:add
难度 2/5 1-3 小时 新手友好度 68/100
-
难度 2/5 1-3 小时 新手友好度 76/100
-
难度 2/5 1-3 小时 新手友好度 68/100