|
| 1 | +import { describe, it, expect } from 'vitest' |
| 2 | + |
| 3 | +import { linkAngularPackageSync } from '../index.js' |
| 4 | + |
| 5 | +/** |
| 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. |
| 9 | + */ |
| 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 | + }); |
| 33 | +} |
| 34 | +
|
| 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 | +} |
| 94 | +
|
| 95 | +export { AsyncPipe }; |
| 96 | +` |
| 97 | + |
| 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 | + ) |
| 104 | + |
| 105 | + expect(result.linked).toBe(true) |
| 106 | + expect(result.code).not.toContain('\u0275\u0275ngDeclare') |
| 107 | + }) |
| 108 | + |
| 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 | + ) |
| 114 | + |
| 115 | + expect(result.linked).toBe(true) |
| 116 | + expect(result.code).not.toContain('\u0275\u0275ngDeclare') |
| 117 | + }) |
| 118 | + |
| 119 | + it('should link \u0275\u0275ngDeclarePipe', () => { |
| 120 | + const result = linkAngularPackageSync( |
| 121 | + PIPE_CHUNK, |
| 122 | + 'node_modules/@angular/common/fesm2022/_pipes-chunk.mjs', |
| 123 | + ) |
| 124 | + |
| 125 | + expect(result.linked).toBe(true) |
| 126 | + expect(result.code).not.toContain('\u0275\u0275ngDeclare') |
| 127 | + }) |
| 128 | + |
| 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', |
| 136 | + ) |
| 137 | + |
| 138 | + expect(result.linked).toBe(false) |
| 139 | + }) |
| 140 | +}) |
| 141 | + |
| 142 | +describe('NODE_MODULES_JS_REGEX filter matching', () => { |
| 143 | + // This is the fixed regex from angular-linker-plugin.ts |
| 144 | + const NODE_MODULES_JS_REGEX = /node_modules[\\/].*\.[cm]?js(?:\?.*)?$/ |
| 145 | + |
| 146 | + it('should match standard Angular FESM files', () => { |
| 147 | + expect(NODE_MODULES_JS_REGEX.test('node_modules/@angular/common/fesm2022/common.mjs')).toBe( |
| 148 | + true, |
| 149 | + ) |
| 150 | + }) |
| 151 | + |
| 152 | + it('should match chunk files', () => { |
| 153 | + expect( |
| 154 | + NODE_MODULES_JS_REGEX.test( |
| 155 | + 'node_modules/@angular/common/fesm2022/_platform_location-chunk.mjs', |
| 156 | + ), |
| 157 | + ).toBe(true) |
| 158 | + }) |
| 159 | + |
| 160 | + it('should match absolute paths', () => { |
| 161 | + expect( |
| 162 | + NODE_MODULES_JS_REGEX.test( |
| 163 | + '/Users/dev/project/node_modules/@angular/common/fesm2022/_platform_location-chunk.mjs', |
| 164 | + ), |
| 165 | + ).toBe(true) |
| 166 | + }) |
| 167 | + |
| 168 | + it('should match paths with Vite query strings', () => { |
| 169 | + expect( |
| 170 | + NODE_MODULES_JS_REGEX.test('node_modules/@angular/common/fesm2022/common.mjs?v=abc123'), |
| 171 | + ).toBe(true) |
| 172 | + }) |
| 173 | + |
| 174 | + it('should match chunk files with Vite query strings', () => { |
| 175 | + expect( |
| 176 | + NODE_MODULES_JS_REGEX.test( |
| 177 | + 'node_modules/@angular/common/fesm2022/_platform_location-chunk.mjs?v=df7b0864', |
| 178 | + ), |
| 179 | + ).toBe(true) |
| 180 | + }) |
| 181 | + |
| 182 | + it('should match Windows-style backslash paths', () => { |
| 183 | + expect(NODE_MODULES_JS_REGEX.test('node_modules\\@angular\\common\\fesm2022\\common.mjs')).toBe( |
| 184 | + true, |
| 185 | + ) |
| 186 | + }) |
| 187 | + |
| 188 | + it('should match .js and .cjs files', () => { |
| 189 | + expect(NODE_MODULES_JS_REGEX.test('node_modules/@ngrx/store/fesm2022/ngrx-store.js')).toBe(true) |
| 190 | + expect(NODE_MODULES_JS_REGEX.test('node_modules/some-lib/index.cjs')).toBe(true) |
| 191 | + }) |
| 192 | + |
| 193 | + it('should not match non-JS files', () => { |
| 194 | + expect(NODE_MODULES_JS_REGEX.test('node_modules/@angular/common/fesm2022/common.d.ts')).toBe( |
| 195 | + false, |
| 196 | + ) |
| 197 | + expect(NODE_MODULES_JS_REGEX.test('src/app/app.component.ts')).toBe(false) |
| 198 | + }) |
| 199 | +}) |
0 commit comments