1- import { readFileSync } from 'node:fs'
2- import { resolve } from 'node:path'
31import { describe , it , expect } from 'vitest'
42
53import { linkAngularPackageSync } from '../index.js'
64
75/**
8- * Resolve the path to an Angular 21 package file.
9- * The e2e app has Angular 21.2.2 installed with chunk files.
6+ * Minimal Angular partial declaration fixtures that simulate the structure
7+ * of FESM bundle files (including Angular 21+ chunk files).
8+ * Uses actual Unicode ɵ (U+0275) characters as they appear in real Angular packages.
109 */
11- function resolveAngular21File ( subpath : string ) : string {
12- return resolve ( __dirname , '../e2e/app/node_modules/@angular' , subpath )
10+ const INJECTABLE_CHUNK = `
11+ import * as i0 from '@angular/core';
12+
13+ class PlatformLocation {
14+ historyGo(relativePosition) {
15+ throw new Error('Not implemented');
16+ }
17+ static \u0275fac = i0.\u0275\u0275ngDeclareFactory({
18+ minVersion: "12.0.0",
19+ version: "21.0.0",
20+ ngImport: i0,
21+ type: PlatformLocation,
22+ deps: [],
23+ target: i0.\u0275\u0275FactoryTarget.Injectable
24+ });
25+ static \u0275prov = i0.\u0275\u0275ngDeclareInjectable({
26+ minVersion: "12.0.0",
27+ version: "21.0.0",
28+ ngImport: i0,
29+ type: PlatformLocation,
30+ providedIn: "platform",
31+ useClass: undefined
32+ });
1333}
1434
15- describe ( 'Angular linker - chunk file support' , ( ) => {
16- it ( 'should link ɵɵngDeclare calls in _platform_location-chunk.mjs' , ( ) => {
17- const filepath = resolveAngular21File ( 'common/fesm2022/_platform_location-chunk.mjs' )
18- const code = readFileSync ( filepath , 'utf8' )
35+ export { PlatformLocation };
36+ `
37+
38+ const NG_MODULE_CHUNK = `
39+ import * as i0 from '@angular/core';
40+
41+ class CommonModule {
42+ static \u0275fac = i0.\u0275\u0275ngDeclareFactory({
43+ minVersion: "12.0.0",
44+ version: "21.0.0",
45+ ngImport: i0,
46+ type: CommonModule,
47+ deps: [],
48+ target: i0.\u0275\u0275FactoryTarget.NgModule
49+ });
50+ static \u0275mod = i0.\u0275\u0275ngDeclareNgModule({
51+ minVersion: "14.0.0",
52+ version: "21.0.0",
53+ ngImport: i0,
54+ type: CommonModule,
55+ imports: [],
56+ exports: []
57+ });
58+ static \u0275inj = i0.\u0275\u0275ngDeclareInjector({
59+ minVersion: "12.0.0",
60+ version: "21.0.0",
61+ ngImport: i0,
62+ type: CommonModule
63+ });
64+ }
65+
66+ export { CommonModule };
67+ `
68+
69+ const PIPE_CHUNK = `
70+ import * as i0 from '@angular/core';
71+
72+ class AsyncPipe {
73+ constructor(ref) {
74+ this._ref = ref;
75+ }
76+ static \u0275fac = i0.\u0275\u0275ngDeclareFactory({
77+ minVersion: "12.0.0",
78+ version: "21.0.0",
79+ ngImport: i0,
80+ type: AsyncPipe,
81+ deps: [{ token: i0.ChangeDetectorRef }],
82+ target: i0.\u0275\u0275FactoryTarget.Pipe
83+ });
84+ static \u0275pipe = i0.\u0275\u0275ngDeclarePipe({
85+ minVersion: "14.0.0",
86+ version: "21.0.0",
87+ ngImport: i0,
88+ type: AsyncPipe,
89+ isStandalone: false,
90+ name: "async",
91+ pure: false
92+ });
93+ }
1994
20- // Verify the chunk file has unlinked declarations
21- expect ( code ) . toContain ( '\u0275\u0275ngDeclare' )
95+ export { AsyncPipe };
96+ `
2297
23- const result = linkAngularPackageSync ( code , filepath )
98+ describe ( 'Angular linker - chunk file linking' , ( ) => {
99+ it ( 'should link \u0275\u0275ngDeclareFactory and \u0275\u0275ngDeclareInjectable' , ( ) => {
100+ const result = linkAngularPackageSync (
101+ INJECTABLE_CHUNK ,
102+ 'node_modules/@angular/common/fesm2022/_platform_location-chunk.mjs' ,
103+ )
24104
25105 expect ( result . linked ) . toBe ( true )
26106 expect ( result . code ) . not . toContain ( '\u0275\u0275ngDeclare' )
27107 } )
28108
29- it ( 'should link ɵɵngDeclare calls in _location-chunk.mjs' , ( ) => {
30- const filepath = resolveAngular21File ( 'common/fesm2022/_location-chunk.mjs' )
31- const code = readFileSync ( filepath , 'utf8' )
32-
33- // Verify the chunk file has unlinked declarations
34- expect ( code ) . toContain ( '\u0275\u0275ngDeclare' )
35-
36- const result = linkAngularPackageSync ( code , filepath )
109+ it ( 'should link \u0275\u0275ngDeclareNgModule and \u0275\u0275ngDeclareInjector' , ( ) => {
110+ const result = linkAngularPackageSync (
111+ NG_MODULE_CHUNK ,
112+ 'node_modules/@angular/common/fesm2022/_common_module-chunk.mjs' ,
113+ )
37114
38115 expect ( result . linked ) . toBe ( true )
39116 expect ( result . code ) . not . toContain ( '\u0275\u0275ngDeclare' )
40117 } )
41118
42- it ( 'should link ɵɵngDeclare calls in _common_module-chunk.mjs' , ( ) => {
43- const filepath = resolveAngular21File ( 'common/fesm2022/_common_module-chunk.mjs' )
44- const code = readFileSync ( filepath , 'utf8' )
45-
46- // Verify the chunk file has unlinked declarations
47- expect ( code ) . toContain ( '\u0275\u0275ngDeclare' )
48-
49- const result = linkAngularPackageSync ( code , filepath )
119+ it ( 'should link \u0275\u0275ngDeclarePipe' , ( ) => {
120+ const result = linkAngularPackageSync (
121+ PIPE_CHUNK ,
122+ 'node_modules/@angular/common/fesm2022/_pipes-chunk.mjs' ,
123+ )
50124
51125 expect ( result . linked ) . toBe ( true )
52126 expect ( result . code ) . not . toContain ( '\u0275\u0275ngDeclare' )
53127 } )
54128
55- it ( 'should link all Angular 21 chunk files in @angular/common' , ( ) => {
56- const { readdirSync } = require ( 'node:fs' )
57- const dir = resolveAngular21File ( 'common/fesm2022' )
58- const files = readdirSync ( dir ) as string [ ]
59- const chunkFiles = files . filter (
60- ( f : string ) => f . startsWith ( '_' ) && f . endsWith ( '-chunk.mjs' ) ,
129+ it ( 'should return linked: false for files without declarations' , ( ) => {
130+ const code = `
131+ export function helper() { return 42; }
132+ `
133+ const result = linkAngularPackageSync (
134+ code ,
135+ 'node_modules/@angular/common/fesm2022/_utils-chunk.mjs' ,
61136 )
62137
63- expect ( chunkFiles . length ) . toBeGreaterThan ( 0 )
64-
65- for ( const chunkFile of chunkFiles ) {
66- const filepath = resolve ( dir , chunkFile )
67- const code = readFileSync ( filepath , 'utf8' )
68-
69- if ( ! code . includes ( '\u0275\u0275ngDeclare' ) ) {
70- continue // Skip chunks without declarations
71- }
72-
73- const result = linkAngularPackageSync ( code , filepath )
74-
75- expect ( result . linked , `${ chunkFile } should be linked` ) . toBe ( true )
76- expect (
77- result . code . includes ( '\u0275\u0275ngDeclare' ) ,
78- `${ chunkFile } should not contain unlinked declarations` ,
79- ) . toBe ( false )
80- }
138+ expect ( result . linked ) . toBe ( false )
81139 } )
82140} )
83141
@@ -91,7 +149,7 @@ describe('NODE_MODULES_JS_REGEX filter matching', () => {
91149 ) . toBe ( true )
92150 } )
93151
94- it ( 'should match Angular 21 chunk files' , ( ) => {
152+ it ( 'should match chunk files' , ( ) => {
95153 expect (
96154 NODE_MODULES_JS_REGEX . test (
97155 'node_modules/@angular/common/fesm2022/_platform_location-chunk.mjs' ,
0 commit comments