Repository navigation
fix(partial): give NgModule components their scope (#655) - #665
Brooooooklyn wants to merge 6 commits into
Conversation
A partial declaration of a component an NgModule declares had no dependencies, so after linking it had no directives or pipes. The NgModule's file now calls ɵɵsetComponentScope for each component it declares, with the module's compilation scope read across files (source @NgModule decorators and .d.ts ɵmod types). A standalone component that imports an NgModule now lists the module's exported directives and pipes. Partial declarations also carry a real version (the target Angular version, else 22.2.3) instead of 0.0.0-PLACEHOLDER, which Angular's published linker reads as 0.0.0 and so turns off block syntax. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Set component scopes at the end of the module's file with `() => [...]` lists, and skip a component whose file imports the module's file back. - A standalone component lists a class an imported NgModule exports once, by declaration, not by name. - Look up each `(file, name)` once per export search, so `export *` cycles end in linear time. - Import a workspace library class by path when its entry point doesn't export it. - Emit `isStandalone: true` for a linker before v19, which reads a missing field as `false`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…orts - Skip a component when the file its scope call imports it from loads the module file back, not only the file that declares it. - Follow `export * as ns from`, and not type-only imports and re-exports, when looking for a cycle. - List a module's classes as seen only once its list is kept: a module with a pipe of no static name no longer hides them from later ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dbda06f3ae
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
A class an imported NgModule exports that the file declares after the standalone component is listed as `forwardRef(() => X)`, as ngtsc does, so creating the component's definition doesn't read it too early. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. What shall we delve into next? Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
…dows `canonicalize` gives the compiled file a `\\?\` path, which the resolver's paths don't have, so an import cycle back to it was never found. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1d47680ba9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- A class an imported NgModule exports, whose file loads the standalone component's file back, is listed as `forwardRef(() => i1.X)`: the component's definition can be created before that file has run. - Name a class imported by path from an `.mts`/`.cts` file by the `.mjs` /`.cjs` file TypeScript writes for it. - Compare canonical paths when looking for a cycle: a path through a tsconfig alias can be spelled differently, as Windows short names are. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Delightful! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Closes #655.
Problem
In partial mode, a component declared by an NgModule had no
dependencies. ngtsc fills them from the module's scope, which needs the whole program. The Angular CLI's linker also emits library NgModules without their scope. So at runtime the component could not find any directive or pipe (<div d>not matched,| p→ NG0302).Fix
NgModule file (only with
compilationMode: 'partial'+resolveImportedValues): cross-file analysis reads the scope statically, followingexport *barrels,constlists,forwardRef,X.forRoot()(ModuleWithProviders<T>or the returned{ ngModule }),.d.tspackages (ɵmod/ɵdir/ɵcmp/ɵpipetype args).The module then emits
ɵɵsetComponentScopefor each component it declares.Standalone component: an NgModule in
importsadds the directives and pipes it exports todependencies. Each class is listed once.Safe fallbacks: if anything can't be read (unknown value, call, cycle), the output stays the same as before.
Names: classes are imported the way ngtsc picks them:
Also fixed here: the
versionfieldDeclarations wrote
version: "0.0.0-PLACEHOLDER", which Angular's linker reads as 0.0.0:@if/@forfailed to link,Now
versionis the Angular version compiled for (angularVersion), or 22.2.3. For a version before 19,isStandalone: trueis written out, because older linkers default it tofalse.Verification
tests/partial_ng_module_scope_test.rs(21).partial-ng-module-scope-runtime.test.ts: it links with Angular's babel linker and with ours, then checksdirectiveDefs/pipeDefson the real@angular/core(12 tests).RouterModule.forRoot(),export *barrels, standaloneimports, and the review repros (import cycles,export *cycles).cross_file_elision), napi tests, conformance 1264/1264.Not in this PR (already on main)
a?.b→null), even for version ≥ 22. Angular's v22 linker givesundefined.declarationsstraight intoɵɵdefineNgModule. In a module ↔ component import cycle this throwsCannot access 'App' before initialization. Angular's linker leaves them out.🤖 Generated with Claude Code