From 2e0f48e3ff40289725d3590fa8e1fc059fbaeb88 Mon Sep 17 00:00:00 2001 From: rk Date: Sat, 10 Oct 2026 19:06:37 +0500 Subject: [PATCH 01/52] fix(@angular/cli): keep ng version working when the package manager is not installed `getVersion()` throws when configured package manager is missing, so `ng version` crashed insted of printing `` Version is left undefined now, same as analytics in command-module.ts --- .../cli/src/commands/version/version-info.ts | 9 ++- .../src/commands/version/version-info_spec.ts | 64 +++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 packages/angular/cli/src/commands/version/version-info_spec.ts diff --git a/packages/angular/cli/src/commands/version/version-info.ts b/packages/angular/cli/src/commands/version/version-info.ts index 128cc8ef5449..9709567e382b 100644 --- a/packages/angular/cli/src/commands/version/version-info.ts +++ b/packages/angular/cli/src/commands/version/version-info.ts @@ -104,6 +104,13 @@ export async function gatherVersionInfo(context: CommandContext): Promise { + let tempRoot: string; + + beforeEach(async () => { + const baseTmpDir = process.env['TEST_TMPDIR']; + assert(baseTmpDir, 'TEST_TMPDIR is not set'); + tempRoot = await mkdtemp(join(baseTmpDir, 'angular-cli-version-info-test-')); + }); + + afterEach(async () => { + await rm(tempRoot, { recursive: true, force: true }); + }); + + function createContext(packageManager: PackageManager): CommandContext { + return { root: tempRoot, packageManager } as unknown as CommandContext; + } + + it('should report the package manager version when it is available', async () => { + const packageManager = new PackageManager( + new MockHost(), + tempRoot, + SUPPORTED_PACKAGE_MANAGERS['npm'], + { version: '10.9.0' }, + ); + + const info = await gatherVersionInfo(createContext(packageManager)); + + expect(info.system.packageManager).toEqual({ name: 'npm', version: '10.9.0' }); + }); + + it('should not fail when the package manager is not installed', async () => { + const packageManager = new PackageManager( + new MockHost(), + tempRoot, + SUPPORTED_PACKAGE_MANAGERS['bun'], + { + initializationError: new Error( + `The project is configured to use 'bun', but it is not installed.`, + ), + }, + ); + + const info = await gatherVersionInfo(createContext(packageManager)); + + expect(info.system.packageManager).toEqual({ name: 'bun', version: undefined }); + }); +}); From 5c656152ef91e2731155f6027a845d8014b53e4f Mon Sep 17 00:00:00 2001 From: rk Date: Sat, 10 Oct 2026 18:53:58 +0500 Subject: [PATCH 02/52] fix(@angular/cli): accept multi-digit array indices in ng config multi-digit index like `styles[10]` stayed string, so get failed and set threw now any run of digits is parsed as array idnex --- .../angular/cli/src/commands/config/cli.ts | 5 +-- .../cli/src/commands/config/cli_spec.ts | 37 +++++++++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 packages/angular/cli/src/commands/config/cli_spec.ts diff --git a/packages/angular/cli/src/commands/config/cli.ts b/packages/angular/cli/src/commands/config/cli.ts index ae25f3839e22..ef7cfd95d5a5 100644 --- a/packages/angular/cli/src/commands/config/cli.ts +++ b/packages/angular/cli/src/commands/config/cli.ts @@ -133,9 +133,8 @@ export default class ConfigCommandModule * ["a", 3, "foo", "bar", 2]. * @param path The JSON string to parse. * @returns {(string|number)[]} The fragments for the string. - * @private */ -function parseJsonPath(path: string): (string | number)[] { +export function parseJsonPath(path: string): (string | number)[] { const fragments = (path || '').split(/\./g); const result: (string | number)[] = []; @@ -155,7 +154,7 @@ function parseJsonPath(path: string): (string | number)[] { const indices = match[2] .slice(1, -1) .split('][') - .map((x) => (/^\d$/.test(x) ? +x : x.replace(/"|'/g, ''))); + .map((x) => (/^\d+$/.test(x) ? +x : x.replace(/"|'/g, ''))); result.push(...indices); } } diff --git a/packages/angular/cli/src/commands/config/cli_spec.ts b/packages/angular/cli/src/commands/config/cli_spec.ts new file mode 100644 index 000000000000..dd8fe4790e16 --- /dev/null +++ b/packages/angular/cli/src/commands/config/cli_spec.ts @@ -0,0 +1,37 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { parseJsonPath } from './cli'; + +describe('parseJsonPath', () => { + it('should parse single digit array indices', () => { + expect(parseJsonPath('a[3].foo.bar[2]')).toEqual(['a', 3, 'foo', 'bar', 2]); + }); + + it('should parse multi digit array indices', () => { + expect(parseJsonPath('projects.app.architect.build.options.styles[10]')).toEqual([ + 'projects', + 'app', + 'architect', + 'build', + 'options', + 'styles', + 10, + ]); + expect(parseJsonPath('a[2][13].b')).toEqual(['a', 2, 13, 'b']); + }); + + it('should keep quoted keys as strings', () => { + expect(parseJsonPath('projects["test-project"].root')).toEqual([ + 'projects', + 'test-project', + 'root', + ]); + expect(parseJsonPath(`a['10']`)).toEqual(['a', '10']); + }); +}); From 445cc767e62b72631dd53c0c5324b458fee76608 Mon Sep 17 00:00:00 2001 From: rk Date: Sat, 10 Oct 2026 18:54:01 +0500 Subject: [PATCH 03/52] fix(@schematics/angular): keep the workspace build version in the use-application-builder migration migration added `@angular/build` at version of CLI running it, so `ng update --name` on older workspace pulled newest major now it reuses `@angular-devkit/build-angular` specifer and leaves existing `@angular/build` alone Fixes #30696 --- .../use-application-builder/migration.ts | 9 +++- .../use-application-builder/migration_spec.ts | 42 +++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/packages/schematics/angular/migrations/use-application-builder/migration.ts b/packages/schematics/angular/migrations/use-application-builder/migration.ts index b481c4f30034..dcf0526a3945 100644 --- a/packages/schematics/angular/migrations/use-application-builder/migration.ts +++ b/packages/schematics/angular/migrations/use-application-builder/migration.ts @@ -19,6 +19,7 @@ import { DependencyType, ExistingBehavior, addDependency, + getDependency, removeDependency, } from '../../utility/dependency'; import { JSONFile } from '../../utility/json-file'; @@ -270,10 +271,14 @@ function updateProjects(tree: Tree, context: SchematicContext) { } // Add direct @angular/build dependencies and remove @angular-devkit/build-angular + // Keep the workspace version since this migration can run from a newer temporary CLI + const buildAngularVersion = + getDependency(tree, '@angular-devkit/build-angular')?.version ?? + latestVersions.AngularBuild; rules.push( - addDependency('@angular/build', latestVersions.DevkitBuildAngular, { + addDependency('@angular/build', buildAngularVersion, { type: DependencyType.Dev, - existing: ExistingBehavior.Replace, + existing: ExistingBehavior.Skip, }), removeDependency('@angular-devkit/build-angular'), ); diff --git a/packages/schematics/angular/migrations/use-application-builder/migration_spec.ts b/packages/schematics/angular/migrations/use-application-builder/migration_spec.ts index fd10352c6eac..05259962dc5d 100644 --- a/packages/schematics/angular/migrations/use-application-builder/migration_spec.ts +++ b/packages/schematics/angular/migrations/use-application-builder/migration_spec.ts @@ -9,6 +9,7 @@ import { JsonObject } from '@angular-devkit/core'; import { EmptyTree } from '@angular-devkit/schematics'; import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; +import { latestVersions } from '../../utility/latest-versions'; import { Builders, ProjectType, WorkspaceSchema } from '../../utility/workspace-models'; function createWorkSpaceConfig(tree: UnitTestTree) { @@ -450,6 +451,47 @@ describe(`Migration to use the application builder`, () => { expect(devDependencies['postcss']).toBeUndefined(); }); + describe('"@angular/build" version', () => { + async function migrateWith( + manifest: object, + ): Promise<{ devDependencies: Record }> { + tree.overwrite('/package.json', JSON.stringify(manifest)); + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + + return JSON.parse(newTree.readContent('/package.json')); + } + + it('should follow the "@angular-devkit/build-angular" range of the workspace', async () => { + const { devDependencies } = await migrateWith({ + devDependencies: { '@angular-devkit/build-angular': '~19.1.4' }, + }); + + expect(devDependencies['@angular/build']).toBe('~19.1.4'); + }); + + it('should read "@angular-devkit/build-angular" from "dependencies" as well', async () => { + const { devDependencies } = await migrateWith({ + dependencies: { '@angular-devkit/build-angular': '18.2.1' }, + }); + + expect(devDependencies['@angular/build']).toBe('18.2.1'); + }); + + it('should keep an "@angular/build" that is already installed', async () => { + const { devDependencies } = await migrateWith({ + devDependencies: { '@angular-devkit/build-angular': '^19.2.0', '@angular/build': '19.0.3' }, + }); + + expect(devDependencies['@angular/build']).toBe('19.0.3'); + }); + + it('should fall back to the latest "@angular/build" without "@angular-devkit/build-angular"', async () => { + const { devDependencies } = await migrateWith({}); + + expect(devDependencies['@angular/build']).toBe(latestVersions.AngularBuild); + }); + }); + it('it should not add esModuleInterop and moduleResolution when module is preserve', async () => { tree.overwrite( 'tsconfig.json', From 13923047f64b6e1063f7f07029c70295b5c99d69 Mon Sep 17 00:00:00 2001 From: rk Date: Sat, 10 Oct 2026 19:16:57 +0500 Subject: [PATCH 04/52] fix(@angular/build): always use AOT when extracting i18n messages with `aot: false` on build target, extraction built app in JIT and template messages never got into extracted file webpack extraction alredy forced AOT, application extraction now does same --- .../builders/extract-i18n/application-extraction.ts | 1 + .../builders/extract-i18n/application-extraction.ts | 1 + tests/e2e/tests/i18n/extract-ivy.ts | 11 ++++++++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/angular/build/src/builders/extract-i18n/application-extraction.ts b/packages/angular/build/src/builders/extract-i18n/application-extraction.ts index ff223ba0bd16..b18c8164481f 100644 --- a/packages/angular/build/src/builders/extract-i18n/application-extraction.ts +++ b/packages/angular/build/src/builders/extract-i18n/application-extraction.ts @@ -39,6 +39,7 @@ export async function extractMessages( await context.getTargetOptions(options.buildTarget), builderName, )) as unknown as ApplicationBuilderInternalOptions; + buildOptions.aot = true; buildOptions.optimization = false; buildOptions.sourceMap = { scripts: true, vendor: true, styles: false }; buildOptions.localize = false; diff --git a/packages/angular_devkit/build_angular/src/builders/extract-i18n/application-extraction.ts b/packages/angular_devkit/build_angular/src/builders/extract-i18n/application-extraction.ts index 8de8b6863aaf..68347fa0fb24 100644 --- a/packages/angular_devkit/build_angular/src/builders/extract-i18n/application-extraction.ts +++ b/packages/angular_devkit/build_angular/src/builders/extract-i18n/application-extraction.ts @@ -45,6 +45,7 @@ export async function extractMessages( ); } + buildOptions.aot = true; buildOptions.optimization = false; buildOptions.sourceMap = { scripts: true, vendor: true, styles: false }; buildOptions.localize = false; diff --git a/tests/e2e/tests/i18n/extract-ivy.ts b/tests/e2e/tests/i18n/extract-ivy.ts index 382051e83cce..cf0d23da08e3 100644 --- a/tests/e2e/tests/i18n/extract-ivy.ts +++ b/tests/e2e/tests/i18n/extract-ivy.ts @@ -1,8 +1,9 @@ import { join } from 'node:path'; import { getGlobalVariable } from '../../utils/env'; -import { expectFileToMatch, writeFile } from '../../utils/fs'; +import { deleteFile, expectFileToMatch, writeFile } from '../../utils/fs'; import { uninstallPackage } from '../../utils/packages'; import { ng } from '../../utils/process'; +import { updateJsonFile } from '../../utils/project'; import { expectToFail } from '../../utils/utils'; import { readNgVersion } from '../../utils/version'; @@ -52,5 +53,13 @@ export default async function () { await expectFileToMatch('messages.xlf', 'Hello world'); + // Template messages should also be extracted when the build target disables AOT + await updateJsonFile('angular.json', (workspaceJson) => { + workspaceJson.projects['test-project'].architect.build.options.aot = false; + }); + await deleteFile('messages.xlf'); + await ng('extract-i18n'); + await expectFileToMatch('messages.xlf', 'Hello world'); + await uninstallPackage('@angular/localize'); } From f2cd8c8cf7c5aa7e7076c87e9c0c55b3bf880f4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Sch=C3=A4ublin?= Date: Mon, 12 Oct 2026 10:08:49 +0200 Subject: [PATCH 05/52] fix(@angular/ssr): preserve query parameters on relative route redirects Route redirects are answered on the server from the route configuration, without running the router. For a relative `redirectTo`, the router keeps the query string of the current URL and ignores a query string in `redirectTo`, but the server did the opposite. It now does the same as the router. Absolute redirects are unchanged, as the router does not keep the query string of the current URL for them either. --- packages/angular/ssr/src/app.ts | 13 ++- packages/angular/ssr/src/routes/ng-routes.ts | 9 +- packages/angular/ssr/src/routes/route-tree.ts | 3 + packages/angular/ssr/test/app_spec.ts | 33 +++++++ .../angular/ssr/test/routes/ng-routes_spec.ts | 99 +++++++++++++++++-- .../angular/ssr/test/routes/router_spec.ts | 3 + 6 files changed, 146 insertions(+), 14 deletions(-) diff --git a/packages/angular/ssr/src/app.ts b/packages/angular/ssr/src/app.ts index 6c0202a8f9b3..517cf1e31727 100644 --- a/packages/angular/ssr/src/app.ts +++ b/packages/angular/ssr/src/app.ts @@ -163,14 +163,17 @@ export class AngularServerApp { return null; } - const { redirectTo, status, renderMode, headers } = matchedRoute; + const { redirectTo, relativeRedirect, status, renderMode, headers } = matchedRoute; if (redirectTo !== undefined) { + const location = joinUrlParts( + request.headers.get('X-Forwarded-Prefix') ?? '', + buildPathWithParams(redirectTo, url.pathname), + ); + + // Match Angular router behavior: relative redirects keep the query string. return createRedirectResponse( - joinUrlParts( - request.headers.get('X-Forwarded-Prefix') ?? '', - buildPathWithParams(redirectTo, url.pathname), - ), + relativeRedirect ? location + url.search : location, status, headers, ); diff --git a/packages/angular/ssr/src/routes/ng-routes.ts b/packages/angular/ssr/src/routes/ng-routes.ts index ac83aae8cd4f..63313b875d34 100644 --- a/packages/angular/ssr/src/routes/ng-routes.ts +++ b/packages/angular/ssr/src/routes/ng-routes.ts @@ -192,6 +192,7 @@ async function* handleRoute(options: { yield { ...metadata, redirectTo: resolveRedirectTo(metadata.route, redirectTo), + relativeRedirect: redirectTo[0] !== '/' ? true : undefined, }; } else { yield metadata; @@ -421,6 +422,7 @@ async function* handleSSGRoute( if (redirectTo !== undefined) { meta.redirectTo = resolveRedirectTo(currentRoutePath, redirectTo); + meta.relativeRedirect = redirectTo[0] !== '/' ? true : undefined; } const isCatchAllRoute = CATCH_ALL_REGEXP.test(currentRoutePath); @@ -534,7 +536,8 @@ function handlePrerenderParamsReplacement( * * This function processes the `redirectTo` property to ensure that it correctly * resolves relative to the current route path. If `redirectTo` is an absolute path, - * it is returned as is. If it is a relative path, it is resolved based on the current route path. + * it is returned as is. If it is a relative path, it is resolved based on the current route path, + * and, like in the Angular router, its query and fragment are ignored. * * @param routePath - The current route path. * @param redirectTo - The target path for redirection. @@ -550,7 +553,9 @@ function resolveRedirectTo(routePath: string, redirectTo: string): string { const segments = routePath.replace(URL_PARAMETER_GLOBAL_REGEXP, '*').split('/'); segments.pop(); // Remove the last segment to make it relative. - return joinUrlParts(...segments, redirectTo); + const [path] = redirectTo.split(/[?#]/, 1); + + return joinUrlParts(...segments, path); } /** diff --git a/packages/angular/ssr/src/routes/route-tree.ts b/packages/angular/ssr/src/routes/route-tree.ts index ff689a3c90f5..253783a5f13c 100644 --- a/packages/angular/ssr/src/routes/route-tree.ts +++ b/packages/angular/ssr/src/routes/route-tree.ts @@ -31,6 +31,9 @@ export interface RouteTreeNodeMetadata { */ redirectTo?: string; + /** Indicates if `redirectTo` was defined as a relative path. */ + relativeRedirect?: boolean; + /** * The route path for this node. * diff --git a/packages/angular/ssr/test/app_spec.ts b/packages/angular/ssr/test/app_spec.ts index b317f99f1d3a..91e847f0bf80 100644 --- a/packages/angular/ssr/test/app_spec.ts +++ b/packages/angular/ssr/test/app_spec.ts @@ -88,6 +88,7 @@ describe('AngularServerApp', () => { { path: 'redirect/relative', redirectTo: 'home' }, { path: 'redirect/:param/relative', redirectTo: 'home' }, { path: 'redirect/absolute', redirectTo: '/home' }, + { path: 'redirect-with-query', redirectTo: 'home?param=value' }, { path: 'redirect-to-function', redirectTo: () => 'home', @@ -222,6 +223,28 @@ describe('AngularServerApp', () => { expect(response?.status).toBe(302); }); + it('should preserve query parameters on relative redirects', async () => { + const response = await app.handle(new Request('http://localhost/redirect?filter=test')); + expect(response?.headers.get('location')).toBe('/home?filter=test'); + expect(response?.status).toBe(302); + }); + + it('should ignore query parameters of relative redirect targets', async () => { + const response = await app.handle( + new Request('http://localhost/redirect-with-query?filter=test'), + ); + expect(response?.headers.get('location')).toBe('/home?filter=test'); + expect(response?.status).toBe(302); + }); + + it('should not preserve query parameters on absolute redirects', async () => { + const response = await app.handle( + new Request('http://localhost/redirect/absolute?filter=test'), + ); + expect(response?.headers.get('location')).toBe('/home'); + expect(response?.status).toBe(302); + }); + it('should handle request abortion gracefully', async () => { const controller = new AbortController(); const request = new Request('http://localhost/home', { signal: controller.signal }); @@ -498,6 +521,16 @@ describe('AngularServerApp', () => { expect(response?.headers.get('location')).toBe('/base/home'); expect(response?.status).toBe(302); }); + + it('returns a 302 status and keeps the query string for relative redirects', async () => { + const response = await app.handle( + new Request('http://localhost/redirect?filter=test', { + headers, + }), + ); + expect(response?.headers.get('location')).toBe('/base/home?filter=test'); + expect(response?.status).toBe(302); + }); }); describe('Critical CSS inlining', () => { diff --git a/packages/angular/ssr/test/routes/ng-routes_spec.ts b/packages/angular/ssr/test/routes/ng-routes_spec.ts index e214c31eab71..f26d6fb4913c 100644 --- a/packages/angular/ssr/test/routes/ng-routes_spec.ts +++ b/packages/angular/ssr/test/routes/ng-routes_spec.ts @@ -51,7 +51,13 @@ describe('extractRoutesAndCreateRouteTree', () => { expect(routeTree.toObject()).toEqual([ { route: '/', renderMode: RenderMode.Server }, { route: '/home', renderMode: RenderMode.Client }, - { route: '/redirect', renderMode: RenderMode.Server, status: 301, redirectTo: '/home' }, + { + route: '/redirect', + renderMode: RenderMode.Server, + status: 301, + redirectTo: '/home', + relativeRedirect: true, + }, { route: '/user/*', renderMode: RenderMode.Server }, ]); }); @@ -371,10 +377,25 @@ describe('extractRoutesAndCreateRouteTree', () => { expect(errors).toHaveSize(0); expect(routeTree.toObject()).toEqual([ - { route: '/', renderMode: RenderMode.Prerender, redirectTo: '/some' }, - { route: '/some', renderMode: RenderMode.Prerender, redirectTo: '/some/thing' }, + { + route: '/', + renderMode: RenderMode.Prerender, + redirectTo: '/some', + relativeRedirect: true, + }, + { + route: '/some', + renderMode: RenderMode.Prerender, + redirectTo: '/some/thing', + relativeRedirect: true, + }, { route: '/some/thing', renderMode: RenderMode.Prerender }, - { redirectTo: '/*/thing', route: '/*', renderMode: RenderMode.Server }, + { + redirectTo: '/*/thing', + relativeRedirect: true, + route: '/*', + renderMode: RenderMode.Server, + }, { route: '/*/thing', renderMode: RenderMode.Server }, ]); }); @@ -496,8 +517,13 @@ describe('extractRoutesAndCreateRouteTree', () => { const { routeTree, errors } = await extractRoutesAndCreateRouteTree({ url }); expect(errors).toHaveSize(0); expect(routeTree.toObject()).toEqual([ - { route: '/', renderMode: RenderMode.Server, redirectTo: '/some' }, - { route: '/*', renderMode: RenderMode.Server, redirectTo: '/*/thing' }, + { route: '/', renderMode: RenderMode.Server, redirectTo: '/some', relativeRedirect: true }, + { + route: '/*', + renderMode: RenderMode.Server, + redirectTo: '/*/thing', + relativeRedirect: true, + }, { route: '/*/thing', renderMode: RenderMode.Server }, ]); }); @@ -526,11 +552,70 @@ describe('extractRoutesAndCreateRouteTree', () => { const { routeTree, errors } = await extractRoutesAndCreateRouteTree({ url }); expect(errors).toHaveSize(0); expect(routeTree.toObject()).toEqual([ - { route: '/*/*', renderMode: RenderMode.Server, redirectTo: '/*/*/thing' }, + { + route: '/*/*', + renderMode: RenderMode.Server, + redirectTo: '/*/*/thing', + relativeRedirect: true, + }, { route: '/*/*/thing', renderMode: RenderMode.Server }, ]); }); + it('should not mark absolute redirects as relative', async () => { + setAngularAppTestingManifest( + [ + { path: 'server', redirectTo: '/home' }, + { path: 'prerender', redirectTo: '/home' }, + { path: 'home', component: DummyComponent }, + ], + [ + { path: 'prerender', renderMode: RenderMode.Prerender }, + { path: '**', renderMode: RenderMode.Server }, + ], + ); + + const { routeTree, errors } = await extractRoutesAndCreateRouteTree({ url }); + expect(errors).toHaveSize(0); + expect(routeTree.toObject()).toEqual([ + { route: '/server', renderMode: RenderMode.Server, redirectTo: '/home' }, + { route: '/prerender', renderMode: RenderMode.Prerender, redirectTo: '/home' }, + { route: '/home', renderMode: RenderMode.Server }, + ]); + }); + + it('should ignore the query and fragment of relative redirect targets', async () => { + setAngularAppTestingManifest( + [ + { path: 'server', redirectTo: 'home?param=value#fragment' }, + { path: 'prerender', redirectTo: 'home?param=value#fragment' }, + { path: 'home', component: DummyComponent }, + ], + [ + { path: 'prerender', renderMode: RenderMode.Prerender }, + { path: '**', renderMode: RenderMode.Server }, + ], + ); + + const { routeTree, errors } = await extractRoutesAndCreateRouteTree({ url }); + expect(errors).toHaveSize(0); + expect(routeTree.toObject()).toEqual([ + { + route: '/server', + renderMode: RenderMode.Server, + redirectTo: '/home', + relativeRedirect: true, + }, + { + route: '/prerender', + renderMode: RenderMode.Prerender, + redirectTo: '/home', + relativeRedirect: true, + }, + { route: '/home', renderMode: RenderMode.Server }, + ]); + }); + it('should not resolve parameterized routes for SSG when `invokeGetPrerenderParams` is false', async () => { setAngularAppTestingManifest( [ diff --git a/packages/angular/ssr/test/routes/router_spec.ts b/packages/angular/ssr/test/routes/router_spec.ts index 380bc659549a..95006eda5f5b 100644 --- a/packages/angular/ssr/test/routes/router_spec.ts +++ b/packages/angular/ssr/test/routes/router_spec.ts @@ -55,6 +55,7 @@ describe('ServerRouter', () => { }); expect(router.match(new URL('http://localhost/redirect'))).toEqual({ redirectTo: '/home', + relativeRedirect: true, route: '/redirect', renderMode: RenderMode.Server, status: 301, @@ -89,6 +90,7 @@ describe('ServerRouter', () => { }); expect(redirectMetadata).toEqual({ redirectTo: '/home', + relativeRedirect: true, route: '/redirect', status: 301, renderMode: RenderMode.Server, @@ -110,6 +112,7 @@ describe('ServerRouter', () => { }); expect(redirectMetadata).toEqual({ redirectTo: '/home', + relativeRedirect: true, route: '/redirect', status: 301, renderMode: RenderMode.Server, From b3bbada1efd0d3a414cce8843b7284e9560f66fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Sch=C3=A4ublin?= Date: Mon, 12 Oct 2026 13:07:00 +0200 Subject: [PATCH 06/52] fix(@angular/ssr): resolve relative redirects against the parent route When a route's own path has several segments, such as `old/page`, only its last segment was replaced when resolving a relative `redirectTo` on the server. A redirect to `new/page` was therefore sent to `/old/new/page`, while the router navigates to `/new/page` because it replaces all segments matched by the route. The server now does the same. --- packages/angular/ssr/src/routes/ng-routes.ts | 29 +++-- packages/angular/ssr/test/app_spec.ts | 17 ++- .../angular/ssr/test/routes/ng-routes_spec.ts | 118 ++++++++++++++++++ 3 files changed, 147 insertions(+), 17 deletions(-) diff --git a/packages/angular/ssr/src/routes/ng-routes.ts b/packages/angular/ssr/src/routes/ng-routes.ts index 63313b875d34..915d7c2b9a47 100644 --- a/packages/angular/ssr/src/routes/ng-routes.ts +++ b/packages/angular/ssr/src/routes/ng-routes.ts @@ -146,6 +146,7 @@ type EntryPointToBrowserMapping = AngularAppManifest['entryPointToBrowserMapping async function* handleRoute(options: { metadata: ServerConfigRouteTreeNodeMetadata; currentRoutePath: string; + parentRoute: string; route: Route; compiler: Compiler; parentInjector: Injector; @@ -158,6 +159,7 @@ async function* handleRoute(options: { const { metadata, currentRoutePath, + parentRoute, route, compiler, parentInjector, @@ -176,6 +178,7 @@ async function* handleRoute(options: { yield* handleSSGRoute( serverConfigRouteTree, typeof redirectTo === 'string' ? redirectTo : undefined, + parentRoute, metadata, parentInjector, invokeGetPrerenderParams, @@ -191,7 +194,7 @@ async function* handleRoute(options: { } else if (typeof redirectTo === 'string') { yield { ...metadata, - redirectTo: resolveRedirectTo(metadata.route, redirectTo), + redirectTo: resolveRedirectTo(parentRoute, redirectTo), relativeRedirect: redirectTo[0] !== '/' ? true : undefined, }; } else { @@ -393,6 +396,7 @@ function appendPreloadToMetadata( * * @param serverConfigRouteTree - The tree representing the server's routing setup. * @param redirectTo - Optional path to redirect to, if specified. + * @param parentRoute - The path of the parent route. * @param metadata - The metadata associated with the route tree node. * @param parentInjector - The dependency injection container for the parent route. * @param invokeGetPrerenderParams - A flag indicating whether to invoke the `getPrerenderParams` function. @@ -402,6 +406,7 @@ function appendPreloadToMetadata( async function* handleSSGRoute( serverConfigRouteTree: RouteTree | undefined, redirectTo: string | undefined, + parentRoute: string, metadata: ServerConfigRouteTreeNodeMetadata, parentInjector: Injector, invokeGetPrerenderParams: boolean, @@ -421,7 +426,7 @@ async function* handleSSGRoute( } if (redirectTo !== undefined) { - meta.redirectTo = resolveRedirectTo(currentRoutePath, redirectTo); + meta.redirectTo = resolveRedirectTo(parentRoute, redirectTo); meta.relativeRedirect = redirectTo[0] !== '/' ? true : undefined; } @@ -480,7 +485,10 @@ async function* handleSSGRoute( redirectTo: redirectTo === undefined ? undefined - : resolveRedirectTo(routeWithResolvedParams, redirectTo), + : resolveRedirectTo( + parentRoute.replace(URL_PARAMETER_GLOBAL_REGEXP, replacer), + redirectTo, + ), }; } } catch (error) { @@ -535,27 +543,24 @@ function handlePrerenderParamsReplacement( * Resolves the `redirectTo` property for a given route. * * This function processes the `redirectTo` property to ensure that it correctly - * resolves relative to the current route path. If `redirectTo` is an absolute path, - * it is returned as is. If it is a relative path, it is resolved based on the current route path, + * resolves relative to the parent route path. If `redirectTo` is an absolute path, + * it is returned as is. If it is a relative path, it is resolved based on the parent route path, * and, like in the Angular router, its query and fragment are ignored. * - * @param routePath - The current route path. + * @param parentRoute - The path of the parent route. * @param redirectTo - The target path for redirection. * @returns The resolved redirect path as a string. */ -function resolveRedirectTo(routePath: string, redirectTo: string): string { +function resolveRedirectTo(parentRoute: string, redirectTo: string): string { if (redirectTo[0] === '/') { // If the redirectTo path is absolute, return it as is. return redirectTo; } - // Resolve relative redirectTo based on the current route path. - const segments = routePath.replace(URL_PARAMETER_GLOBAL_REGEXP, '*').split('/'); - segments.pop(); // Remove the last segment to make it relative. - + // Match Angular router behavior: replace all segments matched by the route. const [path] = redirectTo.split(/[?#]/, 1); - return joinUrlParts(...segments, path); + return joinUrlParts(parentRoute.replace(URL_PARAMETER_GLOBAL_REGEXP, '*'), path); } /** diff --git a/packages/angular/ssr/test/app_spec.ts b/packages/angular/ssr/test/app_spec.ts index 91e847f0bf80..8d8ee9add00b 100644 --- a/packages/angular/ssr/test/app_spec.ts +++ b/packages/angular/ssr/test/app_spec.ts @@ -89,6 +89,7 @@ describe('AngularServerApp', () => { { path: 'redirect/:param/relative', redirectTo: 'home' }, { path: 'redirect/absolute', redirectTo: '/home' }, { path: 'redirect-with-query', redirectTo: 'home?param=value' }, + { path: 'redirect-nested/:param', children: [{ path: 'old', redirectTo: 'new' }] }, { path: 'redirect-to-function', redirectTo: () => 'home', @@ -205,19 +206,25 @@ describe('AngularServerApp', () => { expect(response?.status).toBe(302); }); - it('should correctly handle relative nested redirects', async () => { + it('should correctly handle relative redirects on multi-segment routes', async () => { const response = await app.handle(new Request('http://localhost/redirect/relative')); - expect(response?.headers.get('location')).toBe('/redirect/home'); + expect(response?.headers.get('location')).toBe('/home'); expect(response?.status).toBe(302); }); - it('should correctly handle relative nested redirects with parameter', async () => { + it('should correctly handle relative redirects on multi-segment routes with parameter', async () => { const response = await app.handle(new Request('http://localhost/redirect/param/relative')); - expect(response?.headers.get('location')).toBe('/redirect/param/home'); + expect(response?.headers.get('location')).toBe('/home'); + expect(response?.status).toBe(302); + }); + + it('should correctly handle relative redirects of parameterized parent routes', async () => { + const response = await app.handle(new Request('http://localhost/redirect-nested/x/old')); + expect(response?.headers.get('location')).toBe('/redirect-nested/x/new'); expect(response?.status).toBe(302); }); - it('should correctly handle absolute nested redirects', async () => { + it('should correctly handle absolute redirects on multi-segment routes', async () => { const response = await app.handle(new Request('http://localhost/redirect/absolute')); expect(response?.headers.get('location')).toBe('/home'); expect(response?.status).toBe(302); diff --git a/packages/angular/ssr/test/routes/ng-routes_spec.ts b/packages/angular/ssr/test/routes/ng-routes_spec.ts index f26d6fb4913c..1af823f8f2ba 100644 --- a/packages/angular/ssr/test/routes/ng-routes_spec.ts +++ b/packages/angular/ssr/test/routes/ng-routes_spec.ts @@ -399,6 +399,96 @@ describe('extractRoutesAndCreateRouteTree', () => { { route: '/*/thing', renderMode: RenderMode.Server }, ]); }); + + it('should resolve multi-segment relative redirects of prerendered routes', async () => { + setAngularAppTestingManifest( + [ + { + path: ':param', + children: [ + { path: 'old/page', redirectTo: 'new/page' }, + { path: 'new/page', component: DummyComponent }, + ], + }, + ], + [ + { + path: ':param/old/page', + renderMode: RenderMode.Prerender, + async getPrerenderParams() { + return [{ param: 'some' }]; + }, + }, + { path: '**', renderMode: RenderMode.Server }, + ], + ); + + const { routeTree, errors } = await extractRoutesAndCreateRouteTree({ + url, + invokeGetPrerenderParams: true, + includePrerenderFallbackRoutes: true, + }); + + expect(errors).toHaveSize(0); + expect(routeTree.toObject()).toEqual([ + { route: '/*', renderMode: RenderMode.Server }, + { + route: '/*/old/page', + renderMode: RenderMode.Server, + redirectTo: '/*/new/page', + relativeRedirect: true, + }, + { route: '/*/new/page', renderMode: RenderMode.Server }, + { + route: '/some/old/page', + renderMode: RenderMode.Prerender, + redirectTo: '/some/new/page', + relativeRedirect: true, + }, + ]); + }); + + it('should resolve relative redirects of prerendered catch-all routes', async () => { + setAngularAppTestingManifest( + [ + { path: 'docs/**', redirectTo: 'new' }, + { path: 'new', component: DummyComponent }, + ], + [ + { + path: 'docs/**', + renderMode: RenderMode.Prerender, + async getPrerenderParams() { + return [{ '**': 'a/b' }]; + }, + }, + { path: '**', renderMode: RenderMode.Server }, + ], + ); + + const { routeTree, errors } = await extractRoutesAndCreateRouteTree({ + url, + invokeGetPrerenderParams: true, + includePrerenderFallbackRoutes: true, + }); + + expect(errors).toHaveSize(0); + expect(routeTree.toObject()).toEqual([ + { + route: '/docs/a/b', + renderMode: RenderMode.Prerender, + redirectTo: '/new', + relativeRedirect: true, + }, + { + route: '/docs/**', + renderMode: RenderMode.Server, + redirectTo: '/new', + relativeRedirect: true, + }, + { route: '/new', renderMode: RenderMode.Server }, + ]); + }); }); it('should extract routes with a route level matcher', async () => { @@ -562,6 +652,34 @@ describe('extractRoutesAndCreateRouteTree', () => { ]); }); + it('should resolve multi-segment relative redirects against the parent route', async () => { + setAngularAppTestingManifest( + [ + { + path: ':param', + children: [ + { path: 'old/page', redirectTo: 'new/page' }, + { path: 'new/page', component: DummyComponent }, + ], + }, + ], + [{ path: '**', renderMode: RenderMode.Server }], + ); + + const { routeTree, errors } = await extractRoutesAndCreateRouteTree({ url }); + expect(errors).toHaveSize(0); + expect(routeTree.toObject()).toEqual([ + { route: '/*', renderMode: RenderMode.Server }, + { + route: '/*/old/page', + renderMode: RenderMode.Server, + redirectTo: '/*/new/page', + relativeRedirect: true, + }, + { route: '/*/new/page', renderMode: RenderMode.Server }, + ]); + }); + it('should not mark absolute redirects as relative', async () => { setAngularAppTestingManifest( [ From f0a74e8f0ea04fd3f839be0120346067440b1350 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Mon, 12 Oct 2026 11:06:33 +0000 Subject: [PATCH 07/52] fix(@angular/build): disable Vitest fsModuleCache in unit-test builder Vitest 5.0.4 enabled `fsModuleCache` by default, which caches transformed modules on disk keyed by the raw source file content on disk before calling Vite's `load()` hook. Because `@angular/build:unit-test` pre-bundles test entry points and their imported application modules into memory, changes to imported application files do not change the on-disk `.spec.ts` file content, causing Vitest's `fsModuleCache` to serve stale cached bundles across test runs. --- .../build/src/builders/unit-test/runners/vitest/plugins.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts b/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts index 6be4c6e8ebe3..ec0cd0a8f269 100644 --- a/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts +++ b/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts @@ -271,6 +271,7 @@ export async function createVitestConfigPlugin( test: { name: projectName, include, + fsModuleCache: false, // CLI provider browser options override, if present ...(browser ? { browser } : {}), // Only override if the user explicitly set it via CLI @@ -290,6 +291,7 @@ export async function createVitestConfigPlugin( return { test: { + fsModuleCache: false, coverage: await generateCoverageOption( options.coverage, testConfig?.coverage, From ad4845583b8d1b8de26ccc0e45b4e6e58d95b362 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Mon, 12 Oct 2026 13:37:06 +0000 Subject: [PATCH 08/52] fix(@angular/build): respect tsconfig declarationMap and compilationMode in library builder Remove schema defaults for `declarationMap` and `compilationMode` in `@angular/build:library` and preserve `declarationMap` when reading TypeScript configuration for library builds so values configured in `tsconfig.lib.json` / `tsconfig.lib.prod.json` are respected unless explicitly overridden in `angular.json`. --- .../projects/lib/tsconfig.lib.json | 1 - .../build/src/builders/library/options.ts | 4 +- .../builders/library/pipeline/build-action.ts | 25 ++++++++-- .../src/builders/library/pipeline/bundler.ts | 4 +- .../builders/library/pipeline/compilation.ts | 10 +++- .../build/src/builders/library/schema.json | 6 +-- .../tests/options/compilation-mode_spec.ts | 48 +++++++++++++++++++ .../tests/options/declaration-map_spec.ts | 38 +++++++++++++++ .../build/src/builders/library/types.ts | 7 ++- .../compilation/angular-compilation.ts | 1 + .../angular/compilation/compiler-options.ts | 6 ++- .../angular/compilation/parallel-worker.ts | 1 + .../compilation/typescript-compilation.ts | 8 +++- 13 files changed, 141 insertions(+), 18 deletions(-) diff --git a/modules/testing/builder/projects/hello-world-lib/projects/lib/tsconfig.lib.json b/modules/testing/builder/projects/hello-world-lib/projects/lib/tsconfig.lib.json index fe12470400e2..23e851ac9c8b 100644 --- a/modules/testing/builder/projects/hello-world-lib/projects/lib/tsconfig.lib.json +++ b/modules/testing/builder/projects/hello-world-lib/projects/lib/tsconfig.lib.json @@ -2,7 +2,6 @@ "extends": "../../tsconfig.json", "compilerOptions": { "declaration": true, - "declarationMap": true, "inlineSources": true, "types": [] }, diff --git a/packages/angular/build/src/builders/library/options.ts b/packages/angular/build/src/builders/library/options.ts index 450dce36cab5..c90fd525e1f2 100644 --- a/packages/angular/build/src/builders/library/options.ts +++ b/packages/angular/build/src/builders/library/options.ts @@ -38,8 +38,8 @@ export async function normalizeLibraryOptions( assets: rawAssets, stylePreprocessorOptions, inlineStyleLanguage = 'css', - compilationMode = 'partial', - declarationMap = false, + compilationMode, + declarationMap, allowedNonPeerDependencies: rawAllowedNonPeerDependencies = [], keepLifecycleScripts = false, watch = false, diff --git a/packages/angular/build/src/builders/library/pipeline/build-action.ts b/packages/angular/build/src/builders/library/pipeline/build-action.ts index 19718a793deb..294eb954421b 100644 --- a/packages/angular/build/src/builders/library/pipeline/build-action.ts +++ b/packages/angular/build/src/builders/library/pipeline/build-action.ts @@ -124,6 +124,8 @@ export async function buildAction(actionContext: BuildActionContext): Promise; + + /** Effective declarationMap setting resolved from builder options and tsconfig. */ + readonly declarationMap: boolean; + + /** Effective compilationMode setting resolved from builder options and tsconfig. */ + readonly compilationMode: 'partial' | 'full'; } /** @@ -125,7 +131,7 @@ export async function compileLibrary( processWebWorker: () => '', }; - const { referencedFiles } = await compilationInstance.initialize( + const { referencedFiles, compilerOptions } = await compilationInstance.initialize( tsConfigPath, hostOptions, { @@ -220,6 +226,8 @@ export async function compileLibrary( failedFiles: failedFiles.size > 0 ? failedFiles : undefined, }, diagnosePromise, + declarationMap: !!compilerOptions.declarationMap, + compilationMode: compilerOptions.compilationMode === 'full' ? 'full' : 'partial', }; } catch (error) { if (!cached) { diff --git a/packages/angular/build/src/builders/library/schema.json b/packages/angular/build/src/builders/library/schema.json index bac9944091f6..ee34936bdd62 100644 --- a/packages/angular/build/src/builders/library/schema.json +++ b/packages/angular/build/src/builders/library/schema.json @@ -71,14 +71,12 @@ }, "declarationMap": { "type": "boolean", - "description": "Generates a sourcemap for each corresponding '.d.ts' file.", - "default": false + "description": "Generates a sourcemap for each corresponding '.d.ts' file." }, "compilationMode": { "type": "string", "description": "Angular compilation mode. Use 'partial' when publishing to npm (APF requirement). Use 'full' only during development or for private, internal monorepo packages that are never published.", - "enum": ["partial", "full"], - "default": "partial" + "enum": ["partial", "full"] }, "allowedNonPeerDependencies": { "description": "A list of package names allowed in the 'dependencies' and 'optionalDependencies' sections of package.json. Values can be regular expression patterns.", diff --git a/packages/angular/build/src/builders/library/tests/options/compilation-mode_spec.ts b/packages/angular/build/src/builders/library/tests/options/compilation-mode_spec.ts index cd794206960d..0efedef5708f 100644 --- a/packages/angular/build/src/builders/library/tests/options/compilation-mode_spec.ts +++ b/packages/angular/build/src/builders/library/tests/options/compilation-mode_spec.ts @@ -37,5 +37,53 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => const fesm = harness.readFile('dist/lib/fesm2022/lib.mjs'); expect(fesm).toContain('ɵɵdefineComponent'); }); + + it('should respect angularCompilerOptions.compilationMode from tsconfig when not set in builder options', async () => { + await harness.modifyFile('projects/lib/tsconfig.lib.json', (content) => { + const tsconfig = JSON.parse(content); + tsconfig.angularCompilerOptions = { + ...tsconfig.angularCompilerOptions, + compilationMode: 'full', + }; + + return JSON.stringify(tsconfig, null, 2); + }); + + harness.useTarget('build', { + ...BASE_OPTIONS, + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + + const fesm = harness.readFile('dist/lib/fesm2022/lib.mjs'); + expect(fesm).toContain('ɵɵdefineComponent'); + + const pkgJson = JSON.parse(harness.readFile('dist/lib/package.json')); + expect(pkgJson.scripts?.prepublishOnly).toContain('full compilation mode'); + }); + + it('should override angularCompilerOptions.compilationMode from tsconfig when set in builder options', async () => { + await harness.modifyFile('projects/lib/tsconfig.lib.json', (content) => { + const tsconfig = JSON.parse(content); + tsconfig.angularCompilerOptions = { + ...tsconfig.angularCompilerOptions, + compilationMode: 'full', + }; + + return JSON.stringify(tsconfig, null, 2); + }); + + harness.useTarget('build', { + ...BASE_OPTIONS, + compilationMode: CompilationMode.Partial, + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + + const fesm = harness.readFile('dist/lib/fesm2022/lib.mjs'); + expect(fesm).toContain('ɵɵngDeclareComponent'); + }); }); }); diff --git a/packages/angular/build/src/builders/library/tests/options/declaration-map_spec.ts b/packages/angular/build/src/builders/library/tests/options/declaration-map_spec.ts index a37e2f0dd255..2e30109d6a03 100644 --- a/packages/angular/build/src/builders/library/tests/options/declaration-map_spec.ts +++ b/packages/angular/build/src/builders/library/tests/options/declaration-map_spec.ts @@ -44,5 +44,43 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => expect(dtsMap.sources).toContain('../../../projects/lib/src/lib/lib.component.ts'); harness.expectFile(join('dist/lib/types', dtsMap.sources[0])).toExist(); }); + + it('should respect declarationMap from tsconfig when not set in builder options', async () => { + await harness.modifyFile('projects/lib/tsconfig.lib.json', (content) => { + const tsconfig = JSON.parse(content); + tsconfig.compilerOptions.declarationMap = true; + + return JSON.stringify(tsconfig, null, 2); + }); + + harness.useTarget('build', { + ...BASE_OPTIONS, + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + + harness.expectFile('dist/lib/types/lib.d.ts.map').toExist(); + }); + + it('should override declarationMap from tsconfig when declarationMap is false', async () => { + await harness.modifyFile('projects/lib/tsconfig.lib.json', (content) => { + const tsconfig = JSON.parse(content); + tsconfig.compilerOptions.declarationMap = true; + + return JSON.stringify(tsconfig, null, 2); + }); + + harness.useTarget('build', { + ...BASE_OPTIONS, + declarationMap: false, + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + + harness.expectFile('dist/lib/fesm2022/lib.mjs.map').toExist(); + harness.expectFile('dist/lib/types/lib.d.ts.map').toNotExist(); + }); }); }); diff --git a/packages/angular/build/src/builders/library/types.ts b/packages/angular/build/src/builders/library/types.ts index dfe91c36f3c5..7ec8545a9c8e 100644 --- a/packages/angular/build/src/builders/library/types.ts +++ b/packages/angular/build/src/builders/library/types.ts @@ -74,8 +74,8 @@ export interface NormalizedLibraryOptions { styleIncludePaths: string[]; sass?: StylesheetPluginsass; assets: ReturnType; - compilationMode: 'partial' | 'full'; - declarationMap: boolean; + compilationMode?: 'partial' | 'full'; + declarationMap?: boolean; allowedNonPeerDependencies: RegExp[]; keepLifecycleScripts: boolean; watch: boolean; @@ -127,6 +127,9 @@ export interface SingleBuildState { /** Cached unified TypeScript and Angular compilation state. */ singleProgramCache?: SingleProgramCache; + /** Effective compilation mode resolved from builder options and tsconfig. */ + compilationMode?: 'partial' | 'full'; + /** Map of entry point names to their previous bundle results. */ previousBundleResults: Map; diff --git a/packages/angular/build/src/tools/angular/compilation/angular-compilation.ts b/packages/angular/build/src/tools/angular/compilation/angular-compilation.ts index d766680d1674..3da78cdf0275 100644 --- a/packages/angular/build/src/tools/angular/compilation/angular-compilation.ts +++ b/packages/angular/build/src/tools/angular/compilation/angular-compilation.ts @@ -23,6 +23,7 @@ export interface FileTransformResult { export interface AngularCompilationOptions { allowJs?: boolean; + compilationMode?: 'full' | 'partial' | 'experimental-local'; declarationMap?: boolean; isolatedModules?: boolean; sourceMap?: boolean; diff --git a/packages/angular/build/src/tools/angular/compilation/compiler-options.ts b/packages/angular/build/src/tools/angular/compilation/compiler-options.ts index 1720a8bb0516..b2c83d616f08 100644 --- a/packages/angular/build/src/tools/angular/compilation/compiler-options.ts +++ b/packages/angular/build/src/tools/angular/compilation/compiler-options.ts @@ -71,6 +71,8 @@ export function transformCompilerOptions( compilerOptions.compilationMode = 'full'; } else if (overrides?.compilationMode) { compilerOptions.compilationMode = overrides.compilationMode; + } else if (isLibrary) { + compilerOptions.compilationMode ??= 'partial'; } // Enable incremental compilation by default if caching is enabled and incremental is not explicitly disabled @@ -114,7 +116,9 @@ export function transformCompilerOptions( compilerOptions.moduleResolution = typeScript.ModuleResolutionKind.Bundler; compilerOptions.importHelpers = true; compilerOptions.declaration = true; - compilerOptions.declarationMap = overrides?.declarationMap; + compilerOptions.declarationMap = !!( + overrides?.declarationMap ?? compilerOptions.declarationMap + ); compilerOptions.declarationDir = undefined; } diff --git a/packages/angular/build/src/tools/angular/compilation/parallel-worker.ts b/packages/angular/build/src/tools/angular/compilation/parallel-worker.ts index a74c032a1b70..475592bd478b 100644 --- a/packages/angular/build/src/tools/angular/compilation/parallel-worker.ts +++ b/packages/angular/build/src/tools/angular/compilation/parallel-worker.ts @@ -125,6 +125,7 @@ export async function initialize(request: InitRequest): Promise Date: Mon, 12 Oct 2026 19:18:38 +0200 Subject: [PATCH 09/52] fix(@angular/build): filter Rolldown warnings and disable .d.ts annotation comments in library builder Suppress noisy Rolldown warnings (`EMPTY_BUNDLE`, `UNUSED_EXTERNAL_IMPORT`, and `THIS_IS_UNDEFINED`) and disable annotation comments in `.d.ts` output bundles to match `ng-packagr` behavior. --- .../src/builders/library/pipeline/bundler.ts | 16 +++++++- .../library/tests/behavior/build_spec.ts | 41 +++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/packages/angular/build/src/builders/library/pipeline/bundler.ts b/packages/angular/build/src/builders/library/pipeline/bundler.ts index 314a8e205b2d..64042bd37f92 100644 --- a/packages/angular/build/src/builders/library/pipeline/bundler.ts +++ b/packages/angular/build/src/builders/library/pipeline/bundler.ts @@ -300,6 +300,15 @@ function processRolldownOutput( return { filesToEmit, moduleIdsByBundle, tslibBundles }; } +/** + * Set of Rolldown warning codes that should be ignored. + */ +const IGNORED_ROLLDOWN_WARNING_CODES: ReadonlySet = new Set([ + 'EMPTY_BUNDLE', + 'UNUSED_EXTERNAL_IMPORT', + 'THIS_IS_UNDEFINED', +]); + /** * Executes a Rolldown bundle build across all provided entry inputs. * @@ -341,7 +350,12 @@ async function executeMultiBundle( resolve: { symlinks: !preserveSymlinks }, checks: { circularDependency: false }, onLog(level, log) { + // Ignore specified warning codes if (level === 'warn') { + if (log.code && IGNORED_ROLLDOWN_WARNING_CODES.has(log.code)) { + return; + } + warnings.push(log.message); } }, @@ -358,7 +372,7 @@ async function executeMultiBundle( chunkFileNames: `[name]-[hash].${extension}`, sourcemap, hoistTransitiveImports: false, - comments: { jsdoc: isDts, legal: true, annotation: true }, + comments: { jsdoc: isDts, legal: true, annotation: !isDts }, }); return { diff --git a/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts b/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts index 74150e57acb7..996001db209d 100644 --- a/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts +++ b/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts @@ -74,6 +74,47 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => ); }); + it('should not log EMPTY_BUNDLE warnings for type-only entry points', async () => { + await harness.writeFile( + 'projects/lib/src/public-api.ts', + `export interface OnlyType { id: string; }`, + ); + + harness.useTarget('build', { + ...BASE_OPTIONS, + }); + + const { result, logs } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + expect(logs.some((l) => l.level === 'warn')).toBeFalse(); + }); + + it('should preserve JSDoc comments in .d.ts and annotation comments in .mjs bundles', async () => { + await harness.writeFile( + 'projects/lib/src/public-api.ts', + ` + function identity(x: T): T { return x; } + /** Public API JSDoc comment */ + export const VALUE = /* @__PURE__ */ identity('test'); + `, + ); + + harness.useTarget('build', { + ...BASE_OPTIONS, + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + + const fesmContent = harness.readFile('dist/lib/fesm2022/lib.mjs'); + expect(fesmContent).toContain('@__PURE__'); + expect(fesmContent).not.toContain('Public API JSDoc comment'); + + const dtsContent = harness.readFile('dist/lib/types/lib.d.ts'); + expect(dtsContent).toContain('Public API JSDoc comment'); + expect(dtsContent).not.toContain('@__PURE__'); + }); + it('should automatically add tslib to dependencies when output chunks import tslib', async () => { await harness.writeFile( 'projects/lib/src/public-api.ts', From 1559380cb6e4768c387946cd889beb75eb138779 Mon Sep 17 00:00:00 2001 From: Angular Robot Date: Mon, 12 Oct 2026 19:01:36 +0000 Subject: [PATCH 10/52] build: update cross-repo angular dependencies See associated pull request for more information. --- .../assistant-to-the-branch-manager.yml | 2 +- .github/workflows/ci.yml | 52 +- .github/workflows/dev-infra.yml | 6 +- .github/workflows/perf.yml | 6 +- .github/workflows/pr.yml | 44 +- MODULE.bazel | 6 +- MODULE.bazel.lock | 36 +- package.json | 2 +- pnpm-lock.yaml | 606 ++++++++---------- tests/e2e/ng-snapshot/package.json | 32 +- 10 files changed, 363 insertions(+), 429 deletions(-) diff --git a/.github/workflows/assistant-to-the-branch-manager.yml b/.github/workflows/assistant-to-the-branch-manager.yml index 5431306096a7..8c6035d666dc 100644 --- a/.github/workflows/assistant-to-the-branch-manager.yml +++ b/.github/workflows/assistant-to-the-branch-manager.yml @@ -18,6 +18,6 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - - uses: angular/dev-infra/github-actions/branch-manager@b137f89f74478e0d2b3902372c538d5656795e9a # main + - uses: angular/dev-infra/github-actions/branch-manager@28ae58d2ad683fb3991006c23a9829c08b65aaec # main with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad97a6cf125e..56dde16b608c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,9 +21,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Generate JSON schema types @@ -44,11 +44,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -61,11 +61,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -84,13 +84,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -100,11 +100,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -137,7 +137,7 @@ jobs: runs-on: windows-2025 steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Download built Windows E2E tests @@ -164,13 +164,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -188,13 +188,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -208,13 +208,13 @@ jobs: SAUCE_TUNNEL_IDENTIFIER: angular-cli-${{ github.workflow }}-${{ github.run_number }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Start Sauce Connect @@ -245,11 +245,11 @@ jobs: CIRCLE_BRANCH: ${{ github.ref_name }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - run: pnpm admin snapshots --verbose env: SNAPSHOT_BUILDS_GITHUB_TOKEN: ${{ secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN }} diff --git a/.github/workflows/dev-infra.yml b/.github/workflows/dev-infra.yml index 98d8d726c99b..f508452e9456 100644 --- a/.github/workflows/dev-infra.yml +++ b/.github/workflows/dev-infra.yml @@ -16,21 +16,21 @@ jobs: if: github.event_name == 'pull_request_target' runs-on: ubuntu-latest steps: - - uses: angular/dev-infra/github-actions/labeling/pull-request@b137f89f74478e0d2b3902372c538d5656795e9a # main + - uses: angular/dev-infra/github-actions/labeling/pull-request@28ae58d2ad683fb3991006c23a9829c08b65aaec # main with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} post_approval_changes: if: github.event_name == 'pull_request_target' runs-on: ubuntu-latest steps: - - uses: angular/dev-infra/github-actions/post-approval-changes@b137f89f74478e0d2b3902372c538d5656795e9a # main + - uses: angular/dev-infra/github-actions/post-approval-changes@28ae58d2ad683fb3991006c23a9829c08b65aaec # main with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} issue_labels: if: github.event_name == 'issues' runs-on: ubuntu-latest steps: - - uses: angular/dev-infra/github-actions/labeling/issue@b137f89f74478e0d2b3902372c538d5656795e9a # main + - uses: angular/dev-infra/github-actions/labeling/issue@28ae58d2ad683fb3991006c23a9829c08b65aaec # main with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} google-generative-ai-key: ${{ secrets.GOOGLE_GENERATIVE_AI_KEY }} diff --git a/.github/workflows/perf.yml b/.github/workflows/perf.yml index e61e4d1bb083..1c275f2d1a0d 100644 --- a/.github/workflows/perf.yml +++ b/.github/workflows/perf.yml @@ -22,7 +22,7 @@ jobs: workflows: ${{ steps.workflows.outputs.workflows }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Install node modules run: pnpm install --frozen-lockfile - id: workflows @@ -40,9 +40,9 @@ jobs: workflow: ${{ fromJSON(needs.list.outputs.workflows) }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Install node modules run: pnpm install --frozen-lockfile # We utilize the google-github-actions/auth action to allow us to get an active credential using workflow diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 7cf337949011..d9195bdf9f8c 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -34,9 +34,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup ESLint Caching uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: @@ -66,17 +66,17 @@ jobs: # it has been merged. run: pnpm ng-dev format changed --check ${{ github.event.pull_request.base.sha }} - name: Check Package Licenses - uses: angular/dev-infra/github-actions/linting/licenses@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/linting/licenses@28ae58d2ad683fb3991006c23a9829c08b65aaec # main build: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Build release targets @@ -93,11 +93,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Run module and package tests @@ -114,13 +114,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Run CLI E2E tests run: pnpm bazel test --test_env=E2E_SHARD_TOTAL=6 --test_env=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests:e2e.${{ matrix.subset }}_node${{ matrix.node }} @@ -128,11 +128,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Build E2E tests for Windows on Linux @@ -156,7 +156,7 @@ jobs: runs-on: windows-2025 steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Download built Windows E2E tests @@ -183,13 +183,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Run CLI E2E tests run: pnpm bazel test --test_env=E2E_SHARD_TOTAL=3 --test_env=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests:e2e.${{ matrix.subset }}_node${{ matrix.node }} @@ -205,12 +205,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@b137f89f74478e0d2b3902372c538d5656795e9a # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main - name: Run CLI E2E tests run: pnpm bazel test --test_env=E2E_SHARD_TOTAL=6 --test_env=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests:e2e.snapshots.${{ matrix.subset }}_node${{ matrix.node }} diff --git a/MODULE.bazel b/MODULE.bazel index 1a6f890d5188..a4caf9a9bc97 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -19,21 +19,21 @@ bazel_dep(name = "aspect_rules_jasmine", version = "2.0.4") bazel_dep(name = "rules_angular") git_override( module_name = "rules_angular", - commit = "2d9142c529ac31dddf1bb4e7e5a61c696f97a8f4", + commit = "b5869cff3db5d2217b8896d483e75af8a1d26712", remote = "https://github.com/angular/rules_angular.git", ) bazel_dep(name = "devinfra") git_override( module_name = "devinfra", - commit = "b137f89f74478e0d2b3902372c538d5656795e9a", + commit = "28ae58d2ad683fb3991006c23a9829c08b65aaec", remote = "https://github.com/angular/dev-infra.git", ) bazel_dep(name = "rules_browsers") git_override( module_name = "rules_browsers", - commit = "dba44a25ad8789113c37c2aace5574d794faa7ef", + commit = "4b53d68eed02bbb0901b21fb02b8cf99f4f59a52", remote = "https://github.com/angular/rules_browsers.git", ) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index c29e353e22a7..38524a59eced 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -93,7 +93,6 @@ "https://bcr.bazel.build/modules/hermetic_launcher/0.0.15/source.json": "aceb903a3bda5131b0a3132ccf77f36f32b96dcb70864049ec8cfdf9c0b0f068", "https://bcr.bazel.build/modules/jq.bzl/0.1.0/MODULE.bazel": "2ce69b1af49952cd4121a9c3055faa679e748ce774c7f1fda9657f936cae902f", "https://bcr.bazel.build/modules/jq.bzl/0.4.0/MODULE.bazel": "a7b39b37589f2b0dad53fd6c1ccaabbdb290330caa920d7ef3e6aad068cd4ab2", - "https://bcr.bazel.build/modules/jq.bzl/0.7.0/MODULE.bazel": "9d382531c42e7a7f6f2ea486aa8f27c605c54f6109e565f04056015e5764deca", "https://bcr.bazel.build/modules/jq.bzl/0.7.1/MODULE.bazel": "2dc4fd806df09b30aa7e0339f141a661f72df6af237f6db1fc4ca5c5045f1772", "https://bcr.bazel.build/modules/jq.bzl/0.7.1/source.json": "0dbd7febb9361e34247c952e749f21f258b5123126248624c0d921c4592eac96", "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", @@ -181,7 +180,6 @@ "https://bcr.bazel.build/modules/rules_nodejs/6.2.0/MODULE.bazel": "ec27907f55eb34705adb4e8257952162a2d4c3ed0f0b3b4c3c1aad1fac7be35e", "https://bcr.bazel.build/modules/rules_nodejs/6.5.0/MODULE.bazel": "546d0cf79f36f9f6e080816045f97234b071c205f4542e3351bd4424282a8810", "https://bcr.bazel.build/modules/rules_nodejs/6.7.3/MODULE.bazel": "c22a48b2a0dbf05a9dc5f83837bbc24c226c1f6e618de3c3a610044c9f336056", - "https://bcr.bazel.build/modules/rules_nodejs/6.7.5/MODULE.bazel": "97e6794043821d23c013baa4a50fd1c599f2e6ae92b06e2c5f1cd7074fd83e7c", "https://bcr.bazel.build/modules/rules_nodejs/6.7.6/MODULE.bazel": "45f203b9c0d721bcb1a5932815f218091fa2169cede2af3d88a8a17a4fb7676a", "https://bcr.bazel.build/modules/rules_nodejs/6.7.6/source.json": "ad9987b7979be1ce93d10ffee9b6af4f84f8835cbc7def27937d632da2e4750e", "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", @@ -447,16 +445,16 @@ }, "@@rules_browsers+//browsers:extensions.bzl%browsers": { "general": { - "bzlTransitiveDigest": "v0vEY6SvVg9HBAENk4KWY5NR6epcg4ucdSnkhcCNv8E=", + "bzlTransitiveDigest": "/FonktAou7w4aKjGZUZDFFOlASeGnKNw0QALxUIdtuE=", "usagesDigest": "FmXYJVoVJlnfUU8x8gObSvu4qWcco/9Faw61aC/wBF0=", "recordedInputs": [], "generatedRepoSpecs": { "rules_browsers_chrome_linux": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "272b05d40a44082c82d09beb35c7cb7116564a6a85ff2f7a48bc161129fc5772", + "sha256": "9541eafbc02f85e3ec0c24b05f8bbffe88094389949860681bf6055aef668d7b", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/157.0.8089.0/linux64/chrome-headless-shell-linux64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/157.0.8099.0/linux64/chrome-headless-shell-linux64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-linux64/chrome-headless-shell" @@ -472,9 +470,9 @@ "rules_browsers_chrome_mac": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "9c28150b8c24fa99ac1e9e39fa07247b61d7f6f15f1c25ca9273c1b4273e2afd", + "sha256": "358f032d48a0b825b0601b89b970da5a7c245344ed7a557a3ef8613c342521b0", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/157.0.8089.0/mac-x64/chrome-headless-shell-mac-x64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/157.0.8099.0/mac-x64/chrome-headless-shell-mac-x64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-mac-x64/chrome-headless-shell" @@ -490,9 +488,9 @@ "rules_browsers_chrome_mac_arm": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "a6471f52b4eeb52af88d2f45e16125a9327517fd8b43512fc5561a3318487640", + "sha256": "c3de600edda5e11aa40918f123781040cd6e9c2509a2acfc466b773bf7c9b326", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/157.0.8089.0/mac-arm64/chrome-headless-shell-mac-arm64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/157.0.8099.0/mac-arm64/chrome-headless-shell-mac-arm64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-mac-arm64/chrome-headless-shell" @@ -508,9 +506,9 @@ "rules_browsers_chrome_win64": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "64332865f3d250a66f704e90d37a3d57f9800d6ea774138ede35ea37d1af7f2c", + "sha256": "b2e81e06ac46d3355bc6428b3abe97308d34e810d4404427bbd14665111e67a1", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/157.0.8089.0/win64/chrome-headless-shell-win64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/157.0.8099.0/win64/chrome-headless-shell-win64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-win64/chrome-headless-shell.exe" @@ -526,9 +524,9 @@ "rules_browsers_chromedriver_linux": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "0901026cbac4cce608a95bcbdcc87166e7736c9cc0431f5d3466058c9e570aec", + "sha256": "cf16fed1899de0f0b8999389779cefbb6696c5fd44ad9718ce2195a3ff5ca029", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/157.0.8089.0/linux64/chromedriver-linux64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/157.0.8099.0/linux64/chromedriver-linux64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-linux64/chromedriver" @@ -542,9 +540,9 @@ "rules_browsers_chromedriver_mac": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "69b0982bfe954c969cbc9357a39efb2f1861447f4168017831ffafec62448d90", + "sha256": "ba472bdd32ee62a98f04fcca364015a0df241fdf85ee7d834a048b5fdfd90fd3", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/157.0.8089.0/mac-x64/chromedriver-mac-x64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/157.0.8099.0/mac-x64/chromedriver-mac-x64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-mac-x64/chromedriver" @@ -558,9 +556,9 @@ "rules_browsers_chromedriver_mac_arm": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "18d30af4843f5535d56ab615702749650f1fc9c6b67ec3fd419ed5a9d4fcbf58", + "sha256": "8fe44ebac5303278a5d533c114ad0dbed0df9c218bce5b80d606078472ea95bd", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/157.0.8089.0/mac-arm64/chromedriver-mac-arm64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/157.0.8099.0/mac-arm64/chromedriver-mac-arm64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-mac-arm64/chromedriver" @@ -574,9 +572,9 @@ "rules_browsers_chromedriver_win64": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "9b79fc95eed9212d5888a1a7de456eba68df54d65b6fb490ce34d55efdc5cd48", + "sha256": "1fadd71af32db4e3497ce4faac3f07503f4c4cdad8747e71ff62c5c9c3dd05e1", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/157.0.8089.0/win64/chromedriver-win64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/157.0.8099.0/win64/chromedriver-win64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-win64/chromedriver.exe" diff --git a/package.json b/package.json index 1037a8bfa7c6..6541f5d157af 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "@angular/forms": "22.3.0-next.1", "@angular/localize": "22.3.0-next.1", "@angular/material": "22.3.0-next.1", - "@angular/ng-dev": "https://github.com/angular/dev-infra-private-ng-dev-builds.git#89b8c002e5d47ba1cbc4483d3ec06b0ae0aaccb7", + "@angular/ng-dev": "https://github.com/angular/dev-infra-private-ng-dev-builds.git#fa4308affb4a0dde34ebc95196b58550752485a2", "@angular/platform-browser": "22.3.0-next.1", "@angular/platform-server": "22.3.0-next.1", "@angular/router": "22.3.0-next.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e6b9e456459e..b6cf96a9c926 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -208,8 +208,8 @@ importers: specifier: 22.3.0-next.1 version: 22.3.0-next.1(837417520965053888cf2615dc986a27) '@angular/ng-dev': - specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#89b8c002e5d47ba1cbc4483d3ec06b0ae0aaccb7 - version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/89b8c002e5d47ba1cbc4483d3ec06b0ae0aaccb7 + specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#fa4308affb4a0dde34ebc95196b58550752485a2 + version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/fa4308affb4a0dde34ebc95196b58550752485a2 '@angular/platform-browser': specifier: 22.3.0-next.1 version: 22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)) @@ -1106,9 +1106,9 @@ packages: '@angular/platform-browser': ^22.0.0-0 || ^22.1.0-0 || ^22.2.0-0 || ^22.3.0-0 || ^23.0.0-0 rxjs: ^6.5.3 || ^7.4.0 - '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/89b8c002e5d47ba1cbc4483d3ec06b0ae0aaccb7': - resolution: {gitHosted: true, integrity: sha512-vfMwQfoXYY5dX8IISR/9DpsLT+py7Zm2Nqj6CybryjFosxMxW4ajXKfJ3Zywu2k0wPfRVoQY+PMZ78vfPji+qQ==, tarball: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/89b8c002e5d47ba1cbc4483d3ec06b0ae0aaccb7} - version: 0.0.0-8b6cbbca278a26f2495275c5d9d0d8633573162d + '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/fa4308affb4a0dde34ebc95196b58550752485a2': + resolution: {gitHosted: true, integrity: sha512-zq1Lg7edQb2cf9QrSiQEU/+LwY4e/af9tN9W3hO5jDdYK+gp+sYZbBbuzounSWkmK+j+oG0K5CA9/kmyHAimZg==, tarball: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/fa4308affb4a0dde34ebc95196b58550752485a2} + version: 0.0.0-f28485704b2d1f81ae380a8296a4f14d9852c248 hasBin: true '@angular/platform-browser@22.3.0-next.1': @@ -1763,12 +1763,12 @@ packages: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} - '@conventional-changelog/git-client@3.1.2': - resolution: {integrity: sha512-jZqwnJwf7nboIlAcw/mkOjVa6DexCcUOgT2oOQgkoi3z9vR8tGFkcMy2BFcYwjhL9sYcDDXkRQDayiDieCoW7A==} + '@conventional-changelog/git-client@3.2.0': + resolution: {integrity: sha512-sD/E0vzpkoDz/dqM1Hhv0ihC4KBw6RXjefeO8SG1XrX+wGkMxe1pKeedkKDPCtr2JjuhbuS9aJNgOvnT8hbeBw==} engines: {node: '>=22'} peerDependencies: conventional-commits-filter: ^6.0.1 - conventional-commits-parser: ^7.1.2 + conventional-commits-parser: ^7.1.3 peerDependenciesMeta: conventional-commits-filter: optional: true @@ -2036,9 +2036,9 @@ packages: '@noble/hashes': optional: true - '@firebase/ai@2.16.0': - resolution: {integrity: sha512-WRVxl58B61Orwf7st7949ZIW2L4huV80Gpaum1z8v2eH+m2xaxWtC8mOjQyVAOirr6O/yf89cBjlPvoyBpBfTg==} - engines: {node: '>=20.0.0'} + '@firebase/ai@3.0.0': + resolution: {integrity: sha512-66jJAi6JUmyXna89xaDONmfvupO1wNc3f2BegPwUImagbbpKdVeycE3kMqbU4jiDLL14N5PHzadovvxpaqD2hw==} + engines: {node: '>=24.12.0'} peerDependencies: '@firebase/app': 0.x '@firebase/app-types': 0.x @@ -2076,20 +2076,20 @@ packages: peerDependencies: '@firebase/app': 0.x - '@firebase/app-compat@0.5.18': - resolution: {integrity: sha512-77H57WuGEsgrv59HdtuhHG+eQdP8di6myz7O93yW6yTZlR/tLSmsCxCq5vHp6AWWDwSV0EVtKUvizXQiQZVBWA==} - engines: {node: '>=20.0.0'} + '@firebase/app-compat@0.5.19': + resolution: {integrity: sha512-pdT+THcv3h43LcawVJ+MUTzofL7umBaCvCgdbr01fnTXrbQU2RSHb0Po/YsF7w+tgjCycg84zCgZbd51NmoIaA==} + engines: {node: '>=24.12.0'} '@firebase/app-types@0.9.6': resolution: {integrity: sha512-yPLahy7Esfu2w/yme3msVK4xTkDXQqq6szfQn8yVOQpCKiT5GVFjqNpLbuz6NkX0WuTwUidkmPewW3r4xkvpeg==} - '@firebase/app@0.16.2': - resolution: {integrity: sha512-fyCLPahl3r0Zb7Wzm+JLWcOOH3SaDgAyJzJ8EWIDiv51aNiv+2Pjbpa6myEuP7iXxjmJqrcbVm0GUF7h229T1Q==} - engines: {node: '>=20.0.0'} + '@firebase/app@0.16.3': + resolution: {integrity: sha512-L2mYqVV2ilnek+W4JG7yasA97TsXCwx+f7/abweX5uSp3dkPa5Luiglt3s9YWfh1fBR3SWH/AkRgAwUpDGyCjg==} + engines: {node: '>=24.12.0'} - '@firebase/auth-compat@0.6.11': - resolution: {integrity: sha512-L+xp3DTJQrBV08Vt0UhcL/ofUOSjXom7JOJfbT6oas4o7gCrQnTYFKs8wfiuKLmHoo8BxMr5LdgjAs7o6aAsqQ==} - engines: {node: '>=20.0.0'} + '@firebase/auth-compat@0.6.12': + resolution: {integrity: sha512-Vspo2zx1RR6LB7zuM7TduD1clMLT/x3Wr97u2jf9s2JrhYArJAFKeEu8bRWF1DoX54z6W9N77SdPRbPAiLKPpg==} + engines: {node: '>=24.12.0'} peerDependencies: '@firebase/app': 0.x '@firebase/app-compat': 0.x @@ -2103,9 +2103,9 @@ packages: '@firebase/app-types': 0.x '@firebase/util': 1.x - '@firebase/auth@1.13.6': - resolution: {integrity: sha512-MKRLvF72HJ/irNn2fJR0Gv5FOZNtqv1IBeJHRwK8l8pZ/wi9vuUw8ecyCMvQDDNxfS6uW0MWACL5KC4Y8Pp+fA==} - engines: {node: '>=20.0.0'} + '@firebase/auth@1.13.7': + resolution: {integrity: sha512-00wn8cMrh1ZyEPF6RO5G081Xq1b57FN0QxChiAda0hy/D3Q5TrMk30qhWszRWCgXPRipw6yM6qtqUew3u3qEjA==} + engines: {node: '>=24.12.0'} peerDependencies: '@firebase/app': 0.x '@react-native-async-storage/async-storage': ^2.2.0 || ^3.0.0 @@ -2141,9 +2141,9 @@ packages: resolution: {integrity: sha512-/JGpvszLoNXNgzilRXocigGfFF4hbcPA9wN1i1kjJx6oKkXgkHteZYl3lQs1lJX3ETDf6bv7zI15lPMVUp4sAQ==} engines: {node: '>=20.0.0'} - '@firebase/firestore-compat@0.4.14': - resolution: {integrity: sha512-HJ2HBNgNPrRsWIJ4E+Kc0u0h1U7HlF7If8AtYjie9HZXlMUmwYSJaXBj9VFm6gkSj5dlKZNcOQ0Ou25CVVG6rA==} - engines: {node: '>=20.0.0'} + '@firebase/firestore-compat@0.4.15': + resolution: {integrity: sha512-/hWibRTNFsWkZZi1dbDS1hiJIMezYUMPrRjMmBXevel5b368XWY+NvfOaSxgy3+fDb6I+uZ7SKGFyL06gW3vTA==} + engines: {node: '>=24.12.0'} peerDependencies: '@firebase/app': 0.x '@firebase/app-compat': 0.x @@ -2154,9 +2154,9 @@ packages: '@firebase/app-types': 0.x '@firebase/util': 1.x - '@firebase/firestore@4.17.2': - resolution: {integrity: sha512-SiyQEK1dYPOjItFVA+kZGdvOoRAtMebDBvUaSxJPNZMkKcRwYYK2kzWo5UXTZZj523uMxJnkr+KKVySEMme3kQ==} - engines: {node: '>=20.0.0'} + '@firebase/firestore@4.18.0': + resolution: {integrity: sha512-28aKMUeM+L4fuxx5hurvQK31KLh/KRutaP1544avVWuR4mNTAC0FQoHg8gbkN5NoJj3yN9/ZFGSFSVPR8/x/BQ==} + engines: {node: '>=24.12.0'} peerDependencies: '@firebase/app': 0.x @@ -2224,8 +2224,8 @@ packages: peerDependencies: '@firebase/app': 0.x - '@firebase/remote-config-compat@0.2.29': - resolution: {integrity: sha512-mY7JtTISK6F4g4T0x3kVepr5cp0NXL7f5yjIUXXGaTrg4qUlFBWRbENaHaqZ78dwmNcLm24h/yPsOVRlDXEXhA==} + '@firebase/remote-config-compat@0.2.30': + resolution: {integrity: sha512-Q4sQKhQ8TPEMOcCUvUBfGeAP1DfcG7FGBfA9yFUn/XRr4vSToY0DTmK28Nh7lgLQYzs6D5Ng6knSoXH+aGn1Tg==} peerDependencies: '@firebase/app': 0.x '@firebase/app-compat': 0.x @@ -2233,14 +2233,14 @@ packages: '@firebase/remote-config-types@0.5.2': resolution: {integrity: sha512-i8k1omVfoAnaT1ZPv2FFjxMZrATYsO/GnFgHEj5+7fAJLzi8wLnGGv1WK06oEAD6ltrWXSO1HzeNyajn/NjMWw==} - '@firebase/remote-config@0.9.2': - resolution: {integrity: sha512-Rii93DkXjM+RE/ytHdYa7EIiQLJbdBr+W8EEiqd/vbLCOC+1FdkDuRiumJBp6t3yewHGbdqbpjB3fk3z0cZ+8g==} + '@firebase/remote-config@0.9.3': + resolution: {integrity: sha512-9DbuFNAFeUbVJQZmwLZfdoLRNFWV43V4UqaRpDkaSIdTmVWhzctPeISGkWe4sKTsqpoyldRumquS0gqWZg05fQ==} peerDependencies: '@firebase/app': 0.x - '@firebase/storage-compat@0.4.5': - resolution: {integrity: sha512-vO0tFPxXbKDKdlTu8tYT08S9t9ezUTJYEdLCULpWxWq2aq6zojwN1QmAB+1a50AI/g47GlWUJn1XPncm/PDZsw==} - engines: {node: '>=20.0.0'} + '@firebase/storage-compat@0.4.6': + resolution: {integrity: sha512-te0IsqX1bM+OZCJF7jNSKXcMqCA2yYmpshRHjX4axy0lI/P9ZP9GLjEZMVL8wrjUWF4e3cZxMZTbck3Zd5E1hA==} + engines: {node: '>=24.12.0'} peerDependencies: '@firebase/app': 0.x '@firebase/app-compat': 0.x @@ -2251,9 +2251,9 @@ packages: '@firebase/app-types': 0.x '@firebase/util': 1.x - '@firebase/storage@0.14.5': - resolution: {integrity: sha512-r2tozN/BlEewLi70tJNUQPzWwbex9GM7NgXZsamHKQrjKEfcR0i4jGgHBKAKA4hbwiPE9eNMb3hcxWnDpeJZwg==} - engines: {node: '>=20.0.0'} + '@firebase/storage@0.14.6': + resolution: {integrity: sha512-9WjohxpjbfcySjCp8kIbd1ZhtmCQFQLqPtDQ+wmZ5PVXimTDjDsSx/RZjwwK89MjCTXB9fCdmvZkJxplZn4W1A==} + engines: {node: '>=24.12.0'} peerDependencies: '@firebase/app': 0.x @@ -2295,8 +2295,8 @@ packages: resolution: {integrity: sha512-IJn+8A3QZJfe7FUtWqHVNo3xJs7KFpurCWGWCiCz3oEh+BkRymKZ1QxfAbU2yGMDzTytLGQ2IV6T2r3cuo75/w==} engines: {node: '>=18'} - '@google/genai@2.25.0': - resolution: {integrity: sha512-g1hyidWxahzIg+hh+lLqPeBJl+Fu6051we2QKhFXdWgE4yGYf8PWOS8S3mMAdpe3eLx3KCWmhQR7GWyd3LYT1A==} + '@google/genai@2.28.0': + resolution: {integrity: sha512-hyNAJj+ywu3L46qlZod6KO/JvcT3QONz6VCiPevC/FWOjAD+LQb7DMLUoV8vzoLpt61Q0ruQX99iqbxEjPJWmw==} engines: {node: '>=20.0.0'} peerDependencies: '@modelcontextprotocol/sdk': ^1.25.2 @@ -2358,15 +2358,6 @@ packages: '@types/node': optional: true - '@inquirer/confirm@6.3.2': - resolution: {integrity: sha512-Xvr/0HggjddPtGppuqVmxhTw+Hr8PvsZ/k0HmOEaAqQEt80OITNkFWnsdNmyT0/eM4Ab+iJLx2R8rctlEyfSVg==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/confirm@6.3.3': resolution: {integrity: sha512-ImOBgpl/sJTFp8naeSkNu4S0Sf8F8pxv3/CUx+LoBAdQvCVqFz6rSB2A/oZYsJge3+yphbEDxEkfaRNYq1OU0A==} engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} @@ -2443,15 +2434,6 @@ packages: '@types/node': optional: true - '@inquirer/prompts@8.7.2': - resolution: {integrity: sha512-QoRB4wFIjgH5iOhSjoIKMkTvSHDuV+O3OITlIqAYO0oK5x364GJILXiMBvlPiE+klg7Xx9tq5XVqQHcGUDYYPA==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/prompts@8.7.3': resolution: {integrity: sha512-DHK20kO+H5k/XcJQpHQUpVQbMYHHhZchlGWhZVMUV4WIuRuBW5744hipOtriE1vMqPLgnIyXFMHWKkIbTepa4Q==} engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} @@ -2488,15 +2470,6 @@ packages: '@types/node': optional: true - '@inquirer/type@4.1.1': - resolution: {integrity: sha512-yJoHYrMnxIsJZCY+0Vb66Dy3he3kL3e2wOBKhoSwWWAzZAY82emlxwgprCtp6yRixvNRNq9ztfRWQYPNr3Go7A==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/type@4.2.0': resolution: {integrity: sha512-2rnHX8RPo4glJYqnFc/v3nQeIhDcjyRRyaT7MGcfL/8xv/8K03SXYoA2tX06WVSKywWOE/ncbG3dtuzLjR5TCQ==} engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} @@ -2754,9 +2727,9 @@ packages: cpu: [x64] os: [win32] - '@mswjs/interceptors@0.41.9': - resolution: {integrity: sha512-VVPPgHyQ6ShqnrmDWuxjmUIsO9gWyOZFmuOfLd9LfBGQJwZfy0gvv9pbHSJuoFNIYC7ZDX9aoFwowjcdSC4E8w==} - engines: {node: '>=18'} + '@mswjs/interceptors@0.44.0': + resolution: {integrity: sha512-IYHevRStF4ijM20GI9c9Ndhw483NSAjCydQhUr4/zIB0BNLsTVw3vFAxTo6TlvX4QnV60wEHttUa9539TTAq+A==} + engines: {node: '>=22'} '@napi-rs/lzma-linux-x64-gnu@1.5.1': resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} @@ -2952,12 +2925,6 @@ packages: peerDependencies: '@octokit/core': '>=6' - '@octokit/plugin-paginate-rest@15.0.0': - resolution: {integrity: sha512-lw9A9YL5s4VPj+VEx8uMxaxQm2YTgrPDkrLEuZuu18R8TK3oPcXF4K6t52nx6xn1RcogZC9i188sAr/4XYJaQQ==} - engines: {node: '>= 20'} - peerDependencies: - '@octokit/core': '>=6' - '@octokit/plugin-request-log@6.0.0': resolution: {integrity: sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==} engines: {node: '>= 20'} @@ -2997,14 +2964,8 @@ packages: '@octokit/types@18.0.0': resolution: {integrity: sha512-l6bAF43PNxkJp6g+W4PjoUSSkxHomXw2nOum5CTftJz1NlV3vu93NImgOYtLf6CbBUb5j+fiuzW0PPQ5JTSvZA==} - '@open-draft/deferred-promise@2.2.0': - resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} - - '@open-draft/logger@0.3.0': - resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} - - '@open-draft/until@2.1.0': - resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + '@open-draft/until@3.0.1': + resolution: {integrity: sha512-s7/9ELP4aP9YZtW7RJaa0Xf3RISaRH9+EFN18FtykJYRHGNrl8f9ymvoNXzjhrjmftFvkQudtuDU9RYhk0xs3A==} '@opentelemetry/api@1.9.1': resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} @@ -3781,6 +3742,9 @@ packages: '@types/cors@2.8.19': resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==} + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} @@ -3850,11 +3814,14 @@ packages: '@types/micromatch@2.3.35': resolution: {integrity: sha512-J749bHo/Zu56w0G0NI/IGHLQPiSsjx//0zJhfEVAN95K/xM5C8ZDmhkXtU3qns0sBOao7HuQzr8XV1/2o5LbXA==} + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/node@22.20.5': resolution: {integrity: sha512-U2+DNr+wSjpsTS/wZGYHq7GcwfuSmKiKvoPvK22zwTlRhU91yOniN4qRR5KhIjvif7ysw/dz/hKmfDH0Ris4aA==} - '@types/node@24.19.0': - resolution: {integrity: sha512-zY+5tKxXdhGh1PYI0ac+7juvEu4OI6vWtVVoj5i2m42jxAY1U+zHGt6QCyOFwykdP62sM3MJ9stoYYUw5aCWew==} + '@types/node@24.19.1': + resolution: {integrity: sha512-aS3/DG0oM05K0RIXXP+hKjinGG5IgSSVGzswZxW3O0sS3pH4/fycXundUC9XsszgKCk4gHXylTEK6hyFxVxnoQ==} '@types/npm-package-arg@6.1.4': resolution: {integrity: sha512-vDgdbMy2QXHnAruzlv68pUtXCjmqUk3WrBAsRboRovsOmxbfn/WiYCjmecyKjGztnMps5dWp4Uq2prp+Ilo17Q==} @@ -4911,8 +4878,8 @@ packages: resolution: {integrity: sha512-cs+LadpH7Kpw0M3k8wurk+sOVVDAENA0iK4OBOrkL94j5lEVYRJ4j3zd2bhY9qgzyrPqthdcYT3axzRN7AliMg==} engines: {node: '>=22'} - conventional-commits-parser@7.1.2: - resolution: {integrity: sha512-O+x4N2yH+ijvqWlIyTHsXTAP+algNWgGbjY2duCe8w2vUMvUB95cLRslCPfTMQyLAKlet3bhZTdu6ozn4M+QJQ==} + conventional-commits-parser@7.1.3: + resolution: {integrity: sha512-Q9oWm1o9uy/oEsZQIraoFMZ4RuPD+79KgwWj6mJVP356tazolCB0piRLZ5Kz9te9p027uSEcUW+Gu44Eh+X79g==} engines: {node: '>=22'} hasBin: true @@ -5049,15 +5016,6 @@ packages: supports-color: optional: true - debug@4.4.0: - resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -5565,8 +5523,8 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - firebase@12.19.0: - resolution: {integrity: sha512-kwXCLcI0ly2lkwygkbuRx6SsX3DSO96355YrWh9SWZ5ncsxK/y5cirn3sY6nZVSiBVE++2nL6Hchzu1EB8uohQ==} + firebase@13.0.0: + resolution: {integrity: sha512-4cChZajVtuOijT/t7Vw1GZRTuohCxw+aoc8DAwhF+CSbS+zhqHE+i5PzEVttIySw7oKerBDRZRyDt4FynrWecg==} flat-cache@6.1.23: resolution: {integrity: sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==} @@ -5582,8 +5540,8 @@ packages: resolution: {integrity: sha512-kWyh8ADvHBFz6ua5xYOPnUroZTT/bwWfrCeL0Wj1dzG4/YOmOcfJ99W8dOVyyynJN35rZ9aCOtHChqQovV7yog==} engines: {node: '>=6'} - folder-hash@4.1.3: - resolution: {integrity: sha512-94fj+fXj1XHT8zGumUy/VlyFARc/yrslKJ2+vjrP/U6ftTdL7u68+gQhvSBjz9wrwTuty6BpZ7JsbEK5OU9RNw==} + folder-hash@4.1.4: + resolution: {integrity: sha512-BhHpJCYoTej4YH0C3HY4X49C2uOcWntjSD24T1GBYlfWcW/7mkHZov9HbvzCHQO+ZLbJ3VRE+cL1uEiaQvacLw==} engines: {node: '>=10.10.0'} hasBin: true @@ -6904,9 +6862,9 @@ packages: tailwindcss: optional: true - nock@14.0.17: - resolution: {integrity: sha512-EjRr1weMa4ALQX35AgZTEnP+weJJjlW1KGDiNM2IQC2069YDHas4f4B4UUYR+TTLyKWxJvOz2wObDKQs/LNreA==} - engines: {node: '>=18.20.0 <20 || >=20.12.1'} + nock@15.0.1: + resolution: {integrity: sha512-Mjx5Xl4t9vP13eUZPWqwwpjjXNjvhUTo1qTdryVM3+7t6Z2w6WHZ9GVZk/zQ8Ym1vbmloWaglye3cloyHAJ8FA==} + engines: {node: '>=20.12.1'} node-addon-api@6.1.0: resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} @@ -7305,10 +7263,6 @@ packages: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} - propagate@2.0.1: - resolution: {integrity: sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==} - engines: {node: '>= 8'} - proto3-json-serializer@3.0.4: resolution: {integrity: sha512-E1sbAYg3aEbXrq0n1ojJkRHQJGE1kaE/O6GLA94y8rnJBfgvOPTOd1b9hOceQK1FFZI9qMh1vBERCyO2ifubcw==} engines: {node: '>=18'} @@ -7522,6 +7476,9 @@ packages: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} engines: {node: '>= 4'} + rettime@0.11.12: + resolution: {integrity: sha512-5ExtR1ppiDBQkVoPw5NAqdbfH4Iq2VOmQKHMtUoaFxA9bo2krzFYBtyq6K40xxbYp+2w/YOr6D+1ToF6tTN53A==} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -8002,9 +7959,6 @@ packages: streamx@2.28.1: resolution: {integrity: sha512-zEzXb0s5Cds7tqMH6rhZ05lcJydCWiQPEwiNngVqzsxCc962vLY4Uw+mW7od8kDH258k2Uz/JrOkdIAAhSh9VA==} - strict-event-emitter@0.5.1: - resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} - string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -8890,30 +8844,28 @@ snapshots: rxjs: 7.8.2 tslib: 2.8.1 - '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/89b8c002e5d47ba1cbc4483d3ec06b0ae0aaccb7': + '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/fa4308affb4a0dde34ebc95196b58550752485a2': dependencies: '@actions/core': 3.0.1 - '@conventional-changelog/git-client': 3.1.2(conventional-commits-filter@6.0.1)(conventional-commits-parser@7.1.2) + '@conventional-changelog/git-client': 3.2.0(conventional-commits-filter@6.0.1)(conventional-commits-parser@7.1.3) '@google-cloud/spanner': 8.0.0(supports-color@11.0.0) - '@google/genai': 2.25.0(bufferutil@4.1.0)(supports-color@11.0.0)(utf-8-validate@6.0.6) - '@inquirer/prompts': 8.7.2(@types/node@24.19.0) - '@inquirer/type': 4.1.1(@types/node@24.19.0) + '@google/genai': 2.28.0(bufferutil@4.1.0)(supports-color@11.0.0)(utf-8-validate@6.0.6) + '@inquirer/prompts': 8.7.3(@types/node@24.19.1) + '@inquirer/type': 4.2.0(@types/node@24.19.1) '@octokit/auth-app': 8.3.1 '@octokit/core': 7.0.8 '@octokit/graphql': 9.0.5 '@octokit/graphql-schema': 15.26.1 - '@octokit/openapi-types': 28.0.0 - '@octokit/plugin-paginate-rest': 15.0.0(@octokit/core@7.0.8) '@octokit/plugin-rest-endpoint-methods': 18.0.0(@octokit/core@7.0.8) '@octokit/request-error': 7.1.2 '@octokit/rest': 22.0.1 - '@octokit/types': 17.0.0 + '@octokit/types': 18.0.0 '@types/cli-progress': 3.11.6 '@types/ejs': 3.1.5 '@types/events': 3.0.3 '@types/folder-hash': 4.0.4 '@types/jasmine': 6.0.0 - '@types/node': 24.19.0 + '@types/node': 24.19.1 '@types/semver': 7.8.0 '@types/which': 3.0.4 '@types/yargs': 17.0.35 @@ -8922,19 +8874,19 @@ snapshots: bufferutil: 4.1.0 cli-progress: 3.12.0 conventional-commits-filter: 6.0.1 - conventional-commits-parser: 7.1.2 + conventional-commits-parser: 7.1.3 ejs: 7.0.1 encoding: 0.1.13 fast-glob: 3.3.3 - firebase: 12.19.0 - folder-hash: 4.1.3(supports-color@11.0.0) + firebase: 13.0.0 + folder-hash: 4.1.4(supports-color@11.0.0) jasmine: 6.3.0 jasmine-core: 6.3.0 jasmine-reporters: 2.5.2 jsonc-parser: 3.3.1 minimatch: 10.2.6 multimatch: 8.0.0 - nock: 14.0.17 + nock: 15.0.1(supports-color@11.0.0) semver: 7.8.5 supports-color: 11.0.0 tsx: 4.23.15 @@ -9738,14 +9690,14 @@ snapshots: '@colors/colors@1.5.0': {} - '@conventional-changelog/git-client@3.1.2(conventional-commits-filter@6.0.1)(conventional-commits-parser@7.1.2)': + '@conventional-changelog/git-client@3.2.0(conventional-commits-filter@6.0.1)(conventional-commits-parser@7.1.3)': dependencies: '@simple-libs/child-process-utils': 2.0.0 '@simple-libs/stream-utils': 2.0.0 - semver: 7.8.5 + verkit: 0.5.0 optionalDependencies: conventional-commits-filter: 6.0.1 - conventional-commits-parser: 7.1.2 + conventional-commits-parser: 7.1.3 '@csstools/color-helpers@6.1.2': {} @@ -9929,9 +9881,9 @@ snapshots: optionalDependencies: '@noble/hashes': 1.8.0 - '@firebase/ai@2.16.0(@firebase/app-types@0.9.6)(@firebase/app@0.16.2)': + '@firebase/ai@3.0.0(@firebase/app-types@0.9.6)(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 + '@firebase/app': 0.16.3 '@firebase/app-check-interop-types': 0.3.5 '@firebase/app-types': 0.9.6 '@firebase/component': 0.7.5 @@ -9939,33 +9891,33 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 - '@firebase/analytics-compat@0.2.31(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2)': + '@firebase/analytics-compat@0.2.31(@firebase/app-compat@0.5.19)(@firebase/app@0.16.3)': dependencies: - '@firebase/analytics': 0.10.25(@firebase/app@0.16.2) + '@firebase/analytics': 0.10.25(@firebase/app@0.16.3) '@firebase/analytics-types': 0.8.5 - '@firebase/app': 0.16.2 - '@firebase/app-compat': 0.5.18 + '@firebase/app': 0.16.3 + '@firebase/app-compat': 0.5.19 '@firebase/component': 0.7.5 '@firebase/util': 1.15.3 tslib: 2.8.1 '@firebase/analytics-types@0.8.5': {} - '@firebase/analytics@0.10.25(@firebase/app@0.16.2)': + '@firebase/analytics@0.10.25(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 + '@firebase/app': 0.16.3 '@firebase/component': 0.7.5 - '@firebase/installations': 0.6.24(@firebase/app@0.16.2) + '@firebase/installations': 0.6.24(@firebase/app@0.16.3) '@firebase/logger': 0.5.2 '@firebase/util': 1.15.3 tslib: 2.8.1 - '@firebase/app-check-compat@0.4.7(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2)': + '@firebase/app-check-compat@0.4.7(@firebase/app-compat@0.5.19)(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 - '@firebase/app-check': 0.13.1(@firebase/app@0.16.2) + '@firebase/app': 0.16.3 + '@firebase/app-check': 0.13.1(@firebase/app@0.16.3) '@firebase/app-check-types': 0.5.5 - '@firebase/app-compat': 0.5.18 + '@firebase/app-compat': 0.5.19 '@firebase/component': 0.7.5 '@firebase/logger': 0.5.2 '@firebase/util': 1.15.3 @@ -9975,17 +9927,17 @@ snapshots: '@firebase/app-check-types@0.5.5': {} - '@firebase/app-check@0.13.1(@firebase/app@0.16.2)': + '@firebase/app-check@0.13.1(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 + '@firebase/app': 0.16.3 '@firebase/component': 0.7.5 '@firebase/logger': 0.5.2 '@firebase/util': 1.15.3 tslib: 2.8.1 - '@firebase/app-compat@0.5.18': + '@firebase/app-compat@0.5.19': dependencies: - '@firebase/app': 0.16.2 + '@firebase/app': 0.16.3 '@firebase/component': 0.7.5 '@firebase/logger': 0.5.2 '@firebase/util': 1.15.3 @@ -9995,7 +9947,7 @@ snapshots: dependencies: '@firebase/logger': 0.5.2 - '@firebase/app@0.16.2': + '@firebase/app@0.16.3': dependencies: '@firebase/component': 0.7.5 '@firebase/logger': 0.5.2 @@ -10003,11 +9955,11 @@ snapshots: idb: 7.1.1 tslib: 2.8.1 - '@firebase/auth-compat@0.6.11(@firebase/app-compat@0.5.18)(@firebase/app-types@0.9.6)(@firebase/app@0.16.2)': + '@firebase/auth-compat@0.6.12(@firebase/app-compat@0.5.19)(@firebase/app-types@0.9.6)(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 - '@firebase/app-compat': 0.5.18 - '@firebase/auth': 1.13.6(@firebase/app@0.16.2) + '@firebase/app': 0.16.3 + '@firebase/app-compat': 0.5.19 + '@firebase/auth': 1.13.7(@firebase/app@0.16.3) '@firebase/auth-types': 0.13.2(@firebase/app-types@0.9.6)(@firebase/util@1.15.3) '@firebase/component': 0.7.5 '@firebase/util': 1.15.3 @@ -10023,9 +9975,9 @@ snapshots: '@firebase/app-types': 0.9.6 '@firebase/util': 1.15.3 - '@firebase/auth@1.13.6(@firebase/app@0.16.2)': + '@firebase/auth@1.13.7(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 + '@firebase/app': 0.16.3 '@firebase/component': 0.7.5 '@firebase/logger': 0.5.2 '@firebase/util': 1.15.3 @@ -10036,16 +9988,16 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 - '@firebase/data-connect@0.7.4(@firebase/app@0.16.2)': + '@firebase/data-connect@0.7.4(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 + '@firebase/app': 0.16.3 '@firebase/auth-interop-types': 0.2.6 '@firebase/component': 0.7.5 '@firebase/logger': 0.5.2 '@firebase/util': 1.15.3 tslib: 2.8.1 - '@firebase/database-compat@2.1.7(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2)': + '@firebase/database-compat@2.1.7(@firebase/app-compat@0.5.19)(@firebase/app@0.16.3)': dependencies: '@firebase/component': 0.7.5 '@firebase/database': 1.1.5 @@ -10054,8 +10006,8 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 optionalDependencies: - '@firebase/app': 0.16.2 - '@firebase/app-compat': 0.5.18 + '@firebase/app': 0.16.3 + '@firebase/app-compat': 0.5.19 '@firebase/database-types@1.0.22': dependencies: @@ -10072,12 +10024,12 @@ snapshots: faye-websocket: 0.11.4 tslib: 2.8.1 - '@firebase/firestore-compat@0.4.14(@firebase/app-compat@0.5.18)(@firebase/app-types@0.9.6)(@firebase/app@0.16.2)': + '@firebase/firestore-compat@0.4.15(@firebase/app-compat@0.5.19)(@firebase/app-types@0.9.6)(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 - '@firebase/app-compat': 0.5.18 + '@firebase/app': 0.16.3 + '@firebase/app-compat': 0.5.19 '@firebase/component': 0.7.5 - '@firebase/firestore': 4.17.2(@firebase/app@0.16.2) + '@firebase/firestore': 4.18.0(@firebase/app@0.16.3) '@firebase/firestore-types': 3.0.5(@firebase/app-types@0.9.6)(@firebase/util@1.15.3) '@firebase/util': 1.15.3 tslib: 2.8.1 @@ -10089,9 +10041,9 @@ snapshots: '@firebase/app-types': 0.9.6 '@firebase/util': 1.15.3 - '@firebase/firestore@4.17.2(@firebase/app@0.16.2)': + '@firebase/firestore@4.18.0(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 + '@firebase/app': 0.16.3 '@firebase/component': 0.7.5 '@firebase/logger': 0.5.2 '@firebase/util': 1.15.3 @@ -10101,21 +10053,21 @@ snapshots: re2js: 2.8.6 tslib: 2.8.1 - '@firebase/functions-compat@0.5.0(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2)': + '@firebase/functions-compat@0.5.0(@firebase/app-compat@0.5.19)(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 - '@firebase/app-compat': 0.5.18 + '@firebase/app': 0.16.3 + '@firebase/app-compat': 0.5.19 '@firebase/component': 0.7.5 - '@firebase/functions': 0.14.0(@firebase/app@0.16.2) + '@firebase/functions': 0.14.0(@firebase/app@0.16.3) '@firebase/functions-types': 0.6.5 '@firebase/util': 1.15.3 tslib: 2.8.1 '@firebase/functions-types@0.6.5': {} - '@firebase/functions@0.14.0(@firebase/app@0.16.2)': + '@firebase/functions@0.14.0(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 + '@firebase/app': 0.16.3 '@firebase/app-check-interop-types': 0.3.5 '@firebase/auth-interop-types': 0.2.6 '@firebase/component': 0.7.5 @@ -10123,12 +10075,12 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 - '@firebase/installations-compat@0.2.24(@firebase/app-compat@0.5.18)(@firebase/app-types@0.9.6)(@firebase/app@0.16.2)': + '@firebase/installations-compat@0.2.24(@firebase/app-compat@0.5.19)(@firebase/app-types@0.9.6)(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 - '@firebase/app-compat': 0.5.18 + '@firebase/app': 0.16.3 + '@firebase/app-compat': 0.5.19 '@firebase/component': 0.7.5 - '@firebase/installations': 0.6.24(@firebase/app@0.16.2) + '@firebase/installations': 0.6.24(@firebase/app@0.16.3) '@firebase/installations-types': 0.5.5(@firebase/app-types@0.9.6) '@firebase/util': 1.15.3 tslib: 2.8.1 @@ -10139,9 +10091,9 @@ snapshots: dependencies: '@firebase/app-types': 0.9.6 - '@firebase/installations@0.6.24(@firebase/app@0.16.2)': + '@firebase/installations@0.6.24(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 + '@firebase/app': 0.16.3 '@firebase/component': 0.7.5 '@firebase/util': 1.15.3 idb: 7.1.1 @@ -10151,78 +10103,78 @@ snapshots: dependencies: tslib: 2.8.1 - '@firebase/messaging-compat@0.2.30(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2)': + '@firebase/messaging-compat@0.2.30(@firebase/app-compat@0.5.19)(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 - '@firebase/app-compat': 0.5.18 + '@firebase/app': 0.16.3 + '@firebase/app-compat': 0.5.19 '@firebase/component': 0.7.5 - '@firebase/messaging': 0.13.3(@firebase/app@0.16.2) + '@firebase/messaging': 0.13.3(@firebase/app@0.16.3) '@firebase/util': 1.15.3 tslib: 2.8.1 '@firebase/messaging-interop-types@0.2.6': {} - '@firebase/messaging@0.13.3(@firebase/app@0.16.2)': + '@firebase/messaging@0.13.3(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 + '@firebase/app': 0.16.3 '@firebase/component': 0.7.5 - '@firebase/installations': 0.6.24(@firebase/app@0.16.2) + '@firebase/installations': 0.6.24(@firebase/app@0.16.3) '@firebase/messaging-interop-types': 0.2.6 '@firebase/util': 1.15.3 idb: 7.1.1 tslib: 2.8.1 - '@firebase/performance-compat@0.2.27(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2)': + '@firebase/performance-compat@0.2.27(@firebase/app-compat@0.5.19)(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 - '@firebase/app-compat': 0.5.18 + '@firebase/app': 0.16.3 + '@firebase/app-compat': 0.5.19 '@firebase/component': 0.7.5 '@firebase/logger': 0.5.2 - '@firebase/performance': 0.7.14(@firebase/app@0.16.2) + '@firebase/performance': 0.7.14(@firebase/app@0.16.3) '@firebase/performance-types': 0.2.5 '@firebase/util': 1.15.3 tslib: 2.8.1 '@firebase/performance-types@0.2.5': {} - '@firebase/performance@0.7.14(@firebase/app@0.16.2)': + '@firebase/performance@0.7.14(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 + '@firebase/app': 0.16.3 '@firebase/component': 0.7.5 - '@firebase/installations': 0.6.24(@firebase/app@0.16.2) + '@firebase/installations': 0.6.24(@firebase/app@0.16.3) '@firebase/logger': 0.5.2 '@firebase/util': 1.15.3 tslib: 2.8.1 web-vitals: 4.2.4 - '@firebase/remote-config-compat@0.2.29(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2)': + '@firebase/remote-config-compat@0.2.30(@firebase/app-compat@0.5.19)(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 - '@firebase/app-compat': 0.5.18 + '@firebase/app': 0.16.3 + '@firebase/app-compat': 0.5.19 '@firebase/component': 0.7.5 '@firebase/logger': 0.5.2 - '@firebase/remote-config': 0.9.2(@firebase/app@0.16.2) + '@firebase/remote-config': 0.9.3(@firebase/app@0.16.3) '@firebase/remote-config-types': 0.5.2 '@firebase/util': 1.15.3 tslib: 2.8.1 '@firebase/remote-config-types@0.5.2': {} - '@firebase/remote-config@0.9.2(@firebase/app@0.16.2)': + '@firebase/remote-config@0.9.3(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 + '@firebase/app': 0.16.3 '@firebase/component': 0.7.5 - '@firebase/installations': 0.6.24(@firebase/app@0.16.2) + '@firebase/installations': 0.6.24(@firebase/app@0.16.3) '@firebase/logger': 0.5.2 '@firebase/util': 1.15.3 tslib: 2.8.1 - '@firebase/storage-compat@0.4.5(@firebase/app-compat@0.5.18)(@firebase/app-types@0.9.6)(@firebase/app@0.16.2)': + '@firebase/storage-compat@0.4.6(@firebase/app-compat@0.5.19)(@firebase/app-types@0.9.6)(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 - '@firebase/app-compat': 0.5.18 + '@firebase/app': 0.16.3 + '@firebase/app-compat': 0.5.19 '@firebase/component': 0.7.5 - '@firebase/storage': 0.14.5(@firebase/app@0.16.2) + '@firebase/storage': 0.14.6(@firebase/app@0.16.3) '@firebase/storage-types': 0.8.5(@firebase/app-types@0.9.6)(@firebase/util@1.15.3) '@firebase/util': 1.15.3 tslib: 2.8.1 @@ -10234,9 +10186,9 @@ snapshots: '@firebase/app-types': 0.9.6 '@firebase/util': 1.15.3 - '@firebase/storage@0.14.5(@firebase/app@0.16.2)': + '@firebase/storage@0.14.6(@firebase/app@0.16.3)': dependencies: - '@firebase/app': 0.16.2 + '@firebase/app': 0.16.3 '@firebase/component': 0.7.5 '@firebase/util': 1.15.3 tslib: 2.8.1 @@ -10308,7 +10260,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@google/genai@2.25.0(bufferutil@4.1.0)(supports-color@11.0.0)(utf-8-validate@6.0.6)': + '@google/genai@2.28.0(bufferutil@4.1.0)(supports-color@11.0.0)(utf-8-validate@6.0.6)': dependencies: google-auth-library: 10.9.1(supports-color@11.0.0) p-retry: 4.6.2 @@ -10373,21 +10325,14 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/checkbox@5.2.6(@types/node@24.19.0)': + '@inquirer/checkbox@5.2.6(@types/node@24.19.1)': dependencies: '@inquirer/ansi': 2.0.9 - '@inquirer/core': 12.0.4(@types/node@24.19.0) + '@inquirer/core': 12.0.4(@types/node@24.19.1) '@inquirer/figures': 2.0.9 - '@inquirer/type': 4.2.0(@types/node@24.19.0) - optionalDependencies: - '@types/node': 24.19.0 - - '@inquirer/confirm@6.3.2(@types/node@24.19.0)': - dependencies: - '@inquirer/core': 12.0.4(@types/node@24.19.0) - '@inquirer/type': 4.1.1(@types/node@24.19.0) + '@inquirer/type': 4.2.0(@types/node@24.19.1) optionalDependencies: - '@types/node': 24.19.0 + '@types/node': 24.19.1 '@inquirer/confirm@6.3.3(@types/node@22.20.5)': dependencies: @@ -10396,6 +10341,13 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 + '@inquirer/confirm@6.3.3(@types/node@24.19.1)': + dependencies: + '@inquirer/core': 12.0.4(@types/node@24.19.1) + '@inquirer/type': 4.2.0(@types/node@24.19.1) + optionalDependencies: + '@types/node': 24.19.1 + '@inquirer/core@12.0.4(@types/node@22.20.5)': dependencies: '@inquirer/ansi': 2.0.9 @@ -10408,17 +10360,17 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/core@12.0.4(@types/node@24.19.0)': + '@inquirer/core@12.0.4(@types/node@24.19.1)': dependencies: '@inquirer/ansi': 2.0.9 '@inquirer/figures': 2.0.9 - '@inquirer/type': 4.2.0(@types/node@24.19.0) + '@inquirer/type': 4.2.0(@types/node@24.19.1) cli-width: 4.1.0 fast-wrap-ansi: 0.2.2 mute-stream: 3.0.0 signal-exit: 4.1.0 optionalDependencies: - '@types/node': 24.19.0 + '@types/node': 24.19.1 '@inquirer/editor@5.3.4(@types/node@22.20.5)': dependencies: @@ -10428,13 +10380,13 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/editor@5.3.4(@types/node@24.19.0)': + '@inquirer/editor@5.3.4(@types/node@24.19.1)': dependencies: - '@inquirer/core': 12.0.4(@types/node@24.19.0) - '@inquirer/external-editor': 3.0.6(@types/node@24.19.0) - '@inquirer/type': 4.2.0(@types/node@24.19.0) + '@inquirer/core': 12.0.4(@types/node@24.19.1) + '@inquirer/external-editor': 3.0.6(@types/node@24.19.1) + '@inquirer/type': 4.2.0(@types/node@24.19.1) optionalDependencies: - '@types/node': 24.19.0 + '@types/node': 24.19.1 '@inquirer/expand@5.1.6(@types/node@22.20.5)': dependencies: @@ -10443,12 +10395,12 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/expand@5.1.6(@types/node@24.19.0)': + '@inquirer/expand@5.1.6(@types/node@24.19.1)': dependencies: - '@inquirer/core': 12.0.4(@types/node@24.19.0) - '@inquirer/type': 4.2.0(@types/node@24.19.0) + '@inquirer/core': 12.0.4(@types/node@24.19.1) + '@inquirer/type': 4.2.0(@types/node@24.19.1) optionalDependencies: - '@types/node': 24.19.0 + '@types/node': 24.19.1 '@inquirer/external-editor@3.0.6(@types/node@22.20.5)': dependencies: @@ -10457,12 +10409,12 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/external-editor@3.0.6(@types/node@24.19.0)': + '@inquirer/external-editor@3.0.6(@types/node@24.19.1)': dependencies: chardet: 2.2.0 iconv-lite: 0.7.3 optionalDependencies: - '@types/node': 24.19.0 + '@types/node': 24.19.1 '@inquirer/figures@2.0.9': {} @@ -10473,12 +10425,12 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/input@5.1.7(@types/node@24.19.0)': + '@inquirer/input@5.1.7(@types/node@24.19.1)': dependencies: - '@inquirer/core': 12.0.4(@types/node@24.19.0) - '@inquirer/type': 4.2.0(@types/node@24.19.0) + '@inquirer/core': 12.0.4(@types/node@24.19.1) + '@inquirer/type': 4.2.0(@types/node@24.19.1) optionalDependencies: - '@types/node': 24.19.0 + '@types/node': 24.19.1 '@inquirer/number@4.2.4(@types/node@22.20.5)': dependencies: @@ -10487,12 +10439,12 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/number@4.2.4(@types/node@24.19.0)': + '@inquirer/number@4.2.4(@types/node@24.19.1)': dependencies: - '@inquirer/core': 12.0.4(@types/node@24.19.0) - '@inquirer/type': 4.2.0(@types/node@24.19.0) + '@inquirer/core': 12.0.4(@types/node@24.19.1) + '@inquirer/type': 4.2.0(@types/node@24.19.1) optionalDependencies: - '@types/node': 24.19.0 + '@types/node': 24.19.1 '@inquirer/password@5.2.3(@types/node@22.20.5)': dependencies: @@ -10502,28 +10454,13 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/password@5.2.3(@types/node@24.19.0)': + '@inquirer/password@5.2.3(@types/node@24.19.1)': dependencies: '@inquirer/ansi': 2.0.9 - '@inquirer/core': 12.0.4(@types/node@24.19.0) - '@inquirer/type': 4.2.0(@types/node@24.19.0) + '@inquirer/core': 12.0.4(@types/node@24.19.1) + '@inquirer/type': 4.2.0(@types/node@24.19.1) optionalDependencies: - '@types/node': 24.19.0 - - '@inquirer/prompts@8.7.2(@types/node@24.19.0)': - dependencies: - '@inquirer/checkbox': 5.2.6(@types/node@24.19.0) - '@inquirer/confirm': 6.3.2(@types/node@24.19.0) - '@inquirer/editor': 5.3.4(@types/node@24.19.0) - '@inquirer/expand': 5.1.6(@types/node@24.19.0) - '@inquirer/input': 5.1.7(@types/node@24.19.0) - '@inquirer/number': 4.2.4(@types/node@24.19.0) - '@inquirer/password': 5.2.3(@types/node@24.19.0) - '@inquirer/rawlist': 5.3.6(@types/node@24.19.0) - '@inquirer/search': 4.3.4(@types/node@24.19.0) - '@inquirer/select': 5.2.6(@types/node@24.19.0) - optionalDependencies: - '@types/node': 24.19.0 + '@types/node': 24.19.1 '@inquirer/prompts@8.7.3(@types/node@22.20.5)': dependencies: @@ -10540,6 +10477,21 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 + '@inquirer/prompts@8.7.3(@types/node@24.19.1)': + dependencies: + '@inquirer/checkbox': 5.2.6(@types/node@24.19.1) + '@inquirer/confirm': 6.3.3(@types/node@24.19.1) + '@inquirer/editor': 5.3.4(@types/node@24.19.1) + '@inquirer/expand': 5.1.6(@types/node@24.19.1) + '@inquirer/input': 5.1.7(@types/node@24.19.1) + '@inquirer/number': 4.2.4(@types/node@24.19.1) + '@inquirer/password': 5.2.3(@types/node@24.19.1) + '@inquirer/rawlist': 5.3.6(@types/node@24.19.1) + '@inquirer/search': 4.3.4(@types/node@24.19.1) + '@inquirer/select': 5.2.6(@types/node@24.19.1) + optionalDependencies: + '@types/node': 24.19.1 + '@inquirer/rawlist@5.3.6(@types/node@22.20.5)': dependencies: '@inquirer/core': 12.0.4(@types/node@22.20.5) @@ -10547,12 +10499,12 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/rawlist@5.3.6(@types/node@24.19.0)': + '@inquirer/rawlist@5.3.6(@types/node@24.19.1)': dependencies: - '@inquirer/core': 12.0.4(@types/node@24.19.0) - '@inquirer/type': 4.2.0(@types/node@24.19.0) + '@inquirer/core': 12.0.4(@types/node@24.19.1) + '@inquirer/type': 4.2.0(@types/node@24.19.1) optionalDependencies: - '@types/node': 24.19.0 + '@types/node': 24.19.1 '@inquirer/search@4.3.4(@types/node@22.20.5)': dependencies: @@ -10562,13 +10514,13 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/search@4.3.4(@types/node@24.19.0)': + '@inquirer/search@4.3.4(@types/node@24.19.1)': dependencies: - '@inquirer/core': 12.0.4(@types/node@24.19.0) + '@inquirer/core': 12.0.4(@types/node@24.19.1) '@inquirer/figures': 2.0.9 - '@inquirer/type': 4.2.0(@types/node@24.19.0) + '@inquirer/type': 4.2.0(@types/node@24.19.1) optionalDependencies: - '@types/node': 24.19.0 + '@types/node': 24.19.1 '@inquirer/select@5.2.6(@types/node@22.20.5)': dependencies: @@ -10579,26 +10531,22 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/select@5.2.6(@types/node@24.19.0)': + '@inquirer/select@5.2.6(@types/node@24.19.1)': dependencies: '@inquirer/ansi': 2.0.9 - '@inquirer/core': 12.0.4(@types/node@24.19.0) + '@inquirer/core': 12.0.4(@types/node@24.19.1) '@inquirer/figures': 2.0.9 - '@inquirer/type': 4.2.0(@types/node@24.19.0) + '@inquirer/type': 4.2.0(@types/node@24.19.1) optionalDependencies: - '@types/node': 24.19.0 - - '@inquirer/type@4.1.1(@types/node@24.19.0)': - optionalDependencies: - '@types/node': 24.19.0 + '@types/node': 24.19.1 '@inquirer/type@4.2.0(@types/node@22.20.5)': optionalDependencies: '@types/node': 22.20.5 - '@inquirer/type@4.2.0(@types/node@24.19.0)': + '@inquirer/type@4.2.0(@types/node@24.19.1)': optionalDependencies: - '@types/node': 24.19.0 + '@types/node': 24.19.1 '@isaacs/cliui@8.0.2': dependencies: @@ -10838,14 +10786,16 @@ snapshots: '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4': optional: true - '@mswjs/interceptors@0.41.9': + '@mswjs/interceptors@0.44.0(supports-color@11.0.0)': dependencies: - '@open-draft/deferred-promise': 2.2.0 - '@open-draft/logger': 0.3.0 - '@open-draft/until': 2.1.0 + '@open-draft/until': 3.0.1 + '@types/debug': 4.1.13 + debug: 4.4.3(supports-color@11.0.0) is-node-process: 1.2.0 outvariant: 1.4.3 - strict-event-emitter: 0.5.1 + rettime: 0.11.12 + transitivePeerDependencies: + - supports-color '@napi-rs/lzma-linux-x64-gnu@1.5.1': optional: true @@ -11018,11 +10968,6 @@ snapshots: '@octokit/core': 7.0.8 '@octokit/types': 16.0.0 - '@octokit/plugin-paginate-rest@15.0.0(@octokit/core@7.0.8)': - dependencies: - '@octokit/core': 7.0.8 - '@octokit/types': 17.0.0 - '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.8)': dependencies: '@octokit/core': 7.0.8 @@ -11069,14 +11014,7 @@ snapshots: dependencies: '@octokit/openapi-types': 29.0.1 - '@open-draft/deferred-promise@2.2.0': {} - - '@open-draft/logger@0.3.0': - dependencies: - is-node-process: 1.2.0 - outvariant: 1.4.3 - - '@open-draft/until@2.1.0': {} + '@open-draft/until@3.0.1': {} '@opentelemetry/api@1.9.1': {} @@ -11635,6 +11573,10 @@ snapshots: dependencies: '@types/node': 22.20.5 + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + '@types/deep-eql@4.0.2': {} '@types/duplexify@3.6.5': @@ -11724,11 +11666,13 @@ snapshots: dependencies: '@types/parse-glob': 3.0.32 + '@types/ms@2.1.0': {} + '@types/node@22.20.5': dependencies: undici-types: 6.21.0 - '@types/node@24.19.0': + '@types/node@24.19.1': dependencies: undici-types: 7.24.6 @@ -12904,7 +12848,7 @@ snapshots: conventional-commits-filter@6.0.1: {} - conventional-commits-parser@7.1.2: + conventional-commits-parser@7.1.3: dependencies: '@simple-libs/stream-utils': 2.0.0 argue-cli: 3.2.0 @@ -13039,12 +12983,6 @@ snapshots: optionalDependencies: supports-color: 11.0.0 - debug@4.4.0(supports-color@11.0.0): - dependencies: - ms: 2.1.3 - optionalDependencies: - supports-color: 11.0.0 - debug@4.4.3(supports-color@11.0.0): dependencies: ms: 2.1.3 @@ -13732,35 +13670,35 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 - firebase@12.19.0: + firebase@13.0.0: dependencies: - '@firebase/ai': 2.16.0(@firebase/app-types@0.9.6)(@firebase/app@0.16.2) - '@firebase/analytics': 0.10.25(@firebase/app@0.16.2) - '@firebase/analytics-compat': 0.2.31(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2) - '@firebase/app': 0.16.2 - '@firebase/app-check': 0.13.1(@firebase/app@0.16.2) - '@firebase/app-check-compat': 0.4.7(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2) - '@firebase/app-compat': 0.5.18 + '@firebase/ai': 3.0.0(@firebase/app-types@0.9.6)(@firebase/app@0.16.3) + '@firebase/analytics': 0.10.25(@firebase/app@0.16.3) + '@firebase/analytics-compat': 0.2.31(@firebase/app-compat@0.5.19)(@firebase/app@0.16.3) + '@firebase/app': 0.16.3 + '@firebase/app-check': 0.13.1(@firebase/app@0.16.3) + '@firebase/app-check-compat': 0.4.7(@firebase/app-compat@0.5.19)(@firebase/app@0.16.3) + '@firebase/app-compat': 0.5.19 '@firebase/app-types': 0.9.6 - '@firebase/auth': 1.13.6(@firebase/app@0.16.2) - '@firebase/auth-compat': 0.6.11(@firebase/app-compat@0.5.18)(@firebase/app-types@0.9.6)(@firebase/app@0.16.2) - '@firebase/data-connect': 0.7.4(@firebase/app@0.16.2) + '@firebase/auth': 1.13.7(@firebase/app@0.16.3) + '@firebase/auth-compat': 0.6.12(@firebase/app-compat@0.5.19)(@firebase/app-types@0.9.6)(@firebase/app@0.16.3) + '@firebase/data-connect': 0.7.4(@firebase/app@0.16.3) '@firebase/database': 1.1.5 - '@firebase/database-compat': 2.1.7(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2) - '@firebase/firestore': 4.17.2(@firebase/app@0.16.2) - '@firebase/firestore-compat': 0.4.14(@firebase/app-compat@0.5.18)(@firebase/app-types@0.9.6)(@firebase/app@0.16.2) - '@firebase/functions': 0.14.0(@firebase/app@0.16.2) - '@firebase/functions-compat': 0.5.0(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2) - '@firebase/installations': 0.6.24(@firebase/app@0.16.2) - '@firebase/installations-compat': 0.2.24(@firebase/app-compat@0.5.18)(@firebase/app-types@0.9.6)(@firebase/app@0.16.2) - '@firebase/messaging': 0.13.3(@firebase/app@0.16.2) - '@firebase/messaging-compat': 0.2.30(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2) - '@firebase/performance': 0.7.14(@firebase/app@0.16.2) - '@firebase/performance-compat': 0.2.27(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2) - '@firebase/remote-config': 0.9.2(@firebase/app@0.16.2) - '@firebase/remote-config-compat': 0.2.29(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2) - '@firebase/storage': 0.14.5(@firebase/app@0.16.2) - '@firebase/storage-compat': 0.4.5(@firebase/app-compat@0.5.18)(@firebase/app-types@0.9.6)(@firebase/app@0.16.2) + '@firebase/database-compat': 2.1.7(@firebase/app-compat@0.5.19)(@firebase/app@0.16.3) + '@firebase/firestore': 4.18.0(@firebase/app@0.16.3) + '@firebase/firestore-compat': 0.4.15(@firebase/app-compat@0.5.19)(@firebase/app-types@0.9.6)(@firebase/app@0.16.3) + '@firebase/functions': 0.14.0(@firebase/app@0.16.3) + '@firebase/functions-compat': 0.5.0(@firebase/app-compat@0.5.19)(@firebase/app@0.16.3) + '@firebase/installations': 0.6.24(@firebase/app@0.16.3) + '@firebase/installations-compat': 0.2.24(@firebase/app-compat@0.5.19)(@firebase/app-types@0.9.6)(@firebase/app@0.16.3) + '@firebase/messaging': 0.13.3(@firebase/app@0.16.3) + '@firebase/messaging-compat': 0.2.30(@firebase/app-compat@0.5.19)(@firebase/app@0.16.3) + '@firebase/performance': 0.7.14(@firebase/app@0.16.3) + '@firebase/performance-compat': 0.2.27(@firebase/app-compat@0.5.19)(@firebase/app@0.16.3) + '@firebase/remote-config': 0.9.3(@firebase/app@0.16.3) + '@firebase/remote-config-compat': 0.2.30(@firebase/app-compat@0.5.19)(@firebase/app@0.16.3) + '@firebase/storage': 0.14.6(@firebase/app@0.16.3) + '@firebase/storage-compat': 0.4.6(@firebase/app-compat@0.5.19)(@firebase/app-types@0.9.6)(@firebase/app@0.16.3) '@firebase/util': 1.15.3 transitivePeerDependencies: - '@react-native-async-storage/async-storage' @@ -13777,9 +13715,9 @@ snapshots: flru@1.0.2: {} - folder-hash@4.1.3(supports-color@11.0.0): + folder-hash@4.1.4(supports-color@11.0.0): dependencies: - debug: 4.4.0(supports-color@11.0.0) + debug: 4.4.3(supports-color@11.0.0) minimatch: 7.4.9 transitivePeerDependencies: - supports-color @@ -15183,11 +15121,11 @@ snapshots: - supports-color - vue-tsc - nock@14.0.17: + nock@15.0.1(supports-color@11.0.0): dependencies: - '@mswjs/interceptors': 0.41.9 - json-stringify-safe: 5.0.1 - propagate: 2.0.1 + '@mswjs/interceptors': 0.44.0(supports-color@11.0.0) + transitivePeerDependencies: + - supports-color node-addon-api@6.1.0: optional: true @@ -15610,8 +15548,6 @@ snapshots: process@0.11.10: {} - propagate@2.0.1: {} - proto3-json-serializer@3.0.4: dependencies: protobufjs: 7.6.6 @@ -15888,6 +15824,8 @@ snapshots: retry@0.13.1: {} + rettime@0.11.12: {} + reusify@1.1.0: {} rfdc@1.4.1: {} @@ -16484,8 +16422,6 @@ snapshots: - bare-abort-controller - react-native-b4a - strict-event-emitter@0.5.1: {} - string-width@4.2.3: dependencies: emoji-regex: 8.0.0 diff --git a/tests/e2e/ng-snapshot/package.json b/tests/e2e/ng-snapshot/package.json index a3e554ca1640..7bf474571ca6 100644 --- a/tests/e2e/ng-snapshot/package.json +++ b/tests/e2e/ng-snapshot/package.json @@ -2,21 +2,21 @@ "description": "snapshot versions of Angular for e2e testing", "private": true, "dependencies": { - "@angular/animations": "github:angular/animations-builds#3ec405d1cb11a6f18eacdd7e09378cd097a9a427", - "@angular/cdk": "github:angular/cdk-builds#8eedcdb798ec78b2c0191953b46804f54296ed4f", - "@angular/common": "github:angular/common-builds#bae1a4226a83f02bcb77b6ef447e039d8b5081f3", - "@angular/compiler": "github:angular/compiler-builds#fc8fced0b21574f7846b999a751511f9a453e0cd", - "@angular/compiler-cli": "github:angular/compiler-cli-builds#20b42c8d2e12f28eea2376ff0b0f1f5ec59cac63", - "@angular/core": "github:angular/core-builds#080d86fc456c2029952d72e43ae5e019374a3546", - "@angular/forms": "github:angular/forms-builds#b8ff96856639a22bb3dec5c8bebb562c5395c638", - "@angular/language-service": "github:angular/language-service-builds#9e0a5e50a0f37d5671fc2478ebf2626399fb23f4", - "@angular/localize": "github:angular/localize-builds#fec5dc5c69698fbf47aa794ac8fd80a2baa9b1d5", - "@angular/material": "github:angular/material-builds#72d50c0fd59ea4d1f7fc2053d74d4f2610503730", - "@angular/material-moment-adapter": "github:angular/material-moment-adapter-builds#30012ad773e0536aa4e5ff009c1b65ec8bb1e5f2", - "@angular/platform-browser": "github:angular/platform-browser-builds#ca08a1a24ac892344fb1f69c6f5ac15eb504370b", - "@angular/platform-browser-dynamic": "github:angular/platform-browser-dynamic-builds#163f8f1af3365efeab12b2656ad229a8d76e39b9", - "@angular/platform-server": "github:angular/platform-server-builds#fe61afa721e53041b0bac92f0241a82326d72a47", - "@angular/router": "github:angular/router-builds#7df611a733d4a35d41fd4b5596e0a9800cc67e8e", - "@angular/service-worker": "github:angular/service-worker-builds#3ef11b4fbbd965535f0f45de2ba41a4e3886b918" + "@angular/animations": "github:angular/animations-builds#49e5662e0f5a6a052d8b66bd639ce261b231c807", + "@angular/cdk": "github:angular/cdk-builds#8aa05501715c9b9b0fc95625f52b3b536c35cc4a", + "@angular/common": "github:angular/common-builds#e75bc632bb0f4c992336add2cd9429a5fc580165", + "@angular/compiler": "github:angular/compiler-builds#12aa4df6f3b1bc8402d329301391ab4f52179111", + "@angular/compiler-cli": "github:angular/compiler-cli-builds#051fd3767d2922649e6630cdbd4d726e99900949", + "@angular/core": "github:angular/core-builds#7b84cd24ec45174b8cc0a42e821a98b1a0d330eb", + "@angular/forms": "github:angular/forms-builds#fea1091472626b0c62c1300a4822216a55092cf6", + "@angular/language-service": "github:angular/language-service-builds#60d0bc6afa8bba745ba051afb88a8ccc6d72f61d", + "@angular/localize": "github:angular/localize-builds#5f21029e84cf4fab2902818b5351a9b131cef532", + "@angular/material": "github:angular/material-builds#5f4d7a4724a306e1e24d55f53564eebfa22dbdd4", + "@angular/material-moment-adapter": "github:angular/material-moment-adapter-builds#a600a485f5c91b376684763cbf00b158f85502f0", + "@angular/platform-browser": "github:angular/platform-browser-builds#69be31f21a8df04fd8157676b7d885c94de8bdc6", + "@angular/platform-browser-dynamic": "github:angular/platform-browser-dynamic-builds#f8c0d0c407dd393e8f49593039ae2100f4504e11", + "@angular/platform-server": "github:angular/platform-server-builds#8e9d51d325c6575b54e118410281b6ffb2bd76a9", + "@angular/router": "github:angular/router-builds#42ae1c53acc2bcf444ef4d4d3e84ccdda61486db", + "@angular/service-worker": "github:angular/service-worker-builds#5ac1b5c6526c04ac8d1ba1e74f22f9998020eaf7" } } From 47c328d3ef7b409af02f270a48f5e99a520fbe14 Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Mon, 12 Oct 2026 22:45:00 +0200 Subject: [PATCH 11/52] fix(@angular/build): ensure Sass importers return global Promise instances `sass-embedded` checks whether an importer's `canonicalize` or `findFileUrl` method returned a promise using `result instanceof Promise`. When SSR executes in the same process during `ng serve` for an application using Zone.js, `zone.js/node` replaces `globalThis.Promise` with `ZoneAwarePromise`. Because native V8 `async` functions always return instances of the intrinsic V8 `%Promise%` rather than `globalThis.Promise`, `result instanceof Promise` evaluates to `false` and `sass-embedded` treats the returned Promise as a synchronous URL value (`"[object Promise]"` / `"%5Bobject%20Promise%5D"`). --- .../esbuild/stylesheets/sass-language_spec.ts | 64 +++++++++++++++++++ .../build/src/tools/sass/rebasing-importer.ts | 12 ++-- 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/packages/angular/build/src/tools/esbuild/stylesheets/sass-language_spec.ts b/packages/angular/build/src/tools/esbuild/stylesheets/sass-language_spec.ts index cdd4d7e7c8db..216a2d18fc47 100644 --- a/packages/angular/build/src/tools/esbuild/stylesheets/sass-language_spec.ts +++ b/packages/angular/build/src/tools/esbuild/stylesheets/sass-language_spec.ts @@ -286,5 +286,69 @@ describe('sass-language', () => { pathToFileURL(join(projectRoot, 'node_modules', 'theme', '_index.scss')).href, ); }); + + it('should resolve imports when globalThis.Promise is replaced (e.g., by Zone.js)', async () => { + const originalPromise = globalThis.Promise; + + // Simulate Zone.js replacing globalThis.Promise with a constructor where + // native V8 async function return values fail `instanceof globalThis.Promise`. + class ZoneLikePromise { + #inner: Promise; + + constructor( + executor: ( + resolve: (value: T | PromiseLike) => void, + reject: (reason?: unknown) => void, + ) => void, + ) { + this.#inner = new originalPromise(executor); + } + + then( + onfulfilled?: ((value: T) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null, + ): ZoneLikePromise { + return new ZoneLikePromise((resolve, reject) => { + this.#inner.then(onfulfilled, onrejected).then(resolve, reject); + }); + } + + catch( + onrejected?: ((reason: unknown) => TResult | PromiseLike) | null, + ): ZoneLikePromise { + return this.then(undefined, onrejected); + } + + finally(onfinally?: (() => void) | null): ZoneLikePromise { + return new ZoneLikePromise((resolve, reject) => { + this.#inner.finally(onfinally).then(resolve, reject); + }); + } + + static resolve(value?: U | PromiseLike): ZoneLikePromise> { + if (value instanceof ZoneLikePromise) { + return value; + } + + return new ZoneLikePromise((resolve) => resolve(value as Awaited)); + } + + static reject(reason?: unknown): ZoneLikePromise { + return new ZoneLikePromise((_, reject) => reject(reason)); + } + + static all(values: Iterable): ZoneLikePromise { + return ZoneLikePromise.resolve(originalPromise.all(values)); + } + } + + globalThis.Promise = ZoneLikePromise as unknown as PromiseConstructor; + try { + const application = await compile(buttonStylesheet); + expect(application).toContain('content: "project";'); + } finally { + globalThis.Promise = originalPromise; + } + }); }); }); diff --git a/packages/angular/build/src/tools/sass/rebasing-importer.ts b/packages/angular/build/src/tools/sass/rebasing-importer.ts index 7198d8b74f1e..889d26ef567e 100644 --- a/packages/angular/build/src/tools/sass/rebasing-importer.ts +++ b/packages/angular/build/src/tools/sass/rebasing-importer.ts @@ -344,14 +344,18 @@ export class AsyncModuleUrlRebasingImporter implements Importer<'async'> { this.load = this.load.bind(this); } - async canonicalize(url: string, options: CanonicalizeContext): Promise { + canonicalize(url: string, options: CanonicalizeContext): Promise | URL | null { if (url.startsWith('file://')) { return this.relativeImporter.canonicalize(url, options); } - const result = await this.finder(url, options); - - return result ? this.relativeImporter.canonicalize(result.href, options) : null; + // Use `Promise.resolve` instead of an `async` method so the returned promise is an + // instance of the current `globalThis.Promise` (e.g., `ZoneAwarePromise` when Zone.js + // is loaded during SSR). `sass-embedded` checks `result instanceof Promise`, which fails + // for native `async` function return values when `globalThis.Promise` has been replaced. + return Promise.resolve(this.finder(url, options)).then((result) => + result ? this.relativeImporter.canonicalize(result.href, options) : null, + ); } load(canonicalUrl: URL): ImporterResult | null { From 5e0fd4f134967ac879d6f7d34a4b06f69534d0c0 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Mon, 12 Oct 2026 09:14:07 -0400 Subject: [PATCH 12/52] test(@angular/build): verify Vitest fsModuleCache is disabled across test runs Add an integration test to ensure that modifying an imported application module between test runs is reflected even when `fsModuleCache` is explicitly enabled in the Vitest runner configuration, and that the `.vitest-cache` directory is not created. --- .../behavior/runner-config-vitest_spec.ts | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/packages/angular/build/src/builders/unit-test/tests/behavior/runner-config-vitest_spec.ts b/packages/angular/build/src/builders/unit-test/tests/behavior/runner-config-vitest_spec.ts index 95107d1baec2..53039adf53e8 100644 --- a/packages/angular/build/src/builders/unit-test/tests/behavior/runner-config-vitest_spec.ts +++ b/packages/angular/build/src/builders/unit-test/tests/behavior/runner-config-vitest_spec.ts @@ -614,5 +614,43 @@ describeBuilder(execute, UNIT_TEST_BUILDER_INFO, (harness) => { const { result } = await harness.executeOnce(); expect(result?.success).toBeTrue(); }); + + it('should not serve stale cached modules across runs when an imported file changes', async () => { + harness.useTarget('test', { + ...BASE_OPTIONS, + runnerConfig: 'vitest.config.mts', + }); + + await harness.writeFiles({ + 'vitest.config.mts': ` + import { defineConfig } from 'vitest/config'; + export default defineConfig({ + test: { + fsModuleCache: true, + fsModuleCachePath: './.vitest-cache', + }, + }); + `, + 'src/app/value.ts': `export const VALUE = 'initial';`, + 'src/app/app.component.spec.ts': ` + import { test, expect } from 'vitest'; + import { VALUE } from './value'; + + test('should use the latest value from imported module', () => { + expect(VALUE).toBe('updated'); + }); + `, + }); + + const firstRun = await harness.executeOnce(); + expect(firstRun.result?.success).toBeFalse(); + + // Update the imported application file without modifying the .spec.ts file on disk + await harness.writeFile('src/app/value.ts', `export const VALUE = 'updated';`); + + const secondRun = await harness.executeOnce(); + expect(secondRun.result?.success).toBeTrue(); + harness.expectDirectory('.vitest-cache').toNotExist(); + }); }); }); From 0306faf9e4f9b1c746672711fe107e2e2f0bd406 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Mon, 12 Oct 2026 09:25:13 -0400 Subject: [PATCH 13/52] test(@angular/build): await file writes in unit-test watch rebuild spec Ensure `harness.writeFiles` calls inside `executeWithCases` callbacks are awaited so file modifications complete before the next watch cycle. --- .../unit-test/tests/behavior/watch_rebuild_spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/angular/build/src/builders/unit-test/tests/behavior/watch_rebuild_spec.ts b/packages/angular/build/src/builders/unit-test/tests/behavior/watch_rebuild_spec.ts index 6ff753c7eac7..cab5afd48a2c 100644 --- a/packages/angular/build/src/builders/unit-test/tests/behavior/watch_rebuild_spec.ts +++ b/packages/angular/build/src/builders/unit-test/tests/behavior/watch_rebuild_spec.ts @@ -28,11 +28,11 @@ describeBuilder(execute, UNIT_TEST_BUILDER_INFO, (harness) => { await harness.executeWithCases([ // 1. Initial success - ({ result }) => { + async ({ result }) => { expect(result?.success).toBeTrue(); // 2. Introduce compilation error - harness.writeFiles({ + await harness.writeFiles({ 'src/app/app.component.spec.ts': ` import { describe, expect, test } from 'vitest' describe('AppComponent', () => { @@ -44,11 +44,11 @@ describeBuilder(execute, UNIT_TEST_BUILDER_INFO, (harness) => { }); }, // 3. Expect compilation error - ({ result }) => { + async ({ result }) => { expect(result?.success).toBeFalse(); // 4. Fix compilation error BUT introduce test failure - harness.writeFiles({ + await harness.writeFiles({ 'src/app/app.component.spec.ts': ` import { describe, expect, test } from 'vitest' describe('AppComponent', () => { From 39d230e1862f2f626d3fba03bbf51873f3578153 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Mon, 12 Oct 2026 09:37:15 -0400 Subject: [PATCH 14/52] fix(@angular/build): keep Vite server file watcher disabled in Vitest watch mode In Vitest 5, the internal `vitest:config:append` plugin uses a post `configResolved` hook that resets `server.watch` to `{}` when watch mode is enabled (`server.watch ??= {}`), overriding the `server: { watch: null }` setting passed in `vitestServerConfig`. This caused Vite to start a duplicate Chokidar file watcher alongside the Angular CLI build watcher and trigger redundant, racing test reruns on file changes. Enforce `post` ordering on `angular:vitest-configuration` and reset `config.server.watch = null` in a post `configResolved` hook so Vite uses its no-op watcher. --- .../unit-test/runners/vitest/executor.ts | 5 --- .../unit-test/runners/vitest/plugins.ts | 10 ++++++ .../unit-test/tests/options/watch_spec.ts | 33 +++++++++++++++++++ 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/packages/angular/build/src/builders/unit-test/runners/vitest/executor.ts b/packages/angular/build/src/builders/unit-test/runners/vitest/executor.ts index aa201e24c578..b5c7841c799b 100644 --- a/packages/angular/build/src/builders/unit-test/runners/vitest/executor.ts +++ b/packages/angular/build/src/builders/unit-test/runners/vitest/executor.ts @@ -398,11 +398,6 @@ export class VitestExecutor implements TestExecutor { const vitestServerConfig = { // Note `.vitest` is auto appended to the path. cacheDir: cacheOptions.path, - server: { - // Disable the actual file watcher. The boolean watch option above should still - // be enabled as it controls other internal behavior related to rerunning tests. - watch: null, - }, plugins: [ await createVitestConfigPlugin({ browser: browserOptions.browser, diff --git a/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts b/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts index ec0cd0a8f269..0a8a2c8990b4 100644 --- a/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts +++ b/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts @@ -164,6 +164,16 @@ export async function createVitestConfigPlugin( return { name: 'angular:vitest-configuration', + enforce: 'post', + configResolved: { + order: 'post', + handler(config: Vite.ResolvedConfig) { + // Vitest's internal post-configResolved hook resets `server.watch` to `{}` when + // `watch` is enabled (`server.watch ??= {}`). Force it back to `null` so Vite uses + // a no-op watcher and relies solely on the Angular CLI build watcher. + config.server.watch = null; + }, + }, async config(config: UserWorkspaceConfig & Vite.UserConfig) { const testConfig = config.test; diff --git a/packages/angular/build/src/builders/unit-test/tests/options/watch_spec.ts b/packages/angular/build/src/builders/unit-test/tests/options/watch_spec.ts index d1840beb4a96..79e25ca84b27 100644 --- a/packages/angular/build/src/builders/unit-test/tests/options/watch_spec.ts +++ b/packages/angular/build/src/builders/unit-test/tests/options/watch_spec.ts @@ -55,5 +55,38 @@ describeBuilder(execute, UNIT_TEST_BUILDER_INFO, (harness) => { }, ]); }); + + it('should disable the Vite server file watcher when watch is true', async () => { + harness.useTarget('test', { + ...BASE_OPTIONS, + watch: true, + runnerConfig: 'vitest.config.mts', + }); + + await harness.writeFile( + 'vitest.config.mts', + ` + import { defineConfig } from 'vitest/config'; + export default defineConfig({ + plugins: [ + { + name: 'assert-watch-disabled', + configureVitest({ vitest, project }) { + if (vitest.vite.config.server.watch !== null || project.vite.config.server.watch !== null) { + throw new Error('Expected Vite server.watch to be null'); + } + }, + }, + ], + }); + `, + ); + + await harness.executeWithCases([ + ({ result }) => { + expect(result?.success).toBeTrue(); + }, + ]); + }); }); }); From a1cf33bc45882fb74578cc7d1faeba8cecec7b73 Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Tue, 13 Oct 2026 08:00:44 +0200 Subject: [PATCH 15/52] fix(@angular/cli): resolve package name in npm workspace members Read `package.json` in the working directory first in `getCurrentPackageName` to avoid spawning an unnecessary child process, and handle single-entry workspace objects returned by `npm pkg get name` when falling back to the package manager command. --- .../src/package-managers/package-manager.ts | 34 ++++++--- .../package-managers/package-manager_spec.ts | 69 +++++++++++++++++++ 2 files changed, 93 insertions(+), 10 deletions(-) diff --git a/packages/angular/cli/src/package-managers/package-manager.ts b/packages/angular/cli/src/package-managers/package-manager.ts index 234b54851232..272454c21cbd 100644 --- a/packages/angular/cli/src/package-managers/package-manager.ts +++ b/packages/angular/cli/src/package-managers/package-manager.ts @@ -393,25 +393,39 @@ export class PackageManager { * Gets the name of the package in the current project. */ async getCurrentPackageName(): Promise { + try { + const content = await this.host.readFile(join(this.cwd, 'package.json')); + const { name } = JSON.parse(content) as { name?: unknown }; + if (typeof name === 'string') { + return name; + } + } catch { + // Fall back to package manager command if reading file fails + } + if (this.descriptor.getPackageNameCommand) { try { const { stdout } = await this.#run(this.descriptor.getPackageNameCommand); if (stdout) { - return JSON.parse(stdout); + const name = JSON.parse(stdout); + if (typeof name === 'string') { + return name; + } + + // In a workspace member npm prints an object keyed by workspace name instead of a string. + if (name && typeof name === 'object') { + const values = Object.values(name); + if (values.length === 1 && typeof values[0] === 'string') { + return values[0]; + } + } } } catch { - // Fall back to reading file if command fails + // Ignore command failure } } - try { - const content = await this.host.readFile(join(this.cwd, 'package.json')); - const pkgJson = JSON.parse(content); - - return pkgJson.name; - } catch { - return undefined; - } + return undefined; } /** diff --git a/packages/angular/cli/src/package-managers/package-manager_spec.ts b/packages/angular/cli/src/package-managers/package-manager_spec.ts index d500a435d0df..37e0d8aae113 100644 --- a/packages/angular/cli/src/package-managers/package-manager_spec.ts +++ b/packages/angular/cli/src/package-managers/package-manager_spec.ts @@ -378,6 +378,75 @@ describe('PackageManager', () => { }); }); + describe('getCurrentPackageName', () => { + it('should return the name from package.json without running the package manager command', async () => { + const pm = new PackageManager(host, '/repo/app', descriptor); + const readFileSpy = spyOn(host, 'readFile').and.resolveTo('{"name": "app"}'); + + expect(await pm.getCurrentPackageName()).toBe('app'); + expect(readFileSpy).toHaveBeenCalledWith(jasmine.stringMatching(/package\.json$/)); + expect(runCommandSpy).not.toHaveBeenCalled(); + }); + + it('should fall back to the package manager command when reading package.json fails', async () => { + const pm = new PackageManager(host, '/repo/app/src', descriptor); + spyOn(host, 'readFile').and.rejectWith(new Error('ENOENT')); + runCommandSpy.and.resolveTo({ stdout: '"app"', stderr: '' }); + + expect(await pm.getCurrentPackageName()).toBe('app'); + expect(runCommandSpy).toHaveBeenCalledWith( + descriptor.binary, + descriptor.getPackageNameCommand, + jasmine.objectContaining({ cwd: '/repo/app/src' }), + ); + }); + + it('should extract the package name when npm prints a single-entry workspace object', async () => { + const pm = new PackageManager(host, '/repo/apps/app/src', descriptor); + spyOn(host, 'readFile').and.rejectWith(new Error('ENOENT')); + // Inside a workspace member, `npm pkg get name` prints `{ "app": "app" }` instead of `"app"`. + runCommandSpy.and.resolveTo({ stdout: '{\n "app": "app"\n}', stderr: '' }); + + expect(await pm.getCurrentPackageName()).toBe('app'); + }); + + it('should return undefined when npm prints multiple workspace entries and package.json is unavailable', async () => { + const pm = new PackageManager(host, '/repo', descriptor); + spyOn(host, 'readFile').and.rejectWith(new Error('ENOENT')); + runCommandSpy.and.resolveTo({ + stdout: '{\n "app-a": "app-a",\n "app-b": "app-b"\n}', + stderr: '', + }); + + expect(await pm.getCurrentPackageName()).toBeUndefined(); + }); + }); + + describe('getProjectDependencies', () => { + it('should list the dependencies of an npm workspace member', async () => { + const pm = new PackageManager(host, '/repo/apps/app', descriptor); + runCommandSpy.and.resolveTo({ + stdout: JSON.stringify({ + name: 'monorepo', + dependencies: { + app: { + version: '0.0.0', + resolved: 'file:../apps/app', + dependencies: { '@angular/core': { version: '22.0.0' } }, + }, + }, + }), + stderr: '', + }); + spyOn(host, 'readFile').and.resolveTo('{"name": "app"}'); + + const dependencies = await pm.getProjectDependencies(); + + expect([...dependencies.keys()]).toEqual(['@angular/core']); + expect(dependencies.get('@angular/core')?.version).toBe('22.0.0'); + }); + }); + describe('initializationError', () => { it('should throw initializationError when running commands', async () => { const error = new Error('Not installed'); From 40cb9f850606f43ae7388473d0f3d05577b692bb Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Fri, 9 Oct 2026 13:20:41 +0000 Subject: [PATCH 16/52] refactor(@angular/build): run initialization tasks concurrently in library builder Moving target project name validation before async operations allows early exit if missing. Additionally, normalizing library options, initializing xxHash, and purging the stale build disk cache concurrently via Promise.all avoids serial awaiting during builder startup. --- .../angular/build/src/builders/library/builder.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/angular/build/src/builders/library/builder.ts b/packages/angular/build/src/builders/library/builder.ts index 33df771fc6ab..2435d5db5f18 100644 --- a/packages/angular/build/src/builders/library/builder.ts +++ b/packages/angular/build/src/builders/library/builder.ts @@ -42,10 +42,6 @@ export async function* executeLibraryBuilder( context: BuilderContext & { signal?: AbortSignal }, ): AsyncIterableIterator { assertCompatibleAngularVersion(context.workspaceRoot); - await initializeHash(); - - // Purge old build disk cache - await purgeStaleBuildCache(context); const projectName = context.target?.project; if (!projectName) { @@ -54,7 +50,13 @@ export async function* executeLibraryBuilder( return; } - const normalizedOptions = await normalizeLibraryOptions(context, projectName, options); + const [normalizedOptions] = await Promise.all([ + normalizeLibraryOptions(context, projectName, options), + initializeHash(), + // Purge old build disk cache + purgeStaleBuildCache(context), + ]); + const { workspaceRoot, projectRoot, From 4034fc5cd03c9966eb596ded4173194a13901a60 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:07:39 +0000 Subject: [PATCH 17/52] refactor(@angular/build): make getTailwindConfig synchronous getTailwindConfig only performs synchronous path searches and module resolution. Removing async avoids unnecessary Promise allocations and simplifies option normalization callers. --- .../angular/build/src/builders/application/options.ts | 2 +- packages/angular/build/src/builders/library/options.ts | 2 +- packages/angular/build/src/utils/postcss-configuration.ts | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/angular/build/src/builders/application/options.ts b/packages/angular/build/src/builders/application/options.ts index 322c2dbef897..0e225be24045 100644 --- a/packages/angular/build/src/builders/application/options.ts +++ b/packages/angular/build/src/builders/application/options.ts @@ -287,7 +287,7 @@ export async function normalizeOptions( // Skip tailwind configuration if postcss is customized const tailwindConfiguration = postcssConfiguration ? undefined - : await getTailwindConfig(searchDirectories, workspaceRoot, context.logger); + : getTailwindConfig(searchDirectories, workspaceRoot, context.logger); let serverEntryPoint: string | undefined; if (typeof options.server === 'string') { diff --git a/packages/angular/build/src/builders/library/options.ts b/packages/angular/build/src/builders/library/options.ts index c90fd525e1f2..b7747fb6db27 100644 --- a/packages/angular/build/src/builders/library/options.ts +++ b/packages/angular/build/src/builders/library/options.ts @@ -126,7 +126,7 @@ export async function normalizeLibraryOptions( const postcssConfiguration = await loadPostcssConfiguration(searchDirectories); const tailwindConfiguration = postcssConfiguration ? undefined - : await getTailwindConfig(searchDirectories, workspaceRoot, context.logger); + : getTailwindConfig(searchDirectories, workspaceRoot, context.logger); return { workspaceRoot, diff --git a/packages/angular/build/src/utils/postcss-configuration.ts b/packages/angular/build/src/utils/postcss-configuration.ts index abde0e632b30..e5a4076232a0 100644 --- a/packages/angular/build/src/utils/postcss-configuration.ts +++ b/packages/angular/build/src/utils/postcss-configuration.ts @@ -31,8 +31,8 @@ export interface SearchDirectory { files: Set; } -export async function generateSearchDirectories(roots: string[]): Promise { - return await Promise.all( +export function generateSearchDirectories(roots: string[]): Promise { + return Promise.all( roots.map((root) => readdir(root, { withFileTypes: true }).then((entries) => ({ root, @@ -63,11 +63,11 @@ export function findTailwindConfiguration( return findFile(searchDirectories, tailwindConfigFiles); } -export async function getTailwindConfig( +export function getTailwindConfig( searchDirectories: SearchDirectory[], workspaceRoot: string, logger?: { warn(message: string): void }, -): Promise<{ file: string; package: string } | undefined> { +): { file: string; package: string } | undefined { const tailwindConfigurationPath = findTailwindConfiguration(searchDirectories); if (!tailwindConfigurationPath) { return undefined; From fb7efc86228164330f68ed86801f9d5bbe9ad5b0 Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Tue, 13 Oct 2026 08:02:42 +0200 Subject: [PATCH 18/52] perf(@angular/build): resolve asset patterns concurrently with bounded concurrency Avoid sequentially globbing asset entries one-by-one in `resolveAssets` by utilizing `mapConcurrent` bounded by `MAX_CONCURRENT_READS` (16). Additionally, add a fast path for static, non-dynamic file patterns using direct file stats instead of directory walks. --- .../esbuild/persistent-load-result-cache.ts | 5 +-- .../angular/build/src/utils/concurrency.ts | 5 +++ .../angular/build/src/utils/resolve-assets.ts | 43 +++++++++++++------ 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/packages/angular/build/src/tools/esbuild/persistent-load-result-cache.ts b/packages/angular/build/src/tools/esbuild/persistent-load-result-cache.ts index c5dcee90ccf9..7eaf11806f1d 100644 --- a/packages/angular/build/src/tools/esbuild/persistent-load-result-cache.ts +++ b/packages/angular/build/src/tools/esbuild/persistent-load-result-cache.ts @@ -32,7 +32,7 @@ import { readFile, stat } from 'node:fs/promises'; import { isAbsolute } from 'node:path'; import { fileURLToPath } from 'node:url'; import type { Cache as PersistentCacheStore } from '../../utils/cache'; -import { mapConcurrent, runConcurrent } from '../../utils/concurrency'; +import { MAX_CONCURRENT_READS, mapConcurrent, runConcurrent } from '../../utils/concurrency'; import { calculateHash, createContentHash } from '../../utils/hash'; import { LoadResultCache, MemoryLoadResultCache } from './load-result-cache'; @@ -112,9 +112,6 @@ export function extractDiskFilePath(path: string): string | undefined { return isAbsolute(path) ? path : undefined; } -/** Maximum number of concurrent file system read/stat operations to prevent OS file descriptor exhaustion. */ -const MAX_CONCURRENT_READS = 16; - /** * Validates that all imported watch files exist on disk and their contents match. * Performs a fast-path metadata check (mtime + size) first, falling back to content hashing. diff --git a/packages/angular/build/src/utils/concurrency.ts b/packages/angular/build/src/utils/concurrency.ts index a38a9a57fa36..39f2b70c95df 100644 --- a/packages/angular/build/src/utils/concurrency.ts +++ b/packages/angular/build/src/utils/concurrency.ts @@ -6,6 +6,11 @@ * found in the LICENSE file at https://angular.dev/license */ +/** + * Maximum number of concurrent file system read/stat operations to prevent OS file descriptor exhaustion. + */ +export const MAX_CONCURRENT_READS = 16; + /** * Executes an asynchronous function for each item in an array concurrently up to a specified limit. * diff --git a/packages/angular/build/src/utils/resolve-assets.ts b/packages/angular/build/src/utils/resolve-assets.ts index 79ddd8548266..06a6c6c157e9 100644 --- a/packages/angular/build/src/utils/resolve-assets.ts +++ b/packages/angular/build/src/utils/resolve-assets.ts @@ -6,8 +6,10 @@ * found in the LICENSE file at https://angular.dev/license */ +import { lstat, stat } from 'node:fs/promises'; import path from 'node:path'; -import { glob } from 'tinyglobby'; +import { glob, isDynamicPattern } from 'tinyglobby'; +import { MAX_CONCURRENT_READS, mapConcurrent } from './concurrency'; import { isSubDirectory } from './path'; /** @@ -26,15 +28,34 @@ export async function resolveAssets( }[], root: string, ): Promise<{ source: string; destination: string }[]> { - const outputFiles: { source: string; destination: string }[] = []; - - for (const entry of entries) { + const resolvedEntries = await mapConcurrent(entries, MAX_CONCURRENT_READS, async (entry) => { if (!isSubDirectory(root, entry.input)) { throw new Error(`The ${entry.input} asset path must be within the workspace root.`); } const cwd = path.resolve(root, entry.input); + if (!entry.ignore?.length && !isDynamicPattern(entry.glob)) { + const src = path.join(cwd, entry.glob); + if (isSubDirectory(cwd, src)) { + try { + const stats = await (entry.followSymlinks ? stat(src) : lstat(src)); + if (stats.isFile()) { + const filePath = entry.flatten ? path.basename(entry.glob) : entry.glob; + + return [{ source: src, destination: path.join(entry.output, filePath) }]; + } + + if (!stats.isSymbolicLink()) { + return []; + } + } catch { + // File does not exist or cannot be accessed. + return []; + } + } + } + const files = await glob(entry.glob, { cwd, dot: true, @@ -42,13 +63,11 @@ export async function resolveAssets( followSymbolicLinks: entry.followSymlinks ?? false, }); - for (const file of files) { - const src = path.join(cwd, file); - const filePath = entry.flatten ? path.basename(file) : file; - - outputFiles.push({ source: src, destination: path.join(entry.output, filePath) }); - } - } + return files.map((file) => ({ + source: path.join(cwd, file), + destination: path.join(entry.output, entry.flatten ? path.basename(file) : file), + })); + }); - return outputFiles; + return resolvedEntries.flat(); } From 2c518a6dbe8734d247dfe4eb2c1c4af5e169fa94 Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Tue, 13 Oct 2026 08:49:46 +0200 Subject: [PATCH 19/52] fix(@angular/build): enhance build logs and output location for library builder Align library builder logs with the application builder format by logging: - `Library bundle generation complete. [X seconds] - ` on build completion - `Output location: ` for successful builds - `Watch mode enabled. Watching for file changes...` after initial build when watch mode is active --- .../build/src/builders/library/builder.ts | 34 ++++++++----- .../library/tests/behavior/build_spec.ts | 50 +++++++++++++++++++ 2 files changed, 72 insertions(+), 12 deletions(-) diff --git a/packages/angular/build/src/builders/library/builder.ts b/packages/angular/build/src/builders/library/builder.ts index 2435d5db5f18..948f53ae568b 100644 --- a/packages/angular/build/src/builders/library/builder.ts +++ b/packages/angular/build/src/builders/library/builder.ts @@ -120,10 +120,6 @@ export async function* executeLibraryBuilder( } if (isWatchMode) { - if (progress) { - logger.info('Watch mode enabled. Watching for file changes...'); - } - const { setupWatcher } = await import('../../utils/watcher'); watcher = await setupWatcher({ workspaceRoot, @@ -154,6 +150,11 @@ export async function* executeLibraryBuilder( watcher, buildAction, ); + + if (isWatchMode && progress) { + logger.info('Watch mode enabled. Watching for file changes...'); + } + yield initialResult; if (!isWatchMode || !watcher) { @@ -192,11 +193,11 @@ async function executeBuild( buildAction: typeof import('./pipeline/build-action').buildAction, ): Promise { const startTime = process.hrtime.bigint(); - const { context, watchedCompilationFiles, isWatchMode } = actionContext; + const { context, watchedCompilationFiles, isWatchMode, options } = actionContext; try { await withProgress(message, () => buildAction(actionContext)); - logBuildResult(context.logger, startTime, true); + logBuildResult(context.logger, startTime, true, options.outputPath); if (isWatchMode) { logCumulativeDurations(); } @@ -345,14 +346,23 @@ async function* runWatchLoop( /** * Logs the build completion time and status. */ -function logBuildResult(logger: logging.LoggerApi, startTime: bigint, success: boolean): void { - const durationMs = Number(process.hrtime.bigint() - startTime) / 1_000_000; - const durationSec = (durationMs / 1000).toFixed(2); +function logBuildResult( + logger: logging.LoggerApi, + startTime: bigint, + success: boolean, + outputPath?: string, +): void { + const buildTime = Number(process.hrtime.bigint() - startTime) / 10 ** 9; + const message = + `Library bundle generation ${success ? 'complete' : 'failed'}.` + + ` [${buildTime.toFixed(3)} seconds] - ${new Date().toISOString()}`; if (success) { - logger.info(`Build at: ${new Date().toISOString()} - Time: ${durationMs.toFixed(0)}ms`); - logger.info(`Built Angular library in ${durationSec}s.`); + logger.info(message); + if (outputPath) { + logger.info(`Output location: ${outputPath}\n`); + } } else { - logger.error(`Build failed after ${durationSec}s.`); + logger.error(message); } } diff --git a/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts b/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts index 996001db209d..e55a414c1ada 100644 --- a/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts +++ b/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts @@ -180,5 +180,55 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => tslib: '^2.0.0', }); }); + + it('should log completion and output location', async () => { + harness.useTarget('build', { + ...BASE_OPTIONS, + }); + + const { result, logs } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + expect(logs).toContain( + jasmine.objectContaining({ + level: 'info', + message: jasmine.stringMatching( + /Library bundle generation complete\. \[\d+\.\d{3} seconds\] - \d{4}-\d{2}-\d{2}T/, + ), + }), + ); + expect(logs).toContain( + jasmine.objectContaining({ + level: 'info', + message: jasmine.stringMatching(/Output location: .*dist[/\\]lib/), + }), + ); + }); + + it('should log failure on build error', async () => { + await harness.writeFile( + 'projects/lib/src/public-api.ts', + `export const title: number = 'invalid type';`, + ); + + harness.useTarget('build', { + ...BASE_OPTIONS, + }); + + const { result, logs } = await harness.executeOnce({ outputLogsOnFailure: false }); + expect(result?.success).toBeFalse(); + expect(logs).toContain( + jasmine.objectContaining({ + level: 'error', + message: jasmine.stringMatching( + /Library bundle generation failed\. \[\d+\.\d{3} seconds\] - \d{4}-\d{2}-\d{2}T/, + ), + }), + ); + expect(logs).not.toContain( + jasmine.objectContaining({ + message: jasmine.stringMatching(/Output location:/), + }), + ); + }); }); }); From 07845f019cf7d70c17f037d711b430a776f96031 Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Tue, 13 Oct 2026 09:09:21 +0200 Subject: [PATCH 20/52] perf(@angular/build): optimize incremental watch rebuilds in AOT compilation - Pre-populate `.d.ts` shape signatures on the previous `BuilderProgram` for modified files prior to diffing when type-checking or TypeScript transpilation is active, preventing false-positive `.d.ts` cascades on incremental watch edits. - Synchronize `typeScriptProgram` with `angularCompiler.getCurrentProgram()` after `collectDiagnostics()` and clear uncommitted `changedFilesSet` and `oldSignatures` entries so subsequent incremental builds preserve `.d.ts` signatures and do not treat `.ngtypecheck.ts` shims as newly added files. - Detect affected dependent `.ngtypecheck.ts` shims in `isolatedModules` / `verbatimModuleSyntax` mode via TypeScript's `state.hasCalledUpdateShapeSignature`, ensuring cross-component template diagnostics are re-evaluated when a dependency's `.d.ts` shape changes without cascading on private edits. - Avoid `filter().flatMap()` allocations and skip `getResourceDependencies()` for declaration files when collecting `referencedFiles`. --- .../tests/behavior/rebuild-errors_spec.ts | 237 ++++++++- .../build/src/tools/angular/angular-host.ts | 11 +- .../angular/compilation/aot-compilation.ts | 467 ++++++++++++++---- .../src/tools/esbuild/bundler-context.ts | 6 +- 4 files changed, 613 insertions(+), 108 deletions(-) diff --git a/packages/angular/build/src/builders/application/tests/behavior/rebuild-errors_spec.ts b/packages/angular/build/src/builders/application/tests/behavior/rebuild-errors_spec.ts index de53c7223fff..5e7bdeb3fd9c 100644 --- a/packages/angular/build/src/builders/application/tests/behavior/rebuild-errors_spec.ts +++ b/packages/angular/build/src/builders/application/tests/behavior/rebuild-errors_spec.ts @@ -15,12 +15,6 @@ import { expectNoLog, } from '../setup'; -/** - * Maximum time in milliseconds for single build/rebuild - * This accounts for CI variability. - */ -export const BUILD_TIMEOUT = 30_000; - describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { describe('Behavior: "Rebuild Error Detection"', () => { it('detects template errors with no AOT codegen or TS emit differences', async () => { @@ -128,6 +122,235 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { ); }); + it('detects template errors across components on watch rebuild when isolatedModules is enabled', async () => { + harness.useTarget('build', { + ...BASE_OPTIONS, + watch: true, + }); + + await harness.modifyFile('tsconfig.json', (content) => { + const tsconfig = JSON.parse(content); + tsconfig.compilerOptions = { + ...tsconfig.compilerOptions, + isolatedModules: true, + }; + + return JSON.stringify(tsconfig); + }); + + const goodChildComponentContents = ` + import { Component, Input } from '@angular/core'; + @Component({ + selector: 'child', + standalone: true, + template: '

{{ value }}

', + }) + export class ChildComponent { + @Input() value!: number; + } + `; + + const typeErrorText = `Type 'number' is not assignable to type 'string'.`; + + await harness.writeFiles({ + 'src/app/child.component.ts': goodChildComponentContents, + 'src/app/app.module.ts': ` + import { NgModule } from '@angular/core'; + import { BrowserModule } from '@angular/platform-browser'; + import { AppComponent } from './app.component'; + @NgModule({ + imports: [ + BrowserModule, + AppComponent, + ], + providers: [], + bootstrap: [AppComponent] + }) + export class AppModule { } + `, + 'src/app/app.component.ts': ` + import { Component } from '@angular/core'; + import { ChildComponent } from './child.component'; + @Component({ + selector: 'app-root', + standalone: true, + imports: [ChildComponent], + template: '', + }) + export class AppComponent {} + `, + }); + + await harness.executeWithCases( + [ + async ({ result }) => { + expect(result?.success).toBeTrue(); + + // Update child component to change input type from number to string + await harness.writeFile( + 'src/app/child.component.ts', + ` + import { Component, Input } from '@angular/core'; + @Component({ + selector: 'child', + standalone: true, + template: '

{{ value }}

', + }) + export class ChildComponent { + @Input() value!: string; + } + `, + ); + }, + async ({ result, logs }) => { + expect(result?.success).toBeFalse(); + expectLog(logs, typeErrorText); + + // Make an unrelated change to verify error persists + await harness.modifyFile('src/main.ts', (content) => content + '\n'); + }, + async ({ result, logs }) => { + expect(result?.success).toBeFalse(); + expectLog(logs, typeErrorText); + + // Revert back to number + await harness.writeFile('src/app/child.component.ts', goodChildComponentContents); + }, + async ({ result, logs }) => { + expect(result?.success).toBeTrue(); + expectNoLog(logs, typeErrorText); + + // Make an unrelated change to verify error cache cleared + await harness.modifyFile('src/main.ts', (content) => content + '\n'); + }, + ({ result, logs }) => { + expect(result?.success).toBeTrue(); + expectNoLog(logs, typeErrorText); + }, + ], + { outputLogsOnFailure: false }, + ); + }); + + it('detects template errors when an input becomes required or a selector is renamed on watch rebuild', async () => { + harness.useTarget('build', { + ...BASE_OPTIONS, + watch: true, + }); + + await harness.modifyFile('tsconfig.json', (content) => { + const tsconfig = JSON.parse(content); + tsconfig.compilerOptions = { + ...tsconfig.compilerOptions, + isolatedModules: true, + }; + + return JSON.stringify(tsconfig); + }); + + const goodChildComponentContents = ` + import { Component, input } from '@angular/core'; + @Component({ + selector: 'app-child', + standalone: true, + template: '

{{ label() }}

', + }) + export class ChildComponent { + label = input(''); + } + `; + + const requiredInputErrorText = `Required input 'label' from component ChildComponent must be specified.`; + const unknownElementErrorText = `'app-child' is not a known element`; + + await harness.writeFiles({ + 'src/app/child.component.ts': goodChildComponentContents, + 'src/app/app.module.ts': ` + import { NgModule } from '@angular/core'; + import { BrowserModule } from '@angular/platform-browser'; + import { AppComponent } from './app.component'; + @NgModule({ + imports: [ + BrowserModule, + AppComponent, + ], + providers: [], + bootstrap: [AppComponent] + }) + export class AppModule { } + `, + 'src/app/app.component.ts': ` + import { Component } from '@angular/core'; + import { ChildComponent } from './child.component'; + @Component({ + selector: 'app-root', + standalone: true, + imports: [ChildComponent], + template: '', + }) + export class AppComponent {} + `, + }); + + await harness.executeWithCases( + [ + async ({ result }) => { + expect(result?.success).toBeTrue(); + + // Make input required using signal input.required() (which has the same TS .d.ts type InputSignal) + await harness.writeFile( + 'src/app/child.component.ts', + ` + import { Component, input } from '@angular/core'; + @Component({ + selector: 'app-child', + standalone: true, + template: '

{{ label() }}

', + }) + export class ChildComponent { + label = input.required(); + } + `, + ); + }, + async ({ result, logs }) => { + expect(result?.success).toBeFalse(); + expectLog(logs, requiredInputErrorText); + + // Revert required input and rename selector instead + await harness.writeFile( + 'src/app/child.component.ts', + ` + import { Component, input } from '@angular/core'; + @Component({ + selector: 'app-child-renamed', + standalone: true, + template: '

{{ label() }}

', + }) + export class ChildComponent { + label = input(''); + } + `, + ); + }, + async ({ result, logs }) => { + expect(result?.success).toBeFalse(); + expectNoLog(logs, requiredInputErrorText); + expectLog(logs, unknownElementErrorText); + + // Revert back to valid child component + await harness.writeFile('src/app/child.component.ts', goodChildComponentContents); + }, + ({ result, logs }) => { + expect(result?.success).toBeTrue(); + expectNoLog(logs, requiredInputErrorText); + expectNoLog(logs, unknownElementErrorText); + }, + ], + { outputLogsOnFailure: false }, + ); + }); + it('detects cumulative block syntax errors', async () => { harness.useTarget('build', { ...BASE_OPTIONS, @@ -234,7 +457,7 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { await harness.appendToFile('src/app/app.component.html', '
Guten Tag
'); }, ({ logs }) => { - expectNoLog(logs, 'invalid-css-content'); + expectNoLog(logs, 'Unexpected character "EOF"'); harness.expectFile('dist/browser/main.js').content.toContain('Hello, world!'); harness.expectFile('dist/browser/main.js').content.toContain('Guten Tag'); diff --git a/packages/angular/build/src/tools/angular/angular-host.ts b/packages/angular/build/src/tools/angular/angular-host.ts index 9322b5683dc5..f30df5bab64d 100644 --- a/packages/angular/build/src/tools/angular/angular-host.ts +++ b/packages/angular/build/src/tools/angular/angular-host.ts @@ -35,7 +35,10 @@ export interface AngularHostOptions { * field. The `version` field is required when used with a TypeScript BuilderProgram. * @param program The TypeScript Program instance to patch. */ -export function ensureSourceFileVersions(program: ts.Program): void { +export function ensureSourceFileVersions( + program: ts.Program, + previousProgram?: ts.BuilderProgram, +): void { const baseGetSourceFiles = program.getSourceFiles; // TODO: Update Angular compiler to add versions to all internal files and remove this program.getSourceFiles = function (...parameters) { @@ -45,7 +48,11 @@ export function ensureSourceFileVersions(program: ts.Program): void { for (const file of files) { if (file.version === undefined) { - file.version = calculateHash(file.text); + const previousFile: (ts.SourceFile & { version?: string }) | undefined = + previousProgram && !file.fileName.endsWith('.ngtypecheck.ts') + ? previousProgram.getSourceFile(file.fileName) + : undefined; + file.version = previousFile?.version ?? calculateHash(file.text); } } diff --git a/packages/angular/build/src/tools/angular/compilation/aot-compilation.ts b/packages/angular/build/src/tools/angular/compilation/aot-compilation.ts index 6f45199d1421..749962e3def6 100644 --- a/packages/angular/build/src/tools/angular/compilation/aot-compilation.ts +++ b/packages/angular/build/src/tools/angular/compilation/aot-compilation.ts @@ -37,16 +37,41 @@ import { printSourceFileWithMap } from './typescript-printer'; */ const HMR_MODIFIED_FILE_LIMIT = 32; +/** + * Extension for Angular type-checking files. + */ +const TTC_EXTENSION = '.ngtypecheck.ts'; + +/** + * Length of the `.ngtypecheck.ts` extension. + */ +const TTC_EXTENSION_LENGTH = TTC_EXTENSION.length; + +/** + * Checks if a file is an Angular type-checking shim file. + */ +function isNgTypeCheckFile(fileName: string): boolean { + return fileName.endsWith(TTC_EXTENSION); +} + +/** + * Returns the original filename for a type-checking shim file. + */ +function getOriginalFilename(fileName: string): string { + return fileName.slice(0, -TTC_EXTENSION_LENGTH) + '.ts'; +} + class AngularCompilationState { constructor( public readonly angularProgram: ng.NgtscProgram, public readonly compilerHost: ng.CompilerHost, - public readonly typeScriptProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram, + public typeScriptProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram, public readonly affectedFiles: ReadonlySet, public readonly templateDiagnosticsOptimization: ng.OptimizeFor, public readonly webWorkerTransform: ts.TransformerFactory, public readonly useTypeScriptTranspilation: boolean, public readonly diagnosticCache = new WeakMap(), + public readonly filesWithoutDtsSignature = new Set(), ) {} get angularCompiler() { @@ -103,8 +128,8 @@ export class AotCompilation extends TypeScriptCompilation { if (hostOptions.modifiedFiles) { this.invalidateFiles(hostOptions.modifiedFiles); - for (const modifiedFile of hostOptions.modifiedFiles) { - if (this.#state) { + if (this.#state && hostOptions.modifiedFiles.size > 0) { + for (const modifiedFile of hostOptions.modifiedFiles) { // Clear package.json cache if a node modules file was modified if (!clearPackageJsonCache && modifiedFile.includes('node_modules')) { clearPackageJsonCache = true; @@ -120,6 +145,14 @@ export class AotCompilation extends TypeScriptCompilation { } } } + + if (useTypeChecking || useTypeScriptTranspilation) { + populatePreviousDtsSignatures( + this.#state.typeScriptProgram, + hostOptions.modifiedFiles, + this.#state.filesWithoutDtsSignature, + ); + } } } @@ -155,6 +188,18 @@ export class AotCompilation extends TypeScriptCompilation { configurationDiagnostics, ); + const filesWithoutDtsSignature = this.#state?.filesWithoutDtsSignature ?? new Set(); + if (!this.#state) { + for (const sourceFile of typeScriptProgram.getSourceFiles()) { + if ( + !sourceFile.isDeclarationFile && + !angularCompiler.ignoreForDiagnostics.has(sourceFile) + ) { + filesWithoutDtsSignature.add(sourceFile.fileName); + } + } + } + await profileAsync('NG_ANALYZE_PROGRAM', () => angularCompiler.analyzeAsync()); let templateUpdates; @@ -203,38 +248,62 @@ export class AotCompilation extends TypeScriptCompilation { const affectedFiles = useTypeChecking || useTypeScriptTranspilation ? profileSync('NG_FIND_AFFECTED', () => - findAffectedFiles(typeScriptProgram, angularCompiler, usingBuildInfo), + findAffectedFiles( + typeScriptProgram, + angularCompiler, + usingBuildInfo, + this.#state?.typeScriptProgram, + filesWithoutDtsSignature, + ), ) : new Set(); const componentResourcesDependencies = new Map(); // Get all files referenced in the TypeScript/Angular program including component resources - const referencedFiles = [ - ...tsConfigFiles, - ...typeScriptProgram - .getSourceFiles() - .filter((sourceFile) => !angularCompiler.ignoreForEmit.has(sourceFile)) - .flatMap((sourceFile) => { - const resourceDependencies = angularCompiler.getResourceDependencies(sourceFile); - componentResourcesDependencies.set(sourceFile.fileName, resourceDependencies); - // Also invalidate Angular diagnostics for a source file if component resources are modified - if (this.#state && hostOptions.modifiedFiles?.size) { - for (const resourceDependency of resourceDependencies) { - if ( - hostOptions.modifiedFiles.has(resourceDependency) && - !/\.(?:css|scss|sass|less)$/i.test(resourceDependency) - ) { - this.#state.diagnosticCache.delete(sourceFile); - // Also mark as affected in case changed template affects diagnostics - affectedFiles.add(sourceFile); - } - } + const referencedFiles = [...tsConfigFiles]; + for (const sourceFile of typeScriptProgram.getSourceFiles()) { + if (angularCompiler.ignoreForEmit.has(sourceFile)) { + continue; + } + + referencedFiles.push(sourceFile.fileName); + if (sourceFile.isDeclarationFile) { + continue; + } + + const resourceDependencies = angularCompiler.getResourceDependencies(sourceFile); + componentResourcesDependencies.set(sourceFile.fileName, resourceDependencies); + + if (resourceDependencies.length === 0) { + continue; + } + + referencedFiles.push(...resourceDependencies); + + // Also invalidate Angular diagnostics for a source file if component resources are modified + if (this.#state && hostOptions.modifiedFiles?.size) { + for (const resourceDependency of resourceDependencies) { + if ( + !hostOptions.modifiedFiles.has(resourceDependency) || + /\.(?:css|scss|sass|less)$/i.test(resourceDependency) + ) { + continue; } - return [sourceFile.fileName, ...resourceDependencies]; - }), - ]; + this.#state.diagnosticCache.delete(sourceFile); + + const oldSourceFile = this.#state.typeScriptProgram.getSourceFile(sourceFile.fileName); + if (oldSourceFile) { + this.#state.diagnosticCache.delete(oldSourceFile); + } + + // Also mark as affected in case changed template affects diagnostics + affectedFiles.add(sourceFile); + break; + } + } + } this.#state = new AngularCompilationState( angularProgram, @@ -245,6 +314,7 @@ export class AotCompilation extends TypeScriptCompilation { createWorkerTransformer(hostOptions.processWebWorker.bind(hostOptions)), useTypeScriptTranspilation, this.#state?.diagnosticCache, + filesWithoutDtsSignature, ); return { @@ -270,61 +340,92 @@ export class AotCompilation extends TypeScriptCompilation { const syntactic = modes & DiagnosticModes.Syntactic; const semantic = modes & DiagnosticModes.Semantic; - // Collect program level diagnostics - if (modes & DiagnosticModes.Option) { - yield* typeScriptProgram.getConfigFileParsingDiagnostics(); - yield* angularCompiler.getOptionDiagnostics(); - yield* typeScriptProgram.getOptionsDiagnostics(); - } - if (syntactic) { - yield* typeScriptProgram.getGlobalDiagnostics(); - } - - // Collect source file specific diagnostics - for (const sourceFile of typeScriptProgram.getSourceFiles()) { - if (angularCompiler.ignoreForDiagnostics.has(sourceFile)) { - continue; + try { + // Collect program level diagnostics + if (modes & DiagnosticModes.Option) { + yield* typeScriptProgram.getConfigFileParsingDiagnostics(); + yield* angularCompiler.getOptionDiagnostics(); + yield* typeScriptProgram.getOptionsDiagnostics(); } - if (syntactic) { - // TypeScript will use cached diagnostics for files that have not been - // changed or affected for this build when using incremental building. - yield* profileSync( - 'NG_DIAGNOSTICS_SYNTACTIC', - () => typeScriptProgram.getSyntacticDiagnostics(sourceFile), - true, - ); + yield* typeScriptProgram.getGlobalDiagnostics(); } - if (!semantic) { - continue; - } + // Collect source file specific diagnostics + for (const sourceFile of typeScriptProgram.getSourceFiles()) { + if (angularCompiler.ignoreForDiagnostics.has(sourceFile)) { + continue; + } - yield* profileSync( - 'NG_DIAGNOSTICS_SEMANTIC', - () => typeScriptProgram.getSemanticDiagnostics(sourceFile), - true, - ); + if (syntactic) { + // TypeScript will use cached diagnostics for files that have not been + // changed or affected for this build when using incremental building. + yield* profileSync( + 'NG_DIAGNOSTICS_SYNTACTIC', + () => typeScriptProgram.getSyntacticDiagnostics(sourceFile), + true, + ); + } - // Declaration files cannot have template diagnostics - if (sourceFile.isDeclarationFile) { - continue; - } + if (!semantic) { + continue; + } - // Only request Angular template diagnostics for affected files to avoid - // overhead of template diagnostics for unchanged files. - if (affectedFiles.has(sourceFile)) { - const angularDiagnostics = profileSync( - 'NG_DIAGNOSTICS_TEMPLATE', - () => angularCompiler.getDiagnosticsForFile(sourceFile, templateDiagnosticsOptimization), + yield* profileSync( + 'NG_DIAGNOSTICS_SEMANTIC', + () => typeScriptProgram.getSemanticDiagnostics(sourceFile), true, ); - diagnosticCache.set(sourceFile, angularDiagnostics); - yield* angularDiagnostics; - } else { - const angularDiagnostics = diagnosticCache.get(sourceFile); - if (angularDiagnostics) { + + // Declaration files cannot have template diagnostics + if (sourceFile.isDeclarationFile) { + continue; + } + + // Only request Angular template diagnostics for affected files to avoid + // overhead of template diagnostics for unchanged files. + if (affectedFiles.has(sourceFile)) { + const angularDiagnostics = profileSync( + 'NG_DIAGNOSTICS_TEMPLATE', + () => + angularCompiler.getDiagnosticsForFile(sourceFile, templateDiagnosticsOptimization), + true, + ); + diagnosticCache.set(sourceFile, angularDiagnostics); yield* angularDiagnostics; + } else { + const angularDiagnostics = diagnosticCache.get(sourceFile); + if (angularDiagnostics) { + yield* angularDiagnostics; + } + } + } + } finally { + // Angular's template typechecker lazily creates `.ngtypecheck.ts` shims in a new `ts.Program` + // during `getDiagnosticsForFile`. Sync the builder program with `angularCompiler.getCurrentProgram()` + // so the next incremental build does not treat all `.ngtypecheck.ts` files as newly added files. + const currentTsProgram = angularCompiler.getCurrentProgram(); + if (currentTsProgram !== typeScriptProgram.getProgram()) { + ensureSourceFileVersions(currentTsProgram, typeScriptProgram); + this.#state.typeScriptProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram( + currentTsProgram, + this.#state.compilerHost, + typeScriptProgram, + ); + + const baseEmit = currentTsProgram.emit; + currentTsProgram.emit = () => ({ emitSkipped: true, diagnostics: [] }); + try { + while ( + this.#state.typeScriptProgram.getSemanticDiagnosticsOfNextAffectedFile( + undefined, + () => true, + ) + ) { + /* empty */ + } + } finally { + currentTsProgram.emit = baseEmit; } } } @@ -419,7 +520,7 @@ export class AotCompilation extends TypeScriptCompilation { if ( angularCompiler.incrementalCompilation.safeToSkipEmit(sourceFile) && - !affectedFiles.has(sourceFile) + (!useTypeScriptTranspilation || !affectedFiles.has(sourceFile)) ) { continue; } @@ -483,40 +584,138 @@ export class AotCompilation extends TypeScriptCompilation { function findAffectedFiles( builder: ts.EmitAndSemanticDiagnosticsBuilderProgram, - { ignoreForDiagnostics }: ng.NgtscProgram['compiler'], + { ignoreForDiagnostics, incrementalCompilation }: ng.NgtscProgram['compiler'], includeTTC: boolean, + oldBuilder: ts.EmitAndSemanticDiagnosticsBuilderProgram | undefined, + filesWithoutDtsSignature: Set, ): Set { const affectedFiles = new Set(); - // eslint-disable-next-line no-constant-condition - while (true) { - const result = builder.getSemanticDiagnosticsOfNextAffectedFile(undefined, (sourceFile) => { - // If the affected file is a TTC shim, add the shim's original source file. - // This ensures that changes that affect TTC are typechecked even when the changes - // are otherwise unrelated from a TS perspective and do not result in Ivy codegen changes. - // For example, changing @Input property types of a directive used in another component's - // template. - // A TTC shim is a file that has been ignored for diagnostics and has a filename ending in `.ngtypecheck.ts`. - if (ignoreForDiagnostics.has(sourceFile) && sourceFile.fileName.endsWith('.ngtypecheck.ts')) { - // This file name conversion relies on internal compiler logic and should be converted - // to an official method when available. 15 is length of `.ngtypecheck.ts` - const originalFilename = sourceFile.fileName.slice(0, -15) + '.ts'; - const originalSourceFile = builder.getSourceFile(originalFilename); - if (originalSourceFile) { - affectedFiles.add(originalSourceFile); + // Temporarily disable `isolatedModules` and `verbatimModuleSyntax` while walking affected + // files so TypeScript's `getFilesAffectedByUpdatedShapeWhenModuleEmit` yields dependent + // `.ngtypecheck.ts` shims to the `ignoreSourceFile` callback when a file's `.d.ts` shape + // changes, instead of returning only the modified file itself. + const compilerOptions = builder.getCompilerOptions(); + const prevIsolatedModules = compilerOptions.isolatedModules; + const prevVerbatimModuleSyntax = compilerOptions.verbatimModuleSyntax; + compilerOptions.isolatedModules = false; + compilerOptions.verbatimModuleSyntax = false; + + const program = builder.getProgram(); + const baseEmit = program.emit; + const oldProgram = oldBuilder?.getProgram(); + program.emit = ( + targetSourceFile, + writeFile, + cancellationToken, + emitOnly, + customTransformers, + ...rest + ) => { + if (targetSourceFile) { + if (isNgTypeCheckFile(targetSourceFile.fileName)) { + return { emitSkipped: true, diagnostics: [] }; + } + + if (oldProgram && filesWithoutDtsSignature.has(targetSourceFile.fileName)) { + const oldSourceFile = oldProgram.getSourceFile(targetSourceFile.fileName); + if (oldSourceFile) { + let oldDtsText: string | undefined; + let oldHasDiagnostics = false; + oldProgram.emit( + oldSourceFile, + (_fileName, text, _bom, _onError, _sourceFiles, data) => { + oldDtsText = text; + oldHasDiagnostics = !!(data as { diagnostics?: unknown[] } | undefined)?.diagnostics + ?.length; + }, + cancellationToken, + emitOnly, + customTransformers, + ...(rest as []), + ); + + return baseEmit.call( + program, + targetSourceFile, + (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => { + const newHasDiagnostics = !!(data as { diagnostics?: unknown[] } | undefined) + ?.diagnostics?.length; + if (text !== oldDtsText || newHasDiagnostics !== oldHasDiagnostics) { + filesWithoutDtsSignature.delete(targetSourceFile.fileName); + writeFile?.(fileName, text, writeByteOrderMark, onError, sourceFiles, data); + } + }, + cancellationToken, + emitOnly, + customTransformers, + ...(rest as []), + ); } - return true; + filesWithoutDtsSignature.delete(targetSourceFile.fileName); } + } + + return baseEmit.call( + program, + targetSourceFile, + writeFile, + cancellationToken, + emitOnly, + customTransformers, + ...(rest as []), + ); + }; + + try { + while ( + builder.getSemanticDiagnosticsOfNextAffectedFile(undefined, (sourceFile) => { + if (ignoreForDiagnostics.has(sourceFile)) { + // If the affected file is a TTC shim, add the shim's original source file. + // This ensures that changes that affect TTC are typechecked even when the changes + // are otherwise unrelated from a TS perspective and do not result in Ivy codegen changes. + // For example, changing @Input property types of a directive used in another component's + // template. + // A TTC shim is a file that has been ignored for diagnostics and has a filename ending in `.ngtypecheck.ts`. + if (isNgTypeCheckFile(sourceFile.fileName)) { + // This file name conversion relies on internal compiler logic and should be converted + // to an official method when available. 15 is length of `.ngtypecheck.ts` + const originalFilename = getOriginalFilename(sourceFile.fileName); + const originalSourceFile = builder.getSourceFile(originalFilename); + if (originalSourceFile) { + affectedFiles.add(originalSourceFile); + } + } + } else { + affectedFiles.add(sourceFile); + } - return false; - }); + return true; + }) + ) { + /* empty */ + } + } finally { + program.emit = baseEmit; + compilerOptions.isolatedModules = prevIsolatedModules; + compilerOptions.verbatimModuleSyntax = prevVerbatimModuleSyntax; + } - if (!result) { - break; + // Also include files identified by Angular's incremental compilation graph as needing + // re-emission or template re-typechecking (such as selector renames or required input changes + // that only affect Angular metadata without altering standard TypeScript `.d.ts` signatures). + for (const sourceFile of builder.getSourceFiles()) { + if (sourceFile.isDeclarationFile || ignoreForDiagnostics.has(sourceFile)) { + continue; } - affectedFiles.add(result.affected as ts.SourceFile); + if ( + !incrementalCompilation.safeToSkipEmit(sourceFile) || + incrementalCompilation.priorTypeCheckingResultsFor(sourceFile) === null + ) { + affectedFiles.add(sourceFile); + } } // Add all files with associated template type checking files. @@ -525,10 +724,10 @@ function findAffectedFiles( // info is present. if (includeTTC) { for (const sourceFile of builder.getSourceFiles()) { - if (ignoreForDiagnostics.has(sourceFile) && sourceFile.fileName.endsWith('.ngtypecheck.ts')) { + if (ignoreForDiagnostics.has(sourceFile) && isNgTypeCheckFile(sourceFile.fileName)) { // This file name conversion relies on internal compiler logic and should be converted // to an official method when available. 15 is length of `.ngtypecheck.ts` - const originalFilename = sourceFile.fileName.slice(0, -15) + '.ts'; + const originalFilename = getOriginalFilename(sourceFile.fileName); const originalSourceFile = builder.getSourceFile(originalFilename); if (originalSourceFile) { affectedFiles.add(originalSourceFile); @@ -539,3 +738,75 @@ function findAffectedFiles( return affectedFiles; } + +/** + * Ensures `.d.ts` shape signatures are computed on the previous `BuilderProgram` for modified + * files before the next `BuilderProgram` is created. + * + * On the initial build (`oldProgram === undefined`), TypeScript initializes each file's shape + * signature to its `.ts` source version hash rather than emitting `.d.ts` declarations for every + * file. When a file is modified on a watch rebuild, TypeScript computes its new `.d.ts` signature + * and compares it against the previous program's stored signature. Emitting the `.d.ts` signature + * on `oldProgram` for the modified file replaces its initial `.ts` version hash with its true + * `.d.ts` signature prior to diffing, avoiding false-positive `.d.ts` cascades across importers. + */ +function populatePreviousDtsSignatures( + oldProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram, + modifiedFiles: ReadonlySet, + filesWithoutDtsSignature: Set, +): void { + const filesToUpdate: ts.SourceFile[] = []; + for (const modifiedFile of modifiedFiles) { + const sf = oldProgram.getSourceFile(modifiedFile); + if (sf && !sf.isDeclarationFile && filesWithoutDtsSignature.delete(sf.fileName)) { + filesToUpdate.push(sf); + } + } + + if (filesToUpdate.length === 0) { + return; + } + + const compilerOptions = oldProgram.getCompilerOptions(); + const prevDeclaration = compilerOptions.declaration; + const prevComposite = compilerOptions.composite; + const prevNoEmit = compilerOptions.noEmit; + const prevNoEmitOnError = compilerOptions.noEmitOnError; + + compilerOptions.declaration = true; + compilerOptions.composite = false; + compilerOptions.noEmit = false; + compilerOptions.noEmitOnError = false; + + const program = oldProgram.getProgram(); + const baseEmit = program.emit as ( + targetSourceFile?: ts.SourceFile, + writeFile?: ts.WriteFileCallback, + cancellationToken?: ts.CancellationToken, + emitOnlyDtsFiles?: boolean | number, + customTransformers?: ts.CustomTransformers, + forceDtsEmit?: boolean, + ) => ts.EmitResult; + program.emit = (targetSourceFile, writeFile, cancellationToken) => + baseEmit.call( + program, + targetSourceFile, + writeFile, + cancellationToken, + 2, // ts.EmitOnly.BuilderSignature + undefined, + true, // forceDtsEmit + ); + + try { + for (const sf of filesToUpdate) { + oldProgram.emit(sf, () => {}, undefined, true); + } + } finally { + program.emit = baseEmit; + compilerOptions.declaration = prevDeclaration; + compilerOptions.composite = prevComposite; + compilerOptions.noEmit = prevNoEmit; + compilerOptions.noEmitOnError = prevNoEmitOnError; + } +} diff --git a/packages/angular/build/src/tools/esbuild/bundler-context.ts b/packages/angular/build/src/tools/esbuild/bundler-context.ts index a4228caa5782..202ab514cbfe 100644 --- a/packages/angular/build/src/tools/esbuild/bundler-context.ts +++ b/packages/angular/build/src/tools/esbuild/bundler-context.ts @@ -328,7 +328,11 @@ export class BundlerContext { const initialFiles = new Map(); for (const outputFile of result.outputFiles) { // Entries in the metafile are relative to the `absWorkingDir` option which is set to the workspaceRoot - const relativeFilePath = relative(this.workspaceRoot, outputFile.path); + // `outputFile.path` may already be relative if the `OutputFile` instance was cached in `additionalResults` + // across an incremental rebuild. + const relativeFilePath = isAbsolute(outputFile.path) + ? relative(this.workspaceRoot, outputFile.path) + : outputFile.path; const entryPoint = result.metafile.outputs[relativeFilePath]?.entryPoint; outputFile.path = relativeFilePath; From 1f31103f206c41226e057f396e1ea1e574a6a650 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Tue, 13 Oct 2026 13:28:36 +0000 Subject: [PATCH 21/52] refactor(@angular/build): flatten builderName in cache directory path Strip '@' and replace '/' in addition to ':' when normalizing builderName in normalizeCacheOptions so scoped builder names produce a single flat cache directory instead of nested subdirectories. --- packages/angular/build/src/utils/normalize-cache.ts | 2 +- packages/angular/build/src/utils/normalize-cache_spec.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/angular/build/src/utils/normalize-cache.ts b/packages/angular/build/src/utils/normalize-cache.ts index e24eaf8627c8..bb24f774f79b 100644 --- a/packages/angular/build/src/utils/normalize-cache.ts +++ b/packages/angular/build/src/utils/normalize-cache.ts @@ -140,7 +140,7 @@ export function normalizeCacheOptions( const cacheBasePath = getCacheBasePath(workspaceRoot, path); const localCacheBasePath = isAbsolute(path) ? path : resolve(workspaceRoot, path); - const normalizedBuilderName = builderName.replaceAll(':', '-'); + const normalizedBuilderName = builderName.replace('@', '').replaceAll(/[:/]/g, '-'); return { enabled: cacheEnabled, diff --git a/packages/angular/build/src/utils/normalize-cache_spec.ts b/packages/angular/build/src/utils/normalize-cache_spec.ts index 18e75403756d..1a0520c96a96 100644 --- a/packages/angular/build/src/utils/normalize-cache_spec.ts +++ b/packages/angular/build/src/utils/normalize-cache_spec.ts @@ -283,10 +283,10 @@ describe('normalizeCacheOptions', () => { const options = normalizeCacheOptions({}, workspaceRoot, 'my-app', '@angular/build:unit-test'); expect(options.path).toBe( - resolve(workspaceRoot, '.angular/cache/0.0.0-PLACEHOLDER/my-app/@angular/build-unit-test'), + resolve(workspaceRoot, '.angular/cache/0.0.0-PLACEHOLDER/my-app/angular-build-unit-test'), ); expect(options.localPath).toBe( - resolve(workspaceRoot, '.angular/cache/0.0.0-PLACEHOLDER/my-app/@angular/build-unit-test'), + resolve(workspaceRoot, '.angular/cache/0.0.0-PLACEHOLDER/my-app/angular-build-unit-test'), ); }); }); From 4951994f64f6243f88f28b1174e38e3b25f69ea4 Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Tue, 13 Oct 2026 16:52:05 +0200 Subject: [PATCH 22/52] refactor(@angular/build): unify and deduplicate emitFilesToDisk across builders Relocate emitFilesToDisk into src/utils/emit-files-to-disk.ts and unify the file emission descriptor shape across the application and library builders around origin ('memory' | 'disk') and source. --- .../src/builders/application/build-action.ts | 4 +- .../build/src/builders/application/index.ts | 40 +++-------- .../build/src/builders/application/results.ts | 2 +- .../src/builders/dev-server/vite/utils.ts | 2 +- .../extract-i18n/application-extraction.ts | 2 +- .../src/builders/karma/assets-middleware.ts | 2 +- .../builders/library/pipeline/build-action.ts | 21 +----- .../src/builders/library/pipeline/utils.ts | 8 +-- .../library/tests/behavior/watch_spec.ts | 38 ++++++++++ .../build/src/builders/library/types.ts | 3 - .../unit-test/runners/vitest/plugins.ts | 2 +- packages/angular/build/src/private.ts | 2 +- .../angular/build/src/tools/esbuild/utils.ts | 24 +------ .../vite/middlewares/assets-middleware.ts | 2 +- .../build/src/utils/emit-files-to-disk.ts | 71 +++++++++++++++++++ .../src/utils/emit-files-to-disk_spec.ts | 53 ++++++++++++++ .../angular/build/src/utils/test-files.ts | 33 ++------- .../extract-i18n/application-extraction.ts | 2 +- 18 files changed, 196 insertions(+), 115 deletions(-) create mode 100644 packages/angular/build/src/utils/emit-files-to-disk.ts create mode 100644 packages/angular/build/src/utils/emit-files-to-disk_spec.ts diff --git a/packages/angular/build/src/builders/application/build-action.ts b/packages/angular/build/src/builders/application/build-action.ts index b728ab9a8df5..eaae50848a48 100644 --- a/packages/angular/build/src/builders/application/build-action.ts +++ b/packages/angular/build/src/builders/application/build-action.ts @@ -333,7 +333,7 @@ function* emitOutputResults( incrementalResult.files.push({ path: destination, type: BuildOutputFileType.Browser, - inputPath: source, + source, origin: 'disk', }); } @@ -406,7 +406,7 @@ function createFullResult( ...assetFiles.map(({ source, destination }) => ({ path: destination, type: BuildOutputFileType.Browser, - inputPath: source, + source, origin: 'disk' as const, })), ...outputFiles.map((file) => ({ diff --git a/packages/angular/build/src/builders/application/index.ts b/packages/angular/build/src/builders/application/index.ts index 59ded1cd8182..f1b16a27e394 100644 --- a/packages/angular/build/src/builders/application/index.ts +++ b/packages/angular/build/src/builders/application/index.ts @@ -11,9 +11,10 @@ import assert from 'node:assert'; import fs from 'node:fs/promises'; import path from 'node:path'; import { BuildOutputFileType } from '../../tools/esbuild/bundler-files'; -import { createJsonBuildManifest, emitFilesToDisk } from '../../tools/esbuild/utils'; +import { createJsonBuildManifest } from '../../tools/esbuild/utils'; import { colors as ansiColors } from '../../utils/color'; import { deleteOutputDir } from '../../utils/delete-output-dir'; +import { emitFilesToDisk } from '../../utils/emit-files-to-disk'; import { bazelEsbuildPluginPath, useJSONBuildLogs } from '../../utils/environment-options'; import { isSubDirectory } from '../../utils/path'; import { purgeStaleBuildCache } from '../../utils/purge-cache'; @@ -197,37 +198,14 @@ export async function* buildApplication( } // Writes the output files to disk and ensures the containing directories are present - const directoryExists = new Set(); try { - await emitFilesToDisk(result.files, async (file) => { - if ( - outputOptions.ignoreServer && - (file.type === BuildOutputFileType.ServerApplication || - file.type === BuildOutputFileType.ServerRoot) - ) { - return; - } - - const fullFilePath = generateFullPath(file.path, file.type, outputOptions); - - // Ensure output subdirectories exist - const fileBasePath = path.dirname(fullFilePath); - if (fileBasePath && !directoryExists.has(fileBasePath)) { - await fs.mkdir(fileBasePath, { recursive: true }); - directoryExists.add(fileBasePath); - } - - if (file.origin === 'memory') { - // Write file contents - await fs.writeFile(fullFilePath, file.contents); - } else { - // Copy file contents - await fs.cp(file.inputPath, fullFilePath, { - mode: fs.constants.COPYFILE_FICLONE, - preserveTimestamps: true, - }); - } - }); + await emitFilesToDisk(result.files, (file) => + outputOptions.ignoreServer && + (file.type === BuildOutputFileType.ServerApplication || + file.type === BuildOutputFileType.ServerRoot) + ? undefined + : generateFullPath(file.path, file.type, outputOptions), + ); } catch (error) { context.logger.error(error instanceof Error ? error.message : String(error)); yield { success: false }; diff --git a/packages/angular/build/src/builders/application/results.ts b/packages/angular/build/src/builders/application/results.ts index 8e95176639f5..e9bd786a3fe6 100644 --- a/packages/angular/build/src/builders/application/results.ts +++ b/packages/angular/build/src/builders/application/results.ts @@ -53,7 +53,7 @@ export interface BaseResultFile { export interface DiskFile extends BaseResultFile { origin: 'disk'; - inputPath: string; + source: string; } export interface MemoryFile extends BaseResultFile { diff --git a/packages/angular/build/src/builders/dev-server/vite/utils.ts b/packages/angular/build/src/builders/dev-server/vite/utils.ts index bc2d4a513b5a..4a0b85b9324a 100644 --- a/packages/angular/build/src/builders/dev-server/vite/utils.ts +++ b/packages/angular/build/src/builders/dev-server/vite/utils.ts @@ -40,7 +40,7 @@ export function updateResultRecord( ): void { if (file.origin === 'disk') { assetFiles.set('/' + normalizePath(file.path), { - source: normalizePath(file.inputPath), + source: normalizePath(file.source), updated: !initial, }); diff --git a/packages/angular/build/src/builders/extract-i18n/application-extraction.ts b/packages/angular/build/src/builders/extract-i18n/application-extraction.ts index b18c8164481f..02233fade493 100644 --- a/packages/angular/build/src/builders/extract-i18n/application-extraction.ts +++ b/packages/angular/build/src/builders/extract-i18n/application-extraction.ts @@ -107,7 +107,7 @@ function setupLocalizeExtractor( if (file?.origin === 'memory') { content = textDecoder.decode(file.contents); } else if (file?.origin === 'disk') { - content = readFileSync(file.inputPath, 'utf-8'); + content = readFileSync(file.source, 'utf-8'); } if (content === undefined) { throw new Error('Unknown file requested: ' + requestedPath); diff --git a/packages/angular/build/src/builders/karma/assets-middleware.ts b/packages/angular/build/src/builders/karma/assets-middleware.ts index 45483cb4ec41..6f04faffae46 100644 --- a/packages/angular/build/src/builders/karma/assets-middleware.ts +++ b/packages/angular/build/src/builders/karma/assets-middleware.ts @@ -60,7 +60,7 @@ export class AngularAssetsMiddleware { // https://github.com/karma-runner/karma/blob/84f85e7016efc2266fa6b3465f494a3fa151c85c/lib/middleware/common.js#L10 switch (file.origin) { case 'disk': - this.serveFile(file.inputPath, undefined, res, undefined, undefined, /* doNotCache */ true); + this.serveFile(file.source, undefined, res, undefined, undefined, /* doNotCache */ true); break; case 'memory': // Include pathname to help with Content-Type headers. diff --git a/packages/angular/build/src/builders/library/pipeline/build-action.ts b/packages/angular/build/src/builders/library/pipeline/build-action.ts index 294eb954421b..a430312ac925 100644 --- a/packages/angular/build/src/builders/library/pipeline/build-action.ts +++ b/packages/angular/build/src/builders/library/pipeline/build-action.ts @@ -7,10 +7,9 @@ */ import type { BuilderContext } from '@angular-devkit/architect'; -import { constants, copyFile, mkdir, writeFile } from 'node:fs/promises'; import path from 'node:path'; import type { ComponentStylesheetBundler } from '../../../tools/esbuild/angular/component-stylesheets'; -import { emitFilesToDisk } from '../../../tools/esbuild/utils'; +import { emitFilesToDisk } from '../../../utils/emit-files-to-disk'; import { toPosixPath } from '../../../utils/path'; import type { NormalizedLibraryOptions, SingleBuildState } from '../types'; import { collectAssetsToEmit } from './assets'; @@ -27,7 +26,6 @@ export function createSingleBuildState(): SingleBuildState { previousBundleResults: new Map(), pendingChangedEsmFiles: new Set(), pendingChangedDtsFiles: new Set(), - directoryExists: new Set(), }; } @@ -90,7 +88,7 @@ export async function buildAction(actionContext: BuildActionContext): Promise(filesToEmit, async (file) => { - const fullFilePath = path.join(options.outputPath, file.path); - const fileBasePath = path.dirname(fullFilePath); - if (fileBasePath && !directoryExists.has(fileBasePath)) { - await mkdir(fileBasePath, { recursive: true }); - directoryExists.add(fileBasePath); - } - - if (file.type === 'memory') { - await writeFile(fullFilePath, file.contents); - } else { - await copyFile(file.source, fullFilePath, constants.COPYFILE_FICLONE); - } - }); + await emitFilesToDisk(filesToEmit, (file) => path.join(options.outputPath, file.path)); buildState.hasEmittedManifests = true; buildState.hasEmittedTslib = hasTslibImport; diff --git a/packages/angular/build/src/builders/library/pipeline/utils.ts b/packages/angular/build/src/builders/library/pipeline/utils.ts index 8258c8874e42..9092a73005ef 100644 --- a/packages/angular/build/src/builders/library/pipeline/utils.ts +++ b/packages/angular/build/src/builders/library/pipeline/utils.ts @@ -26,7 +26,7 @@ export const TYPES_OUTPUT_DIR = 'types'; * Represents an in-memory file to be emitted to disk. */ export interface MemoryOutputFile { - type: 'memory'; + origin: 'memory'; /** The destination path where the file should be written. */ path: string; @@ -39,7 +39,7 @@ export interface MemoryOutputFile { * Represents an existing file on disk to be copied to a destination path. */ export interface DiskOutputFile { - type: 'disk'; + origin: 'disk'; /** The path to the source file on disk. */ source: string; @@ -62,7 +62,7 @@ export type OutputFile = MemoryOutputFile | DiskOutputFile; */ export function createDiskOutputFile(source: string, path: string): DiskOutputFile { return { - type: 'disk', + origin: 'disk', source, path, }; @@ -80,7 +80,7 @@ export function createMemoryOutputFile( contents: string | Uint8Array | Record, ): MemoryOutputFile { return { - type: 'memory', + origin: 'memory', path, contents: typeof contents === 'string' || contents instanceof Uint8Array diff --git a/packages/angular/build/src/builders/library/tests/behavior/watch_spec.ts b/packages/angular/build/src/builders/library/tests/behavior/watch_spec.ts index 2533da417909..415f24d269c0 100644 --- a/packages/angular/build/src/builders/library/tests/behavior/watch_spec.ts +++ b/packages/angular/build/src/builders/library/tests/behavior/watch_spec.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ +import { rm } from 'node:fs/promises'; import { executeLibraryBuilder } from '../../builder'; import { BASE_OPTIONS, LIBRARY_BUILDER_INFO, describeLibraryBuilder } from '../setup'; @@ -563,5 +564,42 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => }, ]); }); + + it('should recreate deleted output directories on subsequent watch rebuilds', async () => { + harness.useTarget('build', { + ...BASE_OPTIONS, + watch: true, + }); + + await harness.executeWithCases([ + async ({ result }) => { + expect(result?.success).toBeTrue(); + expect(harness.hasFile('dist/lib/fesm2022/lib.mjs')).toBeTrue(); + + // Remove output subdirectory externally between rebuilds + await rm(harness.resolvePath('dist/lib/fesm2022'), { recursive: true, force: true }); + expect(harness.hasFile('dist/lib/fesm2022/lib.mjs')).toBeFalse(); + + // Trigger a rebuild + await harness.writeFile( + 'projects/lib/src/lib/lib.component.ts', + ` + import { Component } from '@angular/core'; + + @Component({ + selector: 'lib-recreated', + template: 'Recreated', + }) + export class LibComponent {} + `, + ); + }, + ({ result }) => { + expect(result?.success).toBeTrue(); + const content = harness.readFile('dist/lib/fesm2022/lib.mjs'); + expect(content).toContain('lib-recreated'); + }, + ]); + }); }); }); diff --git a/packages/angular/build/src/builders/library/types.ts b/packages/angular/build/src/builders/library/types.ts index 7ec8545a9c8e..d360cfe2c868 100644 --- a/packages/angular/build/src/builders/library/types.ts +++ b/packages/angular/build/src/builders/library/types.ts @@ -153,7 +153,4 @@ export interface SingleBuildState { /** Whether entry points in package.json changed since the last compilation. */ hasEntryPointsChanges?: boolean; - - /** Cache of output directory paths known to exist on disk. */ - directoryExists: Set; } diff --git a/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts b/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts index 0a8a2c8990b4..72308b6b57d6 100644 --- a/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts +++ b/packages/angular/build/src/builders/unit-test/runners/vitest/plugins.ts @@ -322,7 +322,7 @@ async function loadResultFile(file: ResultFile): Promise { return textDecoder.decode(file.contents); } - return readFile(file.inputPath, 'utf-8'); + return readFile(file.source, 'utf-8'); } export function createVitestPlugins(pluginOptions: PluginOptions): Vite.Plugin[] { diff --git a/packages/angular/build/src/private.ts b/packages/angular/build/src/private.ts index 9db709640b57..6f98e4f8f0e9 100644 --- a/packages/angular/build/src/private.ts +++ b/packages/angular/build/src/private.ts @@ -34,7 +34,6 @@ export { // Tools export type { ExternalResultMetadata } from './tools/esbuild/bundler-execution-result'; -export { emitFilesToDisk } from './tools/esbuild/utils'; export { transformSupportedBrowsersToTargets } from './tools/esbuild/target'; export { SassCompiler } from './tools/sass/sass-service'; @@ -73,6 +72,7 @@ export { ComponentStylesheetBundler } from './tools/esbuild/angular/component-st export * from './utils/bundle-calculator'; export { checkPort } from './utils/check-port'; export { deleteOutputDir } from './utils/delete-output-dir'; +export { emitFilesToDisk } from './utils/emit-files-to-disk'; export { type I18nOptions, createI18nOptions, loadTranslations } from './utils/i18n-options'; export { IndexHtmlGenerator, diff --git a/packages/angular/build/src/tools/esbuild/utils.ts b/packages/angular/build/src/tools/esbuild/utils.ts index 3bbaabdd2400..e93bb295b439 100644 --- a/packages/angular/build/src/tools/esbuild/utils.ts +++ b/packages/angular/build/src/tools/esbuild/utils.ts @@ -17,11 +17,7 @@ import { OutputMode } from '../../builders/application/schema'; import { BudgetCalculatorResult } from '../../utils/bundle-calculator'; import { BundleStats, generateEsbuildBuildStatsTable } from '../../utils/stats-table'; -import { - BuildOutputAsset, - ExecutionResult, - PrerenderedRoutesRecord, -} from './bundler-execution-result'; +import { ExecutionResult, PrerenderedRoutesRecord } from './bundler-execution-result'; import { type BuildOutputFile, BuildOutputFileType, type InitialFileRecord } from './bundler-files'; export function logBuildStats( @@ -212,24 +208,6 @@ export function getFeatureSupport(nativeAsyncAwait: boolean): BuildOptions['supp }; } -const MAX_CONCURRENT_WRITES = 64; -export async function emitFilesToDisk( - files: readonly T[], - writeFileCallback: (file: T) => Promise, -): Promise { - // Write files in groups of MAX_CONCURRENT_WRITES to avoid too many open files - for (let fileIndex = 0; fileIndex < files.length;) { - const groupMax = Math.min(fileIndex + MAX_CONCURRENT_WRITES, files.length); - - const actions = []; - while (fileIndex < groupMax) { - actions.push(writeFileCallback(files[fileIndex++])); - } - - await Promise.all(actions); - } -} - interface BuildManifest { errors: string[]; warnings: string[]; diff --git a/packages/angular/build/src/tools/vite/middlewares/assets-middleware.ts b/packages/angular/build/src/tools/vite/middlewares/assets-middleware.ts index 3c38d000b30c..a1aa19361c5c 100644 --- a/packages/angular/build/src/tools/vite/middlewares/assets-middleware.ts +++ b/packages/angular/build/src/tools/vite/middlewares/assets-middleware.ts @@ -236,7 +236,7 @@ export function createBuildAssetsMiddleware( const outputFile = buildResultFiles.get(pathname.slice(1)); if (outputFile) { const contents = - outputFile.origin === 'memory' ? outputFile.contents : readHandler(outputFile.inputPath); + outputFile.origin === 'memory' ? outputFile.contents : readHandler(outputFile.source); const etag = `W/${calculateHash(contents)}`; if (checkAndHandleEtag(req, res, etag)) { diff --git a/packages/angular/build/src/utils/emit-files-to-disk.ts b/packages/angular/build/src/utils/emit-files-to-disk.ts new file mode 100644 index 000000000000..b6df74088451 --- /dev/null +++ b/packages/angular/build/src/utils/emit-files-to-disk.ts @@ -0,0 +1,71 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { constants, cp, mkdir, writeFile } from 'node:fs/promises'; +import { dirname } from 'node:path'; +import { runConcurrent } from './concurrency'; + +/** + * Maximum number of concurrent file system write/copy operations to avoid open file descriptor exhaustion. + */ +const MAX_CONCURRENT_WRITES = 64; + +/** + * Represents a file that can be emitted to disk from memory or copied from an existing path on disk. + */ +export type EmittableFile = + { origin: 'memory'; contents: string | Uint8Array } | { origin: 'disk'; source: string }; + +/** + * Writes or copies a collection of files to disk with bounded concurrency, + * ensuring parent directories are created once per invocation. + * + * @param files The collection of files to emit. + * @param resolveDestinationPath Callback returning the absolute destination path for a file, or `undefined` to skip it. + */ +export async function emitFilesToDisk( + files: readonly T[], + resolveDestinationPath: (file: T) => string | undefined, +): Promise { + if (files.length === 0) { + return; + } + + const directoryCreationPromises = new Map>(); + + await runConcurrent(files, MAX_CONCURRENT_WRITES, async (file) => { + const fullFilePath = resolveDestinationPath(file); + if (!fullFilePath) { + return; + } + + // Ensure output subdirectories exist + const fileBasePath = dirname(fullFilePath); + if (fileBasePath) { + let mkdirPromise = directoryCreationPromises.get(fileBasePath); + if (!mkdirPromise) { + mkdirPromise = mkdir(fileBasePath, { recursive: true }); + directoryCreationPromises.set(fileBasePath, mkdirPromise); + } + await mkdirPromise; + } + + if (file.origin === 'memory') { + // Write file contents + await writeFile(fullFilePath, file.contents); + + return; + } + + // Copy file contents + await cp(file.source, fullFilePath, { + mode: constants.COPYFILE_FICLONE, + preserveTimestamps: true, + }); + }); +} diff --git a/packages/angular/build/src/utils/emit-files-to-disk_spec.ts b/packages/angular/build/src/utils/emit-files-to-disk_spec.ts new file mode 100644 index 000000000000..028653028b43 --- /dev/null +++ b/packages/angular/build/src/utils/emit-files-to-disk_spec.ts @@ -0,0 +1,53 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import assert from 'node:assert'; +import { existsSync } from 'node:fs'; +import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import { type EmittableFile, emitFilesToDisk } from './emit-files-to-disk'; + +describe('emitFilesToDisk', () => { + let tempRoot: string; + + beforeEach(async () => { + const baseTmpDir = process.env['TEST_TMPDIR']; + assert(baseTmpDir, 'TEST_TMPDIR is not set'); + tempRoot = await mkdtemp(join(baseTmpDir, 'angular-cli-emit-files-test-')); + }); + + afterEach(async () => { + if (tempRoot) { + await rm(tempRoot, { recursive: true, force: true }); + } + }); + + it('should write memory files and copy disk files while creating nested directories', async () => { + const sourceFile = join(tempRoot, 'source-asset.txt'); + await writeFile(sourceFile, 'from-disk'); + + const files: (EmittableFile & { path: string })[] = [ + { origin: 'memory', path: 'nested/a/mem1.txt', contents: new TextEncoder().encode('mem-1') }, + { origin: 'memory', path: 'nested/a/mem2.txt', contents: 'mem-2' }, + { origin: 'disk', path: 'nested/b/disk1.txt', source: sourceFile }, + { origin: 'disk', path: 'nested/c/disk2.txt', source: sourceFile }, + { origin: 'memory', path: 'skipped/file.txt', contents: 'should-not-exist' }, + ]; + + const outDir = join(tempRoot, 'out'); + await emitFilesToDisk(files, (file) => + file.path.startsWith('skipped/') ? undefined : join(outDir, file.path), + ); + + expect(await readFile(join(outDir, 'nested/a/mem1.txt'), 'utf-8')).toBe('mem-1'); + expect(await readFile(join(outDir, 'nested/a/mem2.txt'), 'utf-8')).toBe('mem-2'); + expect(await readFile(join(outDir, 'nested/b/disk1.txt'), 'utf-8')).toBe('from-disk'); + expect(await readFile(join(outDir, 'nested/c/disk2.txt'), 'utf-8')).toBe('from-disk'); + expect(existsSync(join(outDir, 'skipped/file.txt'))).toBeFalse(); + }); +}); diff --git a/packages/angular/build/src/utils/test-files.ts b/packages/angular/build/src/utils/test-files.ts index 6790d007e220..db480686b66a 100644 --- a/packages/angular/build/src/utils/test-files.ts +++ b/packages/angular/build/src/utils/test-files.ts @@ -6,11 +6,10 @@ * found in the LICENSE file at https://angular.dev/license */ -import * as fs from 'node:fs/promises'; import path from 'node:path'; import { ResultFile } from '../builders/application/results'; import { BuildOutputFileType } from '../tools/esbuild/bundler-files'; -import { emitFilesToDisk } from '../tools/esbuild/utils'; +import { emitFilesToDisk } from './emit-files-to-disk'; /** * Writes a collection of build result files to a specified directory. @@ -20,29 +19,11 @@ import { emitFilesToDisk } from '../tools/esbuild/utils'; * @param files A collection of `ResultFile` objects, representing the build output. * @param testDir The absolute path to the directory where the files should be written. */ -export async function writeTestFiles(files: readonly ResultFile[], testDir: string): Promise { - const directoryExists = new Set(); +export function writeTestFiles(files: readonly ResultFile[], testDir: string): Promise { // Writes the test related output files to disk and ensures the containing directories are present - await emitFilesToDisk(files, async (file) => { - if (file.type !== BuildOutputFileType.Browser && file.type !== BuildOutputFileType.Media) { - return; - } - - const fullFilePath = path.join(testDir, file.path); - - // Ensure output subdirectories exist - const fileBasePath = path.dirname(fullFilePath); - if (fileBasePath && !directoryExists.has(fileBasePath)) { - await fs.mkdir(fileBasePath, { recursive: true }); - directoryExists.add(fileBasePath); - } - - if (file.origin === 'memory') { - // Write file contents - await fs.writeFile(fullFilePath, file.contents); - } else { - // Copy file contents - await fs.copyFile(file.inputPath, fullFilePath, fs.constants.COPYFILE_FICLONE); - } - }); + return emitFilesToDisk(files, (file) => + file.type === BuildOutputFileType.Browser || file.type === BuildOutputFileType.Media + ? path.join(testDir, file.path) + : undefined, + ); } diff --git a/packages/angular_devkit/build_angular/src/builders/extract-i18n/application-extraction.ts b/packages/angular_devkit/build_angular/src/builders/extract-i18n/application-extraction.ts index 68347fa0fb24..508b27e2d833 100644 --- a/packages/angular_devkit/build_angular/src/builders/extract-i18n/application-extraction.ts +++ b/packages/angular_devkit/build_angular/src/builders/extract-i18n/application-extraction.ts @@ -112,7 +112,7 @@ function setupLocalizeExtractor( if (file?.origin === 'memory') { content = textDecoder.decode(file.contents); } else if (file?.origin === 'disk') { - content = readFileSync(file.inputPath, 'utf-8'); + content = readFileSync(file.source, 'utf-8'); } if (content === undefined) { throw new Error('Unknown file requested: ' + requestedPath); From 9c645ece55f190ed7176ed8135ee0e5d30103c1e Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Tue, 13 Oct 2026 15:21:37 +0000 Subject: [PATCH 23/52] refactor(@angular/build): use import resolution-mode for rolldown-plugin-dts types Use `{ with: { 'resolution-mode': 'import' } }` on the dynamic import type assertion for `rolldown-plugin-dts` and remove the custom ambient module declaration file (`types.d.ts`). --- .../src/builders/library/pipeline/bundler.ts | 5 +- .../src/builders/library/pipeline/types.d.ts | 54 ------------------- 2 files changed, 4 insertions(+), 55 deletions(-) delete mode 100644 packages/angular/build/src/builders/library/pipeline/types.d.ts diff --git a/packages/angular/build/src/builders/library/pipeline/bundler.ts b/packages/angular/build/src/builders/library/pipeline/bundler.ts index 64042bd37f92..5cd89a4b110d 100644 --- a/packages/angular/build/src/builders/library/pipeline/bundler.ts +++ b/packages/angular/build/src/builders/library/pipeline/bundler.ts @@ -439,7 +439,10 @@ async function bundleAllDts( // Ensure Rolldown's native binding is initialized via `loadRolldown()` before evaluating // `rolldown-plugin-dts`, which has top-level imports of `rolldown/experimental`. await loadRolldown(); - const { dts } = await import('rolldown-plugin-dts'); + const { dts } = (await import('rolldown-plugin-dts' as string)) as typeof import( + 'rolldown-plugin-dts', + { with: { 'resolution-mode': 'import' } } + ); const dtsSourcemap = !!options.declarationMap; // Filter out `rolldown-plugin-dts:resolver` because all `.d.ts` files are already emitted diff --git a/packages/angular/build/src/builders/library/pipeline/types.d.ts b/packages/angular/build/src/builders/library/pipeline/types.d.ts deleted file mode 100644 index 100c539f098c..000000000000 --- a/packages/angular/build/src/builders/library/pipeline/types.d.ts +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -declare module 'rolldown-plugin-dts' { - import type { Plugin } from 'rolldown'; - import type { IsolatedDeclarationsOptions } from 'rolldown/experimental'; - - interface Logger { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - } - interface GeneralOptions { - generator?: 'tsc' | 'oxc' | 'tsgo'; - entry?: string | string[]; - cwd?: string; - dtsInput?: boolean; - emitDtsOnly?: boolean; - tsconfig?: string | boolean; - tsconfigRaw?: unknown; - compilerOptions?: unknown; - sourcemap?: boolean; - resolver?: 'oxc' | 'tsc'; - cjsDefault?: boolean; - sideEffects?: boolean; - logger?: Logger; - } - - interface TscOptions { - build?: boolean; - incremental?: boolean; - parallel?: boolean; - eager?: boolean; - newContext?: boolean; - emitJs?: boolean; - } - - interface Options extends GeneralOptions, TscOptions { - oxc?: Omit; - tsgo?: TsgoOptions; - customLanguages?: unknown[]; - } - - interface TsgoOptions { - path?: string; - } - - export declare function dts(options?: Options): Plugin[]; -} From 95548f5ca757ec8305a633df85a198d68c4eae4a Mon Sep 17 00:00:00 2001 From: Angular Robot Date: Tue, 13 Oct 2026 06:55:37 +0000 Subject: [PATCH 24/52] build: lock file maintenance See associated pull request for more information. --- MODULE.bazel.lock | 2 +- pnpm-lock.yaml | 684 ++++++++++++---------------------------------- 2 files changed, 181 insertions(+), 505 deletions(-) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 38524a59eced..5f2282f7683b 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -384,7 +384,7 @@ "aspect_rules_jasmine": "2.0.4", "aspect_tools_telemetry": "0.5.2" }, - "last_notice": 3 + "last_notice": 0 } } }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b6cf96a9c926..2d1df736b28c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -293,7 +293,7 @@ importers: version: 3.0.0(esbuild@0.28.2)(lightningcss@1.33.0)(uglify-js@3.19.3) '@types/lodash': specifier: ^4.17.0 - version: 4.17.25 + version: 4.17.26 '@types/node': specifier: ^22.12.0 version: 22.20.5 @@ -398,7 +398,7 @@ importers: version: 1.4.3 prettier: specifier: ^3.0.0 - version: 3.9.9 + version: 3.9.10 puppeteer: specifier: 25.12.0 version: 25.12.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -431,7 +431,7 @@ importers: version: 6.10.5(encoding@0.1.13)(supports-color@11.0.0) verdaccio-auth-memory: specifier: ^13.0.0 - version: 13.1.5(supports-color@11.0.0) + version: 13.1.6(supports-color@11.0.0) zone.js: specifier: ^0.16.0 version: 0.16.3 @@ -899,10 +899,10 @@ importers: version: link:../../ngtools/webpack webpack: specifier: 5.111.1 - version: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.28)(uglify-js@3.19.3) + version: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3) webpack-dev-server: specifier: 6.0.0 - version: 6.0.0(bufferutil@4.1.0)(supports-color@11.0.0)(utf-8-validate@6.0.6)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.28)(uglify-js@3.19.3)) + version: 6.0.0(bufferutil@4.1.0)(supports-color@11.0.0)(utf-8-validate@6.0.6)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)) packages/angular_devkit/core: dependencies: @@ -975,7 +975,7 @@ importers: version: 6.0.3 webpack: specifier: 5.111.1 - version: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.28)(uglify-js@3.19.3) + version: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3) packages/schematics/angular: dependencies: @@ -1149,8 +1149,8 @@ packages: '@angular/core': 22.3.0-next.1 rxjs: ^6.5.3 || ^7.4.0 - '@asamuzakjp/css-color@7.1.3': - resolution: {integrity: sha512-1t1U8Cm3RBl9vh3RAZhjkPaduzLSvQJRToRrxpGR/eDRW99mOREleuu+mWfiFa795bUzjwht7NgphCKTs2ianQ==} + '@asamuzakjp/css-color@7.1.5': + resolution: {integrity: sha512-jCpAvj8apa7SKHZYogk0rbXB3Kb0hLFrpkWF+Ap+vBA5rirItnpv9NKyAyEuDuFizvl0qwnj6JWR70RGJ0rOlw==} engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} '@asamuzakjp/dom-selector@9.2.4': @@ -1201,22 +1201,18 @@ packages: resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@8.0.6': - resolution: {integrity: sha512-HTrtZ4+iA0+kzdbCgvdSk1U4pEl3BvpGnlUbualCGNbrVhhQvhgBzurTUmqpWyvyHbWYWaIfdx2mOlL9LJjsew==} - engines: {node: ^22.18.0 || >=24.11.0} - '@babel/helper-compilation-targets@8.0.7': resolution: {integrity: sha512-ilAZCdOOlOVA7dQbaFNw2f/59p6GW33NxTopc3DvEE3efp3ZXTrGX/yZScaKw8/vd9bq31Ag0EcXiLw32bAgJg==} engines: {node: ^22.18.0 || >=24.11.0} - '@babel/helper-create-class-features-plugin@8.0.6': - resolution: {integrity: sha512-Hy7wG2Pk1LnAkFMq0CbBk789XMTYVzYGxR7tKgk+TOpZckQRME3Tdou4mMT/8DFjJFxFZ8R6UsS4DR/duBKlVA==} + '@babel/helper-create-class-features-plugin@8.0.7': + resolution: {integrity: sha512-7ug3KrOhNVPPxFFLTel0/pMzimKzU/vTlNJKVL/dKguCpmNJZjjibyFbWg+Qs8QHmiIZPNuZ2UNnDGdHWGEpOg==} engines: {node: ^22.18.0 || >=24.11.0} peerDependencies: '@babel/core': ^8.0.0 - '@babel/helper-create-regexp-features-plugin@8.0.5': - resolution: {integrity: sha512-TWnIgw21pAv/FbBKB8ks26DMxQ+A3aBdi1HUBp+QhqSE8QdOqJgSK/FEvdMYPTZcHBBJPZ5pN6DDKmC5ZYPJbg==} + '@babel/helper-create-regexp-features-plugin@8.0.7': + resolution: {integrity: sha512-pyia4a5cQ9fmUuimPO4pl3p8aX9aGBBMqZyNUmwhJGO/e3bIbbt/26Zun6SE1CRvNaUWiTsfLuZeaLX6EIIUWQ==} engines: {node: ^22.18.0 || >=24.11.0} peerDependencies: '@babel/core': ^8.0.0 @@ -1317,8 +1313,8 @@ packages: resolution: {integrity: sha512-Qpm8+wi5xfDkBfollanwriCcKniFfBmMmaKB01GVM6VGzKXo1fdxosZp04qEr5HM+LKhwr3hG1yRy8+ORsficA==} engines: {node: ^22.18.0 || >=24.11.0} - '@babel/helpers@7.29.7': - resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + '@babel/helpers@7.29.10': + resolution: {integrity: sha512-EMCx3AGZ3WfAl6ht7AyQoPm2Lh+BGYEMdc4Q6Hf7uSCDOZFuLq44qNwL+iaim8VlyYhRAo4X43+weadK8ZB4Yg==} engines: {node: '>=6.9.0'} '@babel/helpers@8.0.7': @@ -1330,11 +1326,6 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/parser@8.0.6': - resolution: {integrity: sha512-LpGDIYJAzc3Y3PT9x+FxBrGYu2PlWxLmyN7SwPTzaX0LSwEmFJBsRnPBqmaXF2r1v+Zhz6lNiEJ+7yKtM5+Ugg==} - engines: {node: ^22.18.0 || >=24.11.0} - hasBin: true - '@babel/parser@8.0.7': resolution: {integrity: sha512-UkDwEbPO1px2JQSrdh4qIgaH1JgG7GO/pFeJkpxhDxIETkT/QvGpnigXIw75ViHYPtIgKITmVUJqLjiO+JuWjA==} engines: {node: ^22.18.0 || >=24.11.0} @@ -1710,14 +1701,10 @@ packages: resolution: {integrity: sha512-eAD0QW/AlbamBbw0FeGiwasbCVPq5ncW0HNVyLP3B9czqLyh4gvw+5JTSNt6le9+ziAU7mqDZsKTHf3jTb4chQ==} engines: {node: ^22.18.0 || >=24.11.0} - '@babel/traverse@7.29.8': - resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==} + '@babel/traverse@7.29.10': + resolution: {integrity: sha512-B3lYAs2nkKskbgQ1nfy8Ma9ao9Q1rntTAQHrzzyDuj+TSO+X3le6PfWwqDvodsb+OumE10eMFfuMCTQSQ5iuIQ==} engines: {node: '>=6.9.0'} - '@babel/traverse@8.0.6': - resolution: {integrity: sha512-ilYV+qLStGzSKLipJlETdvdtpK3rAuwfCmCoGKv15MU4EoeIuLkespSNoNLFGOPSciEHx9TLWtN5mv0fz5w5mQ==} - engines: {node: ^22.18.0 || >=24.11.0} - '@babel/traverse@8.0.7': resolution: {integrity: sha512-bVV0brinsTWgc6ptSIoQo3GbITtl0VZAqEUJbHHcyfDPEu+q/fEvlYEa+6H85HoK8IdksKBFtKJbJFZ6Kff+zg==} engines: {node: ^22.18.0 || >=24.11.0} @@ -1746,8 +1733,8 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} - '@bramus/specificity@2.4.2': - resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} + '@bramus/specificity@2.4.3': + resolution: {integrity: sha512-0GEz8qJWokkUVYQYRukmkSHIFNoBH8QTreeHrAFbvz1XFYc3Y+puhMs8PQ5x8GNugiC2l5jvDBXKLbBIByeSBw==} hasBin: true '@bufbuild/protobuf@2.16.0': @@ -2304,8 +2291,8 @@ packages: '@modelcontextprotocol/sdk': optional: true - '@grpc/grpc-js@1.14.5': - resolution: {integrity: sha512-7VZM+SVdEcUUqSQeNI3zM8Qs/BhQKZndPo2h5VkYkAM8Iz0wJIa8mKV5ekQGqG8UUsnkQ0NMxIxwkIHYvj0qOw==} + '@grpc/grpc-js@1.14.6': + resolution: {integrity: sha512-SgC/B3/VZ8lTyOZ4Cwk6f1skWhmkNAaVfiX90qd5u1rRXGKk1//8FTUEN9GvOUq7rfWIqAYkA3CoyumYVpOS6g==} engines: {node: '>=12.10.0'} '@grpc/grpc-js@1.9.16': @@ -2971,14 +2958,14 @@ packages: resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} engines: {node: '>=8.0.0'} - '@opentelemetry/context-async-hooks@2.11.0': - resolution: {integrity: sha512-Tr79DyWI8itsBdg+jH+opjfrwLzX+erk1/ExkIwhWoAVjVrJIn2y5+cGjTC0Vy8fyNIA/y8wuJPZwr1T3xCZeQ==} + '@opentelemetry/context-async-hooks@2.12.0': + resolution: {integrity: sha512-iK/1nD7mmZVkuYjVjkdFBiCvzntJdFny1S3CYbUYyOq7V5enL6XX+gJ7eh965L1LnS11VA8mQ7Ej/ck04SB0MQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/core@2.11.0': - resolution: {integrity: sha512-7YP44XH0tV6+Mb54x2YGf84i7yi+31MBZlE8JwvozkxyTvXbSp10X7cI7YE49ChJ3shMJoBmCJF3+1QFBJctGA==} + '@opentelemetry/core@2.12.0': + resolution: {integrity: sha512-1HsSAuvT4/my0QrXWsyXFdWjKaPeCHsismKZgEEIb8NK13LP6DrMRlsUbvD/0F9mDWK3xDom9AMv3IscxgOnOQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -3109,9 +3096,6 @@ packages: cpu: [x64] os: [win32] - '@oxc-project/types@0.151.0': - resolution: {integrity: sha512-J1yXrIlNDZVzE3ada310xeAw7nH8yCAyLPuUIsjKatFPmfn5bS1oW+cM+QsGOtVWd5nhSpbwZWx/rue+r5Z+PA==} - '@oxc-project/types@0.152.0': resolution: {integrity: sha512-oM/5rLBm2tPkg0iBgkH/FOeR3PCDpY19GTgAZjMFM8h9WI9VW7cLgzp6nwtarYKmovavIQZ+Fe/RKX/8C8O/Rw==} @@ -3294,85 +3278,42 @@ packages: yauzl: optional: true - '@rolldown/binding-android-arm-eabi@1.2.11': - resolution: {integrity: sha512-A5kXfGKvKWWZE0TtPrfsvT+q4Y5d1QG8gGUzpYjGydM+fARM9MuX90PrXYXe0XbsDVgyxxNzHo6giCj90bsFNw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [android] - '@rolldown/binding-android-arm-eabi@1.2.12': resolution: {integrity: sha512-dB/a1214qKfHMXCpgqR4OZT+jS4kTyEXbQGJPqzobt5EwH5rX080pxE37alt3RzvR1bf1Yz/yGqRfrYAxuPw0A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@rolldown/binding-android-arm64@1.2.11': - resolution: {integrity: sha512-z6cTycz+iJ4PVkuL4HHW4DfTfoeU/2nqYYuSOrTmH7yHK5Y0LCOnA03V4ZNxavyVaU1oOqUgIg2klN/s+USGOA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - '@rolldown/binding-android-arm64@1.2.12': resolution: {integrity: sha512-7KHFgQ5VJxIHcLlrwrc3Xbds7oTNQT7Pgi9gQCJKrd2VGab/UksIOYp6VD8MzCstGxOKMgNamPwUCfxPdP1OHg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.2.11': - resolution: {integrity: sha512-jShvqNtP6vDC6/A5JOAzbVV+DkgHqhl/ScVCJEbt+TUY6QYz7YnXcrg3sLtFBniro0f/Ld50ZwCWA6f7KYD1nQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - '@rolldown/binding-darwin-arm64@1.2.12': resolution: {integrity: sha512-3YIhqHD96nA5SaYNRBR16HnGv4oavZvXfD/ayHM+oYZ0WD/8lBAtf6zQua4kEyAvpqrluKXl0lnOBoiNby7x9w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.2.11': - resolution: {integrity: sha512-f2i2xiNWq1Z1l2++q2fuhZRdLAT3aqxD6vRNm1RAxpUoBcdqNB3C0s1Bt+K+PbEx2F5F4gQp6hqKkphCY/xF9w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - '@rolldown/binding-darwin-x64@1.2.12': resolution: {integrity: sha512-UuuJ35MFw4gmFOrE9pEqIV+K3syIKveph+Qc1/ljHZVdoDW4pz/JHR/eMVom+TZGl/5OOvGJOWaOCVt3ZfqhxA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.2.11': - resolution: {integrity: sha512-4Ir5FSOKIAMr4r0kExpt1s3bMgzJU3rA45AYOHtQpls0oNeqcYBKrWMlckrYH4KCfGLfkfn1tN1dmZPMVsdXow==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - '@rolldown/binding-freebsd-x64@1.2.12': resolution: {integrity: sha512-uMvssit0a4W+/7D8CbHUvG719mH3R2jwXAlh/XcPvuHTE0g++LymF88DCGNX0HM2rBOn0xrzgXktIB6fLSJBTQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.2.11': - resolution: {integrity: sha512-/gnRDM+39BROzAN/k1OZjDPnDMcZxB/0EUxKjONO5yVkNEvlsoMDrxGNKgZi/ttFriS2gwlDNzB65pvNbFOXIQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - '@rolldown/binding-linux-arm-gnueabihf@1.2.12': resolution: {integrity: sha512-XcFu0R0xWnwzSf4IQgFH1rJIckPN1pLy2R+4r9IDB7Yfu/ys9cVqfa4pBrMHj7a3gl8mIR4nRNPg0e5IvEVs6g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.2.11': - resolution: {integrity: sha512-PFaK8HwvAHbaKbBcDNQihjMKYvFnA5hiENx/l5tphTDz1E0WFp32l0A7aq7lyUwGsRw/xSrNIy/gIK4thrSCrw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - '@rolldown/binding-linux-arm64-gnu@1.2.12': resolution: {integrity: sha512-260UrKgn8tz39ak+SMDOirKzr7V04M9dWPw5llW00SwBivCZoWcRBKV1d8cXnRkUmSZA3BdiUmBHWk7734Ulpw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3380,13 +3321,6 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.2.11': - resolution: {integrity: sha512-AskzJUIKRLPxkruR1wLKewGbOw+EYfU/9lOrBFj4AFrEA8hPpKFnODWNu2WLaNs0QNkEb9QIJufmVZZIL/bJlg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - '@rolldown/binding-linux-arm64-musl@1.2.12': resolution: {integrity: sha512-5YK1I9SqDkbPgc1IA8BgDl34suqUS2q0KWnBrirm0E51YjOs6eo6dV6jbQfNE/argHRSvd0QUGgtpIoYx+WWpw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3394,13 +3328,6 @@ packages: os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.2.11': - resolution: {integrity: sha512-qlUGAheh2yh8afH7QBgx0PrRHN85hKnNd78x8MeMhXivuevgd8vgf6/CstOzmNKY/lLTHvNTrPy98cLnAugzJw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - '@rolldown/binding-linux-ppc64-gnu@1.2.12': resolution: {integrity: sha512-Rkcrmp7eFRg74yL5fXEU91JEWbdEPLevWwGtXpmhbjlD1StScbWTmO94Bhly+Mo+ketKYkdmM1vNUKeWSlx8cQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3408,13 +3335,6 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.2.11': - resolution: {integrity: sha512-secpEad+0vCbSfn8upFySkDskv+bGPk3THSDS9Y89yc4rb4kzqHp8Dmyd9BkQW4SnhNXBZCl/6CrO//hZahNJQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.2.12': resolution: {integrity: sha512-qvK4DuAsQc2BSjlx+Xr+IzOIvvxbGZqxFwdWfG6F518Erj0GGISyQbJ6pIappnOxlNPzNHvo/L0BwB30GZ+zVw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3422,13 +3342,6 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.2.11': - resolution: {integrity: sha512-mOVBT3dPpkWm8XBWPmU4bf+U6dYDLeMo/9ojUmis4N0L5uu10qra5vOyngZ7/PSdoE4G9KvRt4bloRxNjLas7A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.2.12': resolution: {integrity: sha512-Q9uLBO53Xd4QIq1WOycVQyPP1O4HhraEV2qqb3uTrnVw6QZih9duY4vNXOivL1xoUS1/z+W8eF4NMfl2a8Sdjw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3436,13 +3349,6 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.2.11': - resolution: {integrity: sha512-Is78i9A8Ui4SqcxUwFJ9uMmjDn58IbVTjFWYdQestFEgeuEmHMLGNriXnVJKkwG2YiZjw8cP0zCTyDMdDGtOOg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - '@rolldown/binding-linux-x64-musl@1.2.12': resolution: {integrity: sha512-3IBxWFMjbOZskDPKv8Lf9BCnahlKuHthWkYnyIxOH/QcJrFcS4EmcenthApkwr/5+nEqZlLzeYbxeMaX7A5u4g==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3450,36 +3356,18 @@ packages: os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.2.11': - resolution: {integrity: sha512-dUCXneZ87INUMyQ0D+C0HrEBNUPNXHaPmU5GTjyKTJEiussw9Kaj5Ln8UztPe4epV/ffvgNBEadksdYhmW6xJA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - '@rolldown/binding-openharmony-arm64@1.2.12': resolution: {integrity: sha512-xtX61xg4LKPkPWilZU1ynKClz5Gj4bf74LML4r3eVLWumKnGjoEr1OSHQhMdbBDoYTi+yjrujvpZe2pUnqCrrA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-win32-arm64-msvc@1.2.11': - resolution: {integrity: sha512-jByxb6qfd+bH1xUd0qnfFnb17i9sWBPY2tOavJ0l3tdr3OTu+Kvtm8cd/JV5nFt657b1VqGltxg9olOEfofXWw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - '@rolldown/binding-win32-arm64-msvc@1.2.12': resolution: {integrity: sha512-At7fPB6PCaIjzgIhEZFxuT+BBFqiQibJDT4d3PhiR3f4E7bbMZF4aKblbFfEM3sETRDd1YiQx/+U/g/B/ou5Ew==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.2.11': - resolution: {integrity: sha512-/PzKqzAJ03i19oy2ItPvyvaVjOjBCNnfaJs8yvUdGBKmiESgnrJSQ2awd81QzFbbnAmu7YO9ZnJrDCb9VSJPRA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - '@rolldown/binding-win32-x64-msvc@1.2.12': resolution: {integrity: sha512-WIw2haVKwjuYdXkHaoC0mF8Le71TuCBxjrdKqLbJGctbBABj+ClfmNvtbOnzpq3RokNo5+V1qhtSzJyXorsklQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3808,8 +3696,8 @@ packages: '@types/loader-utils@3.0.0': resolution: {integrity: sha512-oOi4OGpiLUbb+Q/cN9FIkkDFgOpOGZ2cUAzb5i03wrGstnG6Syx1WDMhSiB5rcP10XX7cw7Uev8mv++/aplnNg==} - '@types/lodash@4.17.25': - resolution: {integrity: sha512-+K1NIO8I+F9/wNulfVvu23QYd0Pe9/OCqRrim4NoYIf1VoEDL90Ve4ClzpyqBLc7NpGGWRvYNCKZ1BE/Jpf8dQ==} + '@types/lodash@4.17.26': + resolution: {integrity: sha512-48NWfiY6oNcKOh47Z4h+sIvwcQR91h6KPhaYKgeMIrkT2jV82Gy90SErj60vW8jQbeMSOSbhIv3bZ7JoqPPVhA==} '@types/micromatch@2.3.35': resolution: {integrity: sha512-J749bHo/Zu56w0G0NI/IGHLQPiSsjx//0zJhfEVAN95K/xM5C8ZDmhkXtU3qns0sBOao7HuQzr8XV1/2o5LbXA==} @@ -3927,10 +3815,6 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.71.0': - resolution: {integrity: sha512-cJ4OoxPGWvFnBTnSZyaU+qJzGTqPTGJY+gDchj6cRyLRdmIdt4rcsE4twj+zPfrNiWuVi38wijHzShL++Z9atQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.71.1': resolution: {integrity: sha512-ybYnPTUwg3VQQOFEiBPLs8Jxl1ry2vXdn1kVKguomBbvxpetdu3MKTNDqFNUrlG8ylP9MpZosmXMFYlGQHk1oQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3964,6 +3848,10 @@ packages: resolution: {integrity: sha512-KRYepjgpSgrYYNHjmg77F9Mp7FMzQ0f9dcNc2AP3fmCmQMx0IWH6TYe4okvqkASoYhLnil5NRWqjO4Z4qSOHVg==} engines: {node: '>=22'} + '@verdaccio/core@8.3.3': + resolution: {integrity: sha512-Vhfpo9MIwUOIsNQCGmTKqYn2l73261YQ6NCmRS47NbpXi5YWuSGf7I6i4dIVMZVG7UUtz9633754WtzFFAgFvg==} + engines: {node: '>=22'} + '@verdaccio/file-locking@13.1.0': resolution: {integrity: sha512-rGFfdyCZdgpbkROJJfjOA01R5BFtzrnDAhNIkxxc/yWZ6Cir+MRHpEbN2weOEPAwYDke9Wms4JKhpsStu+iV8Q==} engines: {node: '>=22'} @@ -4298,8 +4186,8 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.18.0: - resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==} + acorn@8.19.0: + resolution: {integrity: sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==} engines: {node: '>=0.4.0'} hasBin: true @@ -4522,8 +4410,8 @@ packages: bare-abort-controller: optional: true - bare-fs@4.8.2: - resolution: {integrity: sha512-+ZI68KHMUvosXfKbg/UOHK0tbCdRnegbvPEdEcZ3Nd6TetieQsJPRXBRXPdLyy8+3VSEbPXtsumTpEtt78xv9w==} + bare-fs@4.8.4: + resolution: {integrity: sha512-MPC2eyrpbk3A873sK4y6rk+Iv4o2enxTjHZ8zH3HO0mjrpm5XjnguY2XmfidIsDV6vnjpbMBKUAJpV0ISD2SsQ==} engines: {bare: '>=1.28.0'} peerDependencies: bare-buffer: '*' @@ -4554,8 +4442,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.11.27: - resolution: {integrity: sha512-ElY12DaROGuan+lMmZ8Cvo/ZUbXPe7Enc/9VU/b1T3Kp4dwytRcNdR8DoSJN5SNJT/CuvcCA0DHDVmMOCePdRQ==} + baseline-browser-mapping@2.11.28: + resolution: {integrity: sha512-br0LOmjJqr6Rt4AEkadbcNf67Zpo7EPwKsWbjnRrJIa1QYFHQBqM4C7F2WTbV8ahTEcg1Eo+Y0aWjjORInYFyA==} engines: {node: '>=6.0.0'} hasBin: true @@ -4702,8 +4590,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001814: - resolution: {integrity: sha512-/Uaf1lAzr59XcMpW0o96WoEfr+VXK2OX4U9AgFoiSHsVJ4HppnIFUjtYzsyDH2+tgANaQb2/oxYGwCPapN1FpA==} + caniuse-lite@1.0.30001815: + resolution: {integrity: sha512-uDybUEyfgbyJJ93J1vikTylBX31AkdVYeVPeffMQpf8XN7hSfr0oZOn4VFOIMNvtU5+rHvC5Udg2TgtJKHm23Q==} caseless@0.12.0: resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} @@ -5169,8 +5057,8 @@ packages: engines: {node: '>=0.12.18'} hasBin: true - electron-to-chromium@1.5.444: - resolution: {integrity: sha512-5ss/uJfoDYDHT0lfJzT6FbcskIzROIOPf0BbbFkGcvDzoJU7i//9GDrwwIHQVmIsrAGiF3ihpADBRIsrEFt1rQ==} + electron-to-chromium@1.5.452: + resolution: {integrity: sha512-cVvk1YBSj6571VmV6hdJTqj94Y79xSu8cj6Y9t6ae4Y4431z8/7EJFvu3rVp90xhfuv9BpPKUmaLfTo4+FOGBg==} emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} @@ -6366,8 +6254,8 @@ packages: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} - launch-editor@2.14.1: - resolution: {integrity: sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA==} + launch-editor@2.14.2: + resolution: {integrity: sha512-NHJEb30MGBCkmZXLZwz25t37QR4aY03ZzPYUJXOJaOa92uWwExI9SBQUuIznBYc1xkD7cJNGX7oc3Nl3sq2kQQ==} less-loader@13.0.0: resolution: {integrity: sha512-TIa8d6znKH634Mg+7OU3jevZT6KeOhh0amW+YeMPD0GM9buUn5Y7HvtyCR5pUDdLaFfqLA8AX5PTSIHMNSexEA==} @@ -6589,9 +6477,6 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - magic-string@1.4.2: - resolution: {integrity: sha512-vG+rjFRj1PqdIBozIxAGMjPlOhaVe+GXpbttY/iSK7rGcJRMlwNJO7dcUwmUqkymsFLJiNGI06t4D7Fr7yRC9g==} - magic-string@1.4.3: resolution: {integrity: sha512-z12OxmaPGE0F4xlpGdjuAUckipLpQlTAuAmyGhNoD7ODpYUzvDfvtxUbjM/jwznyP178oju/KDdyi220wNJ0RQ==} @@ -6816,8 +6701,8 @@ packages: resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} engines: {node: ^20.17.0 || >=22.9.0} - nanoid@3.3.19: - resolution: {integrity: sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==} + nanoid@3.3.20: + resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -6902,8 +6787,8 @@ packages: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true - node-releases@2.0.57: - resolution: {integrity: sha512-kQK9LGGFiHtrWiNhZtA7Qbw17AQz+dmsEKODRIVTXA9+e5MS/2gZEBhYJt13GrAz5/IOZKddH/0Z3TP/Zgo+yw==} + node-releases@2.0.58: + resolution: {integrity: sha512-BdiKAgbfRlvfMq/XzO/AF9NPmaA8a+YpLAyAFTVFBj3gARrAIfWvNq7Q7NE4se3KgFu0KkrvQMxTS0XVnsGzHg==} engines: {node: '>=18'} normalize-path@3.0.0: @@ -7222,10 +7107,6 @@ packages: postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.28: - resolution: {integrity: sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==} - engines: {node: ^10 || ^12 || >=14} - postcss@8.5.29: resolution: {integrity: sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==} engines: {node: ^10 || ^12 || >=14} @@ -7238,8 +7119,8 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.9.9: - resolution: {integrity: sha512-Z/CJHIkdujO/OtN7nXUii0Rf3VT5SRuhjBA82Xvu2XhBUgX3nhP67T0LHceBdQLex7OOFGTox+Q5Yg8Jk2Qivg==} + prettier@3.9.10: + resolution: {integrity: sha512-skGHTH1Yb9QvaTC4hWnRTzEYtCpApF0UMBPz+t/0ZPzP8ihefo/btKd+QA7pUE0fEwA1SbS/NmhyEcstdXOIdA==} engines: {node: '>=14'} hasBin: true @@ -7256,8 +7137,8 @@ packages: process-warning@1.0.0: resolution: {integrity: sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==} - process-warning@5.1.0: - resolution: {integrity: sha512-jQSaVHsPgtyw60e1rQ/A+/ArPEj/S8pS/vFnyGa/gYFXrKk/6RuDkoqVDQ5NI5MmS01698ltlAk0NoDBNLujRw==} + process-warning@5.1.1: + resolution: {integrity: sha512-oCkNVj4OKnKEcocVBcDfiIugN1/cE6rgfT3nCtzeqZPA8+rIxMaQ0xXzIkGP8Gj2qUaP1UR7uhJ1VD8lUCpzCg==} process@0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} @@ -7373,8 +7254,8 @@ packages: resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - readable-stream@4.7.0: - resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} + readable-stream@4.8.0: + resolution: {integrity: sha512-2jhTTU3Eilp/2DMT71gbcoqC35eQHasMJH0RHkYxwlxIv3+FR6Y5xAFZIwEGLxKkjZYEFlsiMNIdwUqjK2lLHQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} readdirp@3.6.0: @@ -7410,15 +7291,15 @@ packages: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} - regexpu-core@6.5.2: - resolution: {integrity: sha512-zkmVH92DlzjSFc4xKGZp/2BXIFrDIdBQBC8gUXKCsMgKYb1bkCkxfSuoW1werDjaTEMTbULkHtKFHe1L+Abnaw==} + regexpu-core@6.5.3: + resolution: {integrity: sha512-E8VgUoSK+LMQrLboDxavm76MTBGrQhx9RiNuomRmYnZ10Uw12HrI8fkxOOncktb2hBpzIZ9SV/347euQHG5z+g==} engines: {node: '>=4'} regjsgen@0.8.0: resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} - regjsparser@0.13.3: - resolution: {integrity: sha512-ycwFAS14Jw4mppvmK4GR/J6u3WpWpjkEApehuHtLc/8VpPNpDMbQ4WjqwplXifGeyKOzHSFLmSPqzksDQE2Sfg==} + regjsparser@0.13.4: + resolution: {integrity: sha512-EWV80YgFaVgFrjGCAsV7oybp4GOxbls5RzBg8OB0nKEVXsBJR1JlV8Di1JhCROg3MzTfe1RI8yitIm1eOs68iA==} hasBin: true require-directory@2.1.1: @@ -7446,8 +7327,8 @@ packages: resolution: {integrity: sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==} engines: {node: '>=12'} - resolve@1.22.12: - resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} + resolve@1.22.13: + resolution: {integrity: sha512-Dj/cW9zBV2aRj6XzCxuGIs3ESZKv02jixne3q6jFZYZ3/Tg09gHHviSMDL4kObh9pqSahdRHEnDoaP2gn8YLhA==} engines: {node: '>= 0.4'} hasBin: true @@ -7517,11 +7398,6 @@ packages: vue-tsc: optional: true - rolldown@1.2.11: - resolution: {integrity: sha512-qpSwIyz0jHQq5qXBTNxFmE6664rJ7O+4TvPFOiOaBSrz8IOHc1koKKSqTM2H6u1UG1+TveuC6vaDHKXFOvb1Kw==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - rolldown@1.2.12: resolution: {integrity: sha512-8wafseiaG80xmXSfqidUNqZcylTlhmPZZt+za2m+js2sFZ8dTNlhIOV2WcbIPx2hgwPBJpEUGFAMZ9bgBBLTSQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -8089,8 +7965,8 @@ packages: tiny-inflate@1.0.3: resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} - tinybench@6.2.0: - resolution: {integrity: sha512-78U2TlB2CnVenajOFzf3BKSm0J6oz5L0NV7g32LCPccvYc0lbWvys4d3uUUCS2B1N8PAf2+aekR8i1KbC3HO7Q==} + tinybench@6.2.2: + resolution: {integrity: sha512-nIZ2N2dFpjBsg2hgitKu7mA+FvsIJuGJOwysRngmVRRmWgR/UyPjwJj8c/fT/dhm8EkHnF5EOogRf+0Z2qrimA==} engines: {node: '>=20.0.0'} tinyexec@1.3.1: @@ -8108,15 +7984,15 @@ packages: tldts-core@6.1.86: resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} - tldts-core@7.4.16: - resolution: {integrity: sha512-MDolfaSJtlSK5Y0A1xl3277ekubZwobpBjugknDizI9O5Rm60a1m8k4ICK+MRsCDzPygT81mp3BBf5RKDlFRfA==} + tldts-core@7.4.18: + resolution: {integrity: sha512-KI2PKvCmvQI/xD6ypPqkU0i7oxNXR/O58RLRaHR4svsgVUQ2JE/XC8BtMbG6PSehD27I8sZJRcC1ASnCy6lp3g==} tldts@6.1.86: resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} hasBin: true - tldts@7.4.16: - resolution: {integrity: sha512-QwBER5KMR86IIjpIiO7H/Z3IMJPsZ1A6RKPAqzTTgOyUQUSt9FdnKcqhTaJmkY6HVrgouZHZR0ncK5QxvmnQeg==} + tldts@7.4.18: + resolution: {integrity: sha512-somxA8xKAUzlAxl0TX/jMSYIbRNFIVGnI96pVGJPeMc5BsHmfVXn6mOJT6U++ELnl04eGfzpfcEuZe8WiASkXg==} hasBin: true tmp@0.2.7: @@ -8316,8 +8192,8 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - update-browserslist-db@1.3.3: - resolution: {integrity: sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==} + update-browserslist-db@1.3.4: + resolution: {integrity: sha512-t8wonIOdQyOjtPd2VktlBu6QjTVTks6v8bSi7kd0r2Vll8TK1JYDZtRRdbmCHOAMphkZgrzK+L+vXK4pyZ8t4A==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -8361,8 +8237,8 @@ packages: resolution: {integrity: sha512-Q5dkR66lSUpzoR2xKWFiFCYXlvC8hJqV+ZMMLgt9/vm9355VnH25ueIJzrpunO/QjhhgcT5yBlR6wGQjPHeHkA==} engines: {node: '>=22'} - verdaccio-auth-memory@13.1.5: - resolution: {integrity: sha512-rfKDhm1DzZoFdHUjiSwpe8hlXkiKB4brtzagaZcBnZXyBEASwW6SK/mdr4yU4asMcf+Zc8MjUJYnjlI7ji1yaw==} + verdaccio-auth-memory@13.1.6: + resolution: {integrity: sha512-L9LNz1q/JW1I9mPLch+8LUGnma/amo4EpS/+hZA6ZJJRIN7G5QAOKU9hLLPV6WqxO/I8T0KPtwNhyav9Aopqtg==} engines: {node: '>=22'} verdaccio-htpasswd@13.1.5: @@ -8933,7 +8809,7 @@ snapshots: rxjs: 7.8.2 tslib: 2.8.1 - '@asamuzakjp/css-color@7.1.3': + '@asamuzakjp/css-color@7.1.5': dependencies: '@csstools/css-calc': 3.4.3(@csstools/css-parser-algorithms@4.0.2(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2) '@csstools/css-color-parser': 4.2.6(@csstools/css-parser-algorithms@4.0.2(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2) @@ -8969,10 +8845,10 @@ snapshots: '@babel/generator': 7.29.8 '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@11.0.0))(supports-color@11.0.0) - '@babel/helpers': 7.29.7 + '@babel/helpers': 7.29.10 '@babel/parser': 7.29.9 '@babel/template': 7.29.7 - '@babel/traverse': 7.29.8(supports-color@11.0.0) + '@babel/traverse': 7.29.10(supports-color@11.0.0) '@babel/types': 7.29.8 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 @@ -9031,7 +8907,7 @@ snapshots: '@babel/generator@8.0.6': dependencies: - '@babel/parser': 8.0.6 + '@babel/parser': 8.0.7 '@babel/types': 8.0.6 '@jridgewell/gen-mapping': 0.4.0-beta.0 '@jridgewell/trace-mapping': 0.3.31 @@ -9050,14 +8926,6 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-compilation-targets@8.0.6': - dependencies: - '@babel/compat-data': 8.0.5 - '@babel/helper-validator-option': 8.0.0 - browserslist: 4.29.3 - flru: 1.0.2 - verkit: 0.3.2 - '@babel/helper-compilation-targets@8.0.7': dependencies: '@babel/compat-data': 8.0.5 @@ -9066,7 +8934,7 @@ snapshots: flru: 1.0.2 verkit: 0.5.0 - '@babel/helper-create-class-features-plugin@8.0.6(@babel/core@8.0.7)': + '@babel/helper-create-class-features-plugin@8.0.7(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 '@babel/helper-annotate-as-pure': 8.0.0 @@ -9074,20 +8942,20 @@ snapshots: '@babel/helper-optimise-call-expression': 8.0.0 '@babel/helper-replace-supers': 8.0.1(@babel/core@8.0.7) '@babel/helper-skip-transparent-expression-wrappers': 8.0.0 - '@babel/traverse': 8.0.6 - verkit: 0.3.2 + '@babel/traverse': 8.0.7 + verkit: 0.5.0 - '@babel/helper-create-regexp-features-plugin@8.0.5(@babel/core@8.0.7)': + '@babel/helper-create-regexp-features-plugin@8.0.7(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 '@babel/helper-annotate-as-pure': 8.0.0 - regexpu-core: 6.5.2 - verkit: 0.3.2 + regexpu-core: 6.5.3 + verkit: 0.5.0 '@babel/helper-define-polyfill-provider@1.0.0(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 - '@babel/helper-compilation-targets': 8.0.6 + '@babel/helper-compilation-targets': 8.0.7 '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.7) lodash.debounce: 4.0.8 @@ -9097,19 +8965,19 @@ snapshots: '@babel/helper-member-expression-to-functions@8.0.5': dependencies: - '@babel/traverse': 8.0.6 + '@babel/traverse': 8.0.7 '@babel/types': 8.0.6 '@babel/helper-module-imports@7.29.7(supports-color@11.0.0)': dependencies: - '@babel/traverse': 7.29.8(supports-color@11.0.0) + '@babel/traverse': 7.29.10(supports-color@11.0.0) '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color '@babel/helper-module-imports@8.0.0': dependencies: - '@babel/traverse': 8.0.6 + '@babel/traverse': 8.0.7 '@babel/types': 8.0.6 '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@11.0.0))(supports-color@11.0.0)': @@ -9117,7 +8985,7 @@ snapshots: '@babel/core': 7.29.7(supports-color@11.0.0) '@babel/helper-module-imports': 7.29.7(supports-color@11.0.0) '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.8(supports-color@11.0.0) + '@babel/traverse': 7.29.10(supports-color@11.0.0) transitivePeerDependencies: - supports-color @@ -9126,7 +8994,7 @@ snapshots: '@babel/core': 8.0.7 '@babel/helper-module-imports': 8.0.0 '@babel/helper-validator-identifier': 8.0.6 - '@babel/traverse': 8.0.6 + '@babel/traverse': 8.0.7 '@babel/helper-optimise-call-expression@8.0.0': dependencies: @@ -9141,18 +9009,18 @@ snapshots: '@babel/core': 8.0.7 '@babel/helper-annotate-as-pure': 8.0.0 '@babel/helper-wrap-function': 8.0.0 - '@babel/traverse': 8.0.6 + '@babel/traverse': 8.0.7 '@babel/helper-replace-supers@8.0.1(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 '@babel/helper-member-expression-to-functions': 8.0.5 '@babel/helper-optimise-call-expression': 8.0.0 - '@babel/traverse': 8.0.6 + '@babel/traverse': 8.0.7 '@babel/helper-skip-transparent-expression-wrappers@8.0.0': dependencies: - '@babel/traverse': 8.0.6 + '@babel/traverse': 8.0.7 '@babel/types': 8.0.6 '@babel/helper-split-export-declaration@7.24.7': @@ -9174,10 +9042,10 @@ snapshots: '@babel/helper-wrap-function@8.0.0': dependencies: '@babel/template': 8.0.0 - '@babel/traverse': 8.0.6 + '@babel/traverse': 8.0.7 '@babel/types': 8.0.6 - '@babel/helpers@7.29.7': + '@babel/helpers@7.29.10': dependencies: '@babel/template': 7.29.7 '@babel/types': 7.29.8 @@ -9191,10 +9059,6 @@ snapshots: dependencies: '@babel/types': 7.29.8 - '@babel/parser@8.0.6': - dependencies: - '@babel/types': 8.0.6 - '@babel/parser@8.0.7': dependencies: '@babel/types': 8.0.6 @@ -9242,7 +9106,7 @@ snapshots: '@babel/core': 8.0.7 '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.7) '@babel/helper-remap-async-to-generator': 8.0.1(@babel/core@8.0.7) - '@babel/traverse': 8.0.6 + '@babel/traverse': 8.0.7 '@babel/plugin-transform-async-to-generator@8.0.1(@babel/core@8.0.7)': dependencies: @@ -9264,24 +9128,24 @@ snapshots: '@babel/plugin-transform-class-properties@8.0.1(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 - '@babel/helper-create-class-features-plugin': 8.0.6(@babel/core@8.0.7) + '@babel/helper-create-class-features-plugin': 8.0.7(@babel/core@8.0.7) '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.7) '@babel/plugin-transform-class-static-block@8.0.5(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 - '@babel/helper-create-class-features-plugin': 8.0.6(@babel/core@8.0.7) + '@babel/helper-create-class-features-plugin': 8.0.7(@babel/core@8.0.7) '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.7) '@babel/plugin-transform-classes@8.0.5(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 '@babel/helper-annotate-as-pure': 8.0.0 - '@babel/helper-compilation-targets': 8.0.6 + '@babel/helper-compilation-targets': 8.0.7 '@babel/helper-globals': 8.0.6 '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.7) '@babel/helper-replace-supers': 8.0.1(@babel/core@8.0.7) - '@babel/traverse': 8.0.6 + '@babel/traverse': 8.0.7 '@babel/plugin-transform-computed-properties@8.0.1(@babel/core@8.0.7)': dependencies: @@ -9296,7 +9160,7 @@ snapshots: '@babel/plugin-transform-dotall-regex@8.0.1(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 - '@babel/helper-create-regexp-features-plugin': 8.0.5(@babel/core@8.0.7) + '@babel/helper-create-regexp-features-plugin': 8.0.7(@babel/core@8.0.7) '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.7) '@babel/plugin-transform-duplicate-keys@8.0.1(@babel/core@8.0.7)': @@ -9307,7 +9171,7 @@ snapshots: '@babel/plugin-transform-duplicate-named-capturing-groups-regex@8.0.1(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 - '@babel/helper-create-regexp-features-plugin': 8.0.5(@babel/core@8.0.7) + '@babel/helper-create-regexp-features-plugin': 8.0.7(@babel/core@8.0.7) '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.7) '@babel/plugin-transform-dynamic-import@8.0.1(@babel/core@8.0.7)': @@ -9340,7 +9204,7 @@ snapshots: '@babel/plugin-transform-function-name@8.0.1(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 - '@babel/helper-compilation-targets': 8.0.6 + '@babel/helper-compilation-targets': 8.0.7 '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.7) '@babel/plugin-transform-json-strings@8.0.1(@babel/core@8.0.7)': @@ -9391,7 +9255,7 @@ snapshots: '@babel/plugin-transform-named-capturing-groups-regex@8.0.1(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 - '@babel/helper-create-regexp-features-plugin': 8.0.5(@babel/core@8.0.7) + '@babel/helper-create-regexp-features-plugin': 8.0.7(@babel/core@8.0.7) '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.7) '@babel/plugin-transform-new-target@8.0.1(@babel/core@8.0.7)': @@ -9412,7 +9276,7 @@ snapshots: '@babel/plugin-transform-object-rest-spread@8.0.1(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 - '@babel/helper-compilation-targets': 8.0.6 + '@babel/helper-compilation-targets': 8.0.7 '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.7) '@babel/plugin-transform-destructuring': 8.0.5(@babel/core@8.0.7) '@babel/plugin-transform-parameters': 8.0.5(@babel/core@8.0.7) @@ -9442,14 +9306,14 @@ snapshots: '@babel/plugin-transform-private-methods@8.0.1(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 - '@babel/helper-create-class-features-plugin': 8.0.6(@babel/core@8.0.7) + '@babel/helper-create-class-features-plugin': 8.0.7(@babel/core@8.0.7) '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.7) '@babel/plugin-transform-private-property-in-object@8.0.5(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 '@babel/helper-annotate-as-pure': 8.0.0 - '@babel/helper-create-class-features-plugin': 8.0.6(@babel/core@8.0.7) + '@babel/helper-create-class-features-plugin': 8.0.7(@babel/core@8.0.7) '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.7) '@babel/plugin-transform-property-literals@8.0.1(@babel/core@8.0.7)': @@ -9465,7 +9329,7 @@ snapshots: '@babel/plugin-transform-regexp-modifiers@8.0.1(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 - '@babel/helper-create-regexp-features-plugin': 8.0.5(@babel/core@8.0.7) + '@babel/helper-create-regexp-features-plugin': 8.0.7(@babel/core@8.0.7) '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.7) '@babel/plugin-transform-reserved-words@8.0.1(@babel/core@8.0.7)': @@ -9513,19 +9377,19 @@ snapshots: '@babel/plugin-transform-unicode-property-regex@8.0.1(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 - '@babel/helper-create-regexp-features-plugin': 8.0.5(@babel/core@8.0.7) + '@babel/helper-create-regexp-features-plugin': 8.0.7(@babel/core@8.0.7) '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.7) '@babel/plugin-transform-unicode-regex@8.0.1(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 - '@babel/helper-create-regexp-features-plugin': 8.0.5(@babel/core@8.0.7) + '@babel/helper-create-regexp-features-plugin': 8.0.7(@babel/core@8.0.7) '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.7) '@babel/plugin-transform-unicode-sets-regex@8.0.1(@babel/core@8.0.7)': dependencies: '@babel/core': 8.0.7 - '@babel/helper-create-regexp-features-plugin': 8.0.5(@babel/core@8.0.7) + '@babel/helper-create-regexp-features-plugin': 8.0.7(@babel/core@8.0.7) '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.7) '@babel/preset-env@8.0.7(@babel/core@8.0.7)': @@ -9617,10 +9481,10 @@ snapshots: '@babel/template@8.0.0': dependencies: '@babel/code-frame': 8.0.6 - '@babel/parser': 8.0.6 + '@babel/parser': 8.0.7 '@babel/types': 8.0.6 - '@babel/traverse@7.29.8(supports-color@11.0.0)': + '@babel/traverse@7.29.10(supports-color@11.0.0)': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.8 @@ -9632,16 +9496,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/traverse@8.0.6': - dependencies: - '@babel/code-frame': 8.0.6 - '@babel/generator': 8.0.6 - '@babel/helper-globals': 8.0.6 - '@babel/parser': 8.0.6 - '@babel/template': 8.0.0 - '@babel/types': 8.0.6 - obug: 2.2.1 - '@babel/traverse@8.0.7': dependencies: '@babel/code-frame': 8.0.6 @@ -9670,7 +9524,7 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} - '@bramus/specificity@2.4.2': + '@bramus/specificity@2.4.3': dependencies: css-tree: 3.2.1 @@ -10233,8 +10087,8 @@ snapshots: '@google-cloud/promisify': 5.1.0 '@grpc/proto-loader': 0.7.15 '@opentelemetry/api': 1.9.1 - '@opentelemetry/context-async-hooks': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/context-async-hooks': 2.12.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.12.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.43.0 '@types/big.js': 6.2.2 '@types/stack-trace': 0.0.33 @@ -10271,7 +10125,7 @@ snapshots: - supports-color - utf-8-validate - '@grpc/grpc-js@1.14.5': + '@grpc/grpc-js@1.14.6': dependencies: '@grpc/proto-loader': 0.8.1 '@js-sdsl/ordered-map': 4.4.2 @@ -11018,11 +10872,11 @@ snapshots: '@opentelemetry/api@1.9.1': {} - '@opentelemetry/context-async-hooks@2.11.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/context-async-hooks@2.12.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core@2.11.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/core@2.12.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/semantic-conventions': 1.43.0 @@ -11086,8 +10940,6 @@ snapshots: '@oxc-parser/binding-win32-x64-msvc@0.153.0': optional: true - '@oxc-project/types@0.151.0': {} - '@oxc-project/types@0.152.0': {} '@oxc-project/types@0.153.0': {} @@ -11272,93 +11124,48 @@ snapshots: modern-tar: 0.8.5 yargs: 18.2.0 - '@rolldown/binding-android-arm-eabi@1.2.11': - optional: true - '@rolldown/binding-android-arm-eabi@1.2.12': optional: true - '@rolldown/binding-android-arm64@1.2.11': - optional: true - '@rolldown/binding-android-arm64@1.2.12': optional: true - '@rolldown/binding-darwin-arm64@1.2.11': - optional: true - '@rolldown/binding-darwin-arm64@1.2.12': optional: true - '@rolldown/binding-darwin-x64@1.2.11': - optional: true - '@rolldown/binding-darwin-x64@1.2.12': optional: true - '@rolldown/binding-freebsd-x64@1.2.11': - optional: true - '@rolldown/binding-freebsd-x64@1.2.12': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.2.11': - optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.2.12': optional: true - '@rolldown/binding-linux-arm64-gnu@1.2.11': - optional: true - '@rolldown/binding-linux-arm64-gnu@1.2.12': optional: true - '@rolldown/binding-linux-arm64-musl@1.2.11': - optional: true - '@rolldown/binding-linux-arm64-musl@1.2.12': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.2.11': - optional: true - '@rolldown/binding-linux-ppc64-gnu@1.2.12': optional: true - '@rolldown/binding-linux-s390x-gnu@1.2.11': - optional: true - '@rolldown/binding-linux-s390x-gnu@1.2.12': optional: true - '@rolldown/binding-linux-x64-gnu@1.2.11': - optional: true - '@rolldown/binding-linux-x64-gnu@1.2.12': optional: true - '@rolldown/binding-linux-x64-musl@1.2.11': - optional: true - '@rolldown/binding-linux-x64-musl@1.2.12': optional: true - '@rolldown/binding-openharmony-arm64@1.2.11': - optional: true - '@rolldown/binding-openharmony-arm64@1.2.12': optional: true - '@rolldown/binding-win32-arm64-msvc@1.2.11': - optional: true - '@rolldown/binding-win32-arm64-msvc@1.2.12': optional: true - '@rolldown/binding-win32-x64-msvc@1.2.11': - optional: true - '@rolldown/binding-win32-x64-msvc@1.2.12': optional: true @@ -11388,7 +11195,7 @@ snapshots: '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 - resolve: 1.22.12 + resolve: 1.22.13 optionalDependencies: rollup: 4.64.1 @@ -11501,7 +11308,7 @@ snapshots: '@stylistic/eslint-plugin@5.10.0(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))': dependencies: '@eslint-community/eslint-utils': 4.10.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0)) - '@typescript-eslint/types': 8.71.0 + '@typescript-eslint/types': 8.71.1 eslint: 10.12.0(jiti@2.7.0)(supports-color@11.0.0) eslint-visitor-keys: 4.2.1 espree: 10.4.0 @@ -11660,7 +11467,7 @@ snapshots: - uglify-js - webpack-cli - '@types/lodash@4.17.25': {} + '@types/lodash@4.17.26': {} '@types/micromatch@2.3.35': dependencies: @@ -11799,8 +11606,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.71.0': {} - '@typescript-eslint/types@8.71.1': {} '@typescript-eslint/typescript-estree@8.71.1(supports-color@11.0.0)(typescript@6.0.3)': @@ -11865,6 +11670,16 @@ snapshots: process-warning: 1.0.0 semver: 7.8.5 + '@verdaccio/core@8.3.3': + dependencies: + ajv: 8.20.0 + http-errors: 2.0.1 + http-status-codes: 2.3.0 + lodash: 4.18.1 + minimatch: 10.2.6 + process-warning: 1.0.0 + semver: 7.8.5 + '@verdaccio/file-locking@13.1.0': dependencies: lockfile: 1.0.4 @@ -12019,7 +11834,7 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 '@vitest/spy': 5.0.3 estree-walker: 3.0.3 - magic-string: 1.4.2 + magic-string: 1.4.3 optionalDependencies: vite: 8.3.3(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1) @@ -12202,11 +12017,11 @@ snapshots: mime-types: 3.0.2 negotiator: 1.1.0 - acorn-jsx@5.3.2(acorn@8.18.0): + acorn-jsx@5.3.2(acorn@8.19.0): dependencies: - acorn: 8.18.0 + acorn: 8.19.0 - acorn@8.18.0: {} + acorn@8.19.0: {} adjust-sourcemap-loader@4.0.0: dependencies: @@ -12372,7 +12187,7 @@ snapshots: autoprefixer@10.6.1(postcss@8.5.29): dependencies: browserslist: 4.29.3 - caniuse-lite: 1.0.30001814 + caniuse-lite: 1.0.30001815 fraction.js: 5.3.4 picocolors: 1.1.1 postcss: 8.5.29 @@ -12407,7 +12222,7 @@ snapshots: bare-events@2.9.2: {} - bare-fs@4.8.2: + bare-fs@4.8.4: dependencies: bare-events: 2.9.2 bare-path: 3.1.2 @@ -12436,7 +12251,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.11.27: {} + baseline-browser-mapping@2.11.28: {} batch@0.6.1: {} @@ -12591,11 +12406,11 @@ snapshots: browserslist@4.29.3: dependencies: - baseline-browser-mapping: 2.11.27 - caniuse-lite: 1.0.30001814 - electron-to-chromium: 1.5.444 - node-releases: 2.0.57 - update-browserslist-db: 1.3.3(browserslist@4.29.3) + baseline-browser-mapping: 2.11.28 + caniuse-lite: 1.0.30001815 + electron-to-chromium: 1.5.452 + node-releases: 2.0.58 + update-browserslist-db: 1.3.4(browserslist@4.29.3) bs-recipes@1.3.4: {} @@ -12661,7 +12476,7 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001814: {} + caniuse-lite@1.0.30001815: {} caseless@0.12.0: {} @@ -13120,7 +12935,7 @@ snapshots: ejs@7.0.1: {} - electron-to-chromium@1.5.444: {} + electron-to-chromium@1.5.452: {} emoji-regex@10.6.0: {} @@ -13437,14 +13252,14 @@ snapshots: espree@10.4.0: dependencies: - acorn: 8.18.0 - acorn-jsx: 5.3.2(acorn@8.18.0) + acorn: 8.19.0 + acorn-jsx: 5.3.2(acorn@8.19.0) eslint-visitor-keys: 4.2.1 espree@11.2.0: dependencies: - acorn: 8.18.0 - acorn-jsx: 5.3.2(acorn@8.18.0) + acorn: 8.19.0 + acorn-jsx: 5.3.2(acorn@8.19.0) eslint-visitor-keys: 5.0.1 esquery@1.7.0: @@ -13949,7 +13764,7 @@ snapshots: google-gax@5.0.8(supports-color@11.0.0): dependencies: - '@grpc/grpc-js': 1.14.5 + '@grpc/grpc-js': 1.14.6 '@grpc/proto-loader': 0.8.1 duplexify: 4.1.3 google-auth-library: 10.5.0(supports-color@11.0.0) @@ -13993,7 +13808,7 @@ snapshots: grpc-gcp@1.1.1: dependencies: - '@grpc/grpc-js': 1.14.5 + '@grpc/grpc-js': 1.14.6 protobufjs: 7.6.6 gtoken@8.0.0(supports-color@11.0.0): @@ -14505,9 +14320,9 @@ snapshots: jsdom@30.1.2(@noble/hashes@1.8.0): dependencies: - '@asamuzakjp/css-color': 7.1.3 + '@asamuzakjp/css-color': 7.1.5 '@asamuzakjp/dom-selector': 9.2.4 - '@bramus/specificity': 2.4.2 + '@bramus/specificity': 2.4.3 '@csstools/css-syntax-patches-for-csstree': 1.1.15(css-tree@3.2.1) '@exodus/bytes': 1.16.0(@noble/hashes@1.8.0) css-tree: 3.2.1 @@ -14665,7 +14480,7 @@ snapshots: kind-of@6.0.3: {} - launch-editor@2.14.1: + launch-editor@2.14.2: dependencies: picocolors: 1.1.1 shell-quote: 1.12.0 @@ -14877,10 +14692,6 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.6.0 - magic-string@1.4.2: - dependencies: - '@jridgewell/sourcemap-codec': 1.6.0 - magic-string@1.4.3: dependencies: '@jridgewell/sourcemap-codec': 1.6.0 @@ -14984,19 +14795,6 @@ snapshots: minimist@1.2.8: {} - minimizer-webpack-plugin@5.13.0(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.28)(uglify-js@3.19.3)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.28)(uglify-js@3.19.3)): - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - jest-worker: 27.5.1 - schema-utils: 4.5.0 - terser: 5.51.2 - webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.28)(uglify-js@3.19.3) - optionalDependencies: - esbuild: 0.28.2 - lightningcss: 1.33.0 - postcss: 8.5.28 - uglify-js: 3.19.3 - minimizer-webpack-plugin@5.13.0(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)): dependencies: '@jridgewell/trace-mapping': 0.3.31 @@ -15060,7 +14858,7 @@ snapshots: mute-stream@3.0.0: {} - nanoid@3.3.19: {} + nanoid@3.3.20: {} natural-compare@1.4.0: {} @@ -15104,9 +14902,9 @@ snapshots: jsonc-parser: 3.3.1 less: 4.9.1(supports-color@11.0.0) ora: 9.4.1 - postcss: 8.5.28 - rolldown: 1.2.11 - rolldown-plugin-dts: 0.28.6(rolldown@1.2.11)(typescript@6.0.3) + postcss: 8.5.29 + rolldown: 1.2.12 + rolldown-plugin-dts: 0.28.6(rolldown@1.2.12)(typescript@6.0.3) rxjs: 7.8.2 sass: 1.105.1 sass-embedded: 1.105.1 @@ -15160,7 +14958,7 @@ snapshots: node-gyp-build@4.8.4: {} - node-releases@2.0.57: {} + node-releases@2.0.58: {} normalize-path@3.0.0: {} @@ -15417,7 +15215,7 @@ snapshots: pino-abstract-transport@1.2.0: dependencies: - readable-stream: 4.7.0 + readable-stream: 4.8.0 split2: 4.2.0 pino-abstract-transport@2.0.0: @@ -15433,7 +15231,7 @@ snapshots: on-exit-leak-free: 2.1.2 pino-abstract-transport: 2.0.0 pino-std-serializers: 7.1.0 - process-warning: 5.1.0 + process-warning: 5.1.1 quick-format-unescaped: 4.0.4 real-require: 0.2.0 safe-stable-stringify: 2.5.0 @@ -15511,15 +15309,9 @@ snapshots: postcss-value-parser@4.2.0: {} - postcss@8.5.28: - dependencies: - nanoid: 3.3.19 - picocolors: 1.1.1 - source-map-js: 1.2.2 - postcss@8.5.29: dependencies: - nanoid: 3.3.19 + nanoid: 3.3.20 picocolors: 1.1.1 source-map-js: 1.2.2 @@ -15527,7 +15319,7 @@ snapshots: prelude-ls@1.2.1: {} - prettier@3.9.9: {} + prettier@3.9.10: {} probe-image-size@7.4.0(supports-color@11.0.0): dependencies: @@ -15544,7 +15336,7 @@ snapshots: process-warning@1.0.0: {} - process-warning@5.1.0: {} + process-warning@5.1.1: {} process@0.11.10: {} @@ -15702,7 +15494,7 @@ snapshots: process: 0.11.10 string_decoder: 1.3.0 - readable-stream@4.7.0: + readable-stream@4.8.0: dependencies: abort-controller: 3.0.0 buffer: 6.0.3 @@ -15748,18 +15540,18 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 - regexpu-core@6.5.2: + regexpu-core@6.5.3: dependencies: regenerate: 1.5.0 regenerate-unicode-properties: 10.3.0 regjsgen: 0.8.0 - regjsparser: 0.13.3 + regjsparser: 0.13.4 unicode-match-property-ecmascript: 2.0.0 unicode-match-property-value-ecmascript: 2.2.1 regjsgen@0.8.0: {} - regjsparser@0.13.3: + regjsparser@0.13.4: dependencies: jsesc: 3.1.0 @@ -15783,7 +15575,7 @@ snapshots: postcss: 8.5.29 source-map: 0.6.1 - resolve@1.22.12: + resolve@1.22.13: dependencies: es-errors: 1.3.0 is-core-module: 2.17.0 @@ -15838,20 +15630,6 @@ snapshots: dependencies: glob: 10.5.0 - rolldown-plugin-dts@0.28.6(rolldown@1.2.11)(typescript@6.0.3): - dependencies: - dts-resolver: 3.0.0 - get-tsconfig: 5.0.0-beta.6 - obug: 3.0.0 - rolldown: 1.2.11 - yuku-ast: 0.10.2 - yuku-codegen: 0.10.2 - yuku-parser: 0.10.2 - optionalDependencies: - typescript: 6.0.3 - transitivePeerDependencies: - - oxc-resolver - rolldown-plugin-dts@0.28.6(rolldown@1.2.12)(typescript@6.0.3): dependencies: dts-resolver: 3.0.0 @@ -15866,27 +15644,6 @@ snapshots: transitivePeerDependencies: - oxc-resolver - rolldown@1.2.11: - dependencies: - '@oxc-project/types': 0.151.0 - '@rolldown/pluginutils': 1.0.1 - optionalDependencies: - '@rolldown/binding-android-arm-eabi': 1.2.11 - '@rolldown/binding-android-arm64': 1.2.11 - '@rolldown/binding-darwin-arm64': 1.2.11 - '@rolldown/binding-darwin-x64': 1.2.11 - '@rolldown/binding-freebsd-x64': 1.2.11 - '@rolldown/binding-linux-arm-gnueabihf': 1.2.11 - '@rolldown/binding-linux-arm64-gnu': 1.2.11 - '@rolldown/binding-linux-arm64-musl': 1.2.11 - '@rolldown/binding-linux-ppc64-gnu': 1.2.11 - '@rolldown/binding-linux-s390x-gnu': 1.2.11 - '@rolldown/binding-linux-x64-gnu': 1.2.11 - '@rolldown/binding-linux-x64-musl': 1.2.11 - '@rolldown/binding-openharmony-arm64': 1.2.11 - '@rolldown/binding-win32-arm64-msvc': 1.2.11 - '@rolldown/binding-win32-x64-msvc': 1.2.11 - rolldown@1.2.12: dependencies: '@oxc-project/types': 0.152.0 @@ -16516,7 +16273,7 @@ snapshots: tar-stream@3.2.0: dependencies: b4a: 1.9.0 - bare-fs: 4.8.2 + bare-fs: 4.8.4 fast-fifo: 1.3.2 streamx: 2.28.1 transitivePeerDependencies: @@ -16527,7 +16284,7 @@ snapshots: tar-stream@3.2.2: dependencies: b4a: 1.9.0 - bare-fs: 4.8.2 + bare-fs: 4.8.4 fast-fifo: 1.3.2 streamx: 2.28.1 transitivePeerDependencies: @@ -16554,7 +16311,7 @@ snapshots: terser@5.51.2: dependencies: '@jridgewell/source-map': 0.3.11 - acorn: 8.18.0 + acorn: 8.19.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -16587,7 +16344,7 @@ snapshots: tiny-inflate@1.0.3: {} - tinybench@6.2.0: {} + tinybench@6.2.2: {} tinyexec@1.3.1: {} @@ -16600,15 +16357,15 @@ snapshots: tldts-core@6.1.86: {} - tldts-core@7.4.16: {} + tldts-core@7.4.18: {} tldts@6.1.86: dependencies: tldts-core: 6.1.86 - tldts@7.4.16: + tldts@7.4.18: dependencies: - tldts-core: 7.4.16 + tldts-core: 7.4.18 tmp@0.2.7: {} @@ -16626,7 +16383,7 @@ snapshots: tough-cookie@6.0.2: dependencies: - tldts: 7.4.16 + tldts: 7.4.18 tr46@0.0.3: {} @@ -16791,7 +16548,7 @@ snapshots: unpipe@1.0.0: {} - update-browserslist-db@1.3.3(browserslist@4.29.3): + update-browserslist-db@1.3.4(browserslist@4.29.3): dependencies: browserslist: 4.29.3 escalade: 3.2.0 @@ -16832,9 +16589,9 @@ snapshots: - encoding - supports-color - verdaccio-auth-memory@13.1.5(supports-color@11.0.0): + verdaccio-auth-memory@13.1.6(supports-color@11.0.0): dependencies: - '@verdaccio/core': 8.3.2 + '@verdaccio/core': 8.3.3 debug: 4.4.3(supports-color@11.0.0) transitivePeerDependencies: - supports-color @@ -16904,8 +16661,8 @@ snapshots: dependencies: lightningcss: 1.33.0 picomatch: 4.0.7 - postcss: 8.5.28 - rolldown: 1.2.11 + postcss: 8.5.29 + rolldown: 1.2.12 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 22.20.5 @@ -16926,11 +16683,11 @@ snapshots: chai: 6.3.0 es-module-lexer: 2.3.2 expect-type: 1.4.0 - magic-string: 1.4.2 + magic-string: 1.4.3 obug: 2.2.1 picomatch: 4.0.7 std-env: 4.3.0 - tinybench: 6.2.0 + tinybench: 6.2.2 tinyexec: 1.3.1 tinyglobby: 0.2.17 vite: 8.3.3(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1) @@ -16966,16 +16723,6 @@ snapshots: webidl-conversions@8.0.1: {} - webpack-dev-middleware@8.3.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.28)(uglify-js@3.19.3)): - dependencies: - ansi-html-community: 0.0.8 - memfs: 4.80.0 - mime-types: 3.0.2 - range-parser: 1.3.0 - schema-utils: 4.5.0 - optionalDependencies: - webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.28)(uglify-js@3.19.3) - webpack-dev-middleware@8.3.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)): dependencies: ansi-html-community: 0.0.8 @@ -16986,40 +16733,6 @@ snapshots: optionalDependencies: webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3) - webpack-dev-server@6.0.0(bufferutil@4.1.0)(supports-color@11.0.0)(utf-8-validate@6.0.6)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.28)(uglify-js@3.19.3)): - dependencies: - '@types/bonjour': 3.5.13 - '@types/connect-history-api-fallback': 1.5.4 - '@types/express': 5.0.6 - '@types/express-serve-static-core': 5.1.3 - '@types/serve-index': 1.9.4 - '@types/serve-static': 2.2.0 - '@types/ws': 8.18.2 - ansi-html-community: 0.0.8 - bonjour-service: 1.4.4 - chokidar: 5.0.0 - compression: 1.8.2(supports-color@11.0.0) - connect-history-api-fallback: 2.0.0 - express: 5.2.1(supports-color@11.0.0) - graceful-fs: 4.2.11 - http-proxy-middleware: 4.2.0(supports-color@11.0.0) - ipaddr.js: 2.5.0 - launch-editor: 2.14.1 - open: 11.0.4 - p-retry: 8.0.1 - schema-utils: 4.5.0 - selfsigned: 5.5.0 - serve-index: 1.9.2(supports-color@11.0.0) - tinyglobby: 0.2.17 - webpack-dev-middleware: 8.3.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.28)(uglify-js@3.19.3)) - ws: 8.22.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) - optionalDependencies: - webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.28)(uglify-js@3.19.3) - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - webpack-dev-server@6.0.0(bufferutil@4.1.0)(supports-color@11.0.0)(utf-8-validate@6.0.6)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)): dependencies: '@types/bonjour': 3.5.13 @@ -17038,7 +16751,7 @@ snapshots: graceful-fs: 4.2.11 http-proxy-middleware: 4.2.0(supports-color@11.0.0) ipaddr.js: 2.5.0 - launch-editor: 2.14.1 + launch-editor: 2.14.2 open: 11.0.4 p-retry: 8.0.1 schema-utils: 4.5.0 @@ -17067,43 +16780,6 @@ snapshots: typed-assert: 1.0.9 webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3) - webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.28)(uglify-js@3.19.3): - dependencies: - '@types/estree': 1.0.9 - '@types/json-schema': 7.0.15 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - browserslist: 4.29.3 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.26.0 - es-module-lexer: 2.3.2 - events: 3.3.0 - graceful-fs: 4.2.11 - mime-db: 1.54.0 - minimizer-webpack-plugin: 5.13.0(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.28)(uglify-js@3.19.3)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.28)(uglify-js@3.19.3)) - schema-utils: 4.5.0 - tapable: 2.3.3 - watchpack: 2.5.2 - webpack-sources: 3.6.0 - transitivePeerDependencies: - - '@minify-html/node' - - '@napi-rs/image' - - '@swc/core' - - '@swc/css' - - '@swc/html' - - clean-css - - cssnano - - csso - - esbuild - - html-minifier-terser - - imagemin - - lightningcss - - postcss - - sharp - - svgo - - uglify-js - webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3): dependencies: '@types/estree': 1.0.9 From 22efeff5aa8eb50e3b507cfdd1da70283b6a9ef1 Mon Sep 17 00:00:00 2001 From: Angular Robot Date: Tue, 13 Oct 2026 03:46:16 +0000 Subject: [PATCH 25/52] build: update cross-repo angular dependencies See associated pull request for more information. --- tests/e2e/ng-snapshot/package.json | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/e2e/ng-snapshot/package.json b/tests/e2e/ng-snapshot/package.json index 7bf474571ca6..0618eb046f57 100644 --- a/tests/e2e/ng-snapshot/package.json +++ b/tests/e2e/ng-snapshot/package.json @@ -2,21 +2,21 @@ "description": "snapshot versions of Angular for e2e testing", "private": true, "dependencies": { - "@angular/animations": "github:angular/animations-builds#49e5662e0f5a6a052d8b66bd639ce261b231c807", + "@angular/animations": "github:angular/animations-builds#7ef64e48fbd50c668e386243a1d4c2f1ef84675b", "@angular/cdk": "github:angular/cdk-builds#8aa05501715c9b9b0fc95625f52b3b536c35cc4a", - "@angular/common": "github:angular/common-builds#e75bc632bb0f4c992336add2cd9429a5fc580165", - "@angular/compiler": "github:angular/compiler-builds#12aa4df6f3b1bc8402d329301391ab4f52179111", - "@angular/compiler-cli": "github:angular/compiler-cli-builds#051fd3767d2922649e6630cdbd4d726e99900949", - "@angular/core": "github:angular/core-builds#7b84cd24ec45174b8cc0a42e821a98b1a0d330eb", - "@angular/forms": "github:angular/forms-builds#fea1091472626b0c62c1300a4822216a55092cf6", - "@angular/language-service": "github:angular/language-service-builds#60d0bc6afa8bba745ba051afb88a8ccc6d72f61d", - "@angular/localize": "github:angular/localize-builds#5f21029e84cf4fab2902818b5351a9b131cef532", + "@angular/common": "github:angular/common-builds#96bb8a452e96a75e2130519f1301b25a08e408ec", + "@angular/compiler": "github:angular/compiler-builds#c94e6865d332afa0694d24049624ef23d1923089", + "@angular/compiler-cli": "github:angular/compiler-cli-builds#2d4f2f5eede86c9f3fa7ec4e8ce4cf03fc502d54", + "@angular/core": "github:angular/core-builds#f43cfb919a0da367f40da1bd07e67cd1845388c2", + "@angular/forms": "github:angular/forms-builds#a181c75be824e20dcc653e7e029217014aaae777", + "@angular/language-service": "github:angular/language-service-builds#3224af77e1a302a3ba6a5620fce41879c8c8158e", + "@angular/localize": "github:angular/localize-builds#b1148951f8251042228b544facb01d24f40d7380", "@angular/material": "github:angular/material-builds#5f4d7a4724a306e1e24d55f53564eebfa22dbdd4", "@angular/material-moment-adapter": "github:angular/material-moment-adapter-builds#a600a485f5c91b376684763cbf00b158f85502f0", - "@angular/platform-browser": "github:angular/platform-browser-builds#69be31f21a8df04fd8157676b7d885c94de8bdc6", - "@angular/platform-browser-dynamic": "github:angular/platform-browser-dynamic-builds#f8c0d0c407dd393e8f49593039ae2100f4504e11", - "@angular/platform-server": "github:angular/platform-server-builds#8e9d51d325c6575b54e118410281b6ffb2bd76a9", - "@angular/router": "github:angular/router-builds#42ae1c53acc2bcf444ef4d4d3e84ccdda61486db", - "@angular/service-worker": "github:angular/service-worker-builds#5ac1b5c6526c04ac8d1ba1e74f22f9998020eaf7" + "@angular/platform-browser": "github:angular/platform-browser-builds#b8cd3c70f3e83ccc2675345dbaef19406c274814", + "@angular/platform-browser-dynamic": "github:angular/platform-browser-dynamic-builds#81f80d43de410f7d4a2f0da625ca5882b7c3f71a", + "@angular/platform-server": "github:angular/platform-server-builds#b94ffc850d236d03d53460c6bb72b23eb7e21920", + "@angular/router": "github:angular/router-builds#cbe6196b50ea6948bb8ade7ac32f26029d37ca45", + "@angular/service-worker": "github:angular/service-worker-builds#5bb5c383c8e2323d28a2347a784327e031a4b101" } } From 48f8c0ca9c6615bdc28272970cc3091ee4e64426 Mon Sep 17 00:00:00 2001 From: Angular Robot Date: Tue, 13 Oct 2026 19:53:16 +0000 Subject: [PATCH 26/52] build: update all non-major dependencies See associated pull request for more information. --- modules/testing/builder/package.json | 4 +- package.json | 16 +- packages/angular/build/package.json | 16 +- packages/angular/cli/package.json | 6 +- packages/angular/ssr/package.json | 2 +- .../angular_devkit/build_angular/package.json | 2 +- pnpm-lock.yaml | 1137 +++++++++++------ 7 files changed, 794 insertions(+), 389 deletions(-) diff --git a/modules/testing/builder/package.json b/modules/testing/builder/package.json index 8823cbf0c68e..398a200cdf8a 100644 --- a/modules/testing/builder/package.json +++ b/modules/testing/builder/package.json @@ -4,12 +4,12 @@ "@angular-devkit/build-angular": "workspace:*", "@angular-devkit/core": "workspace:*", "@angular/ssr": "workspace:*", - "@vitest/coverage-v8": "5.0.3", + "@vitest/coverage-v8": "5.0.4", "browser-sync": "3.0.4", "istanbul-lib-instrument": "6.0.3", "jsdom": "30.1.2", "ng-packagr": "22.3.0-next.2", "rxjs": "7.8.2", - "vitest": "5.0.3" + "vitest": "5.0.4" } } diff --git a/package.json b/package.json index 6541f5d157af..c2efa7133c4f 100644 --- a/package.json +++ b/package.json @@ -29,12 +29,12 @@ "type": "git", "url": "git+https://github.com/angular/angular-cli.git" }, - "packageManager": "pnpm@12.10.1", + "packageManager": "pnpm@12.11.2", "engines": { "node": "^22.22.3 || ^24.15.0 || >=26.0.0", "npm": "Please use pnpm instead of NPM to install dependencies", "yarn": "Please use pnpm instead of Yarn to install dependencies", - "pnpm": "12.10.1" + "pnpm": "12.11.2" }, "author": "Angular Authors", "license": "MIT", @@ -70,7 +70,7 @@ "@rollup/plugin-commonjs": "^29.0.0", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "16.0.3", - "@rollup/wasm-node": "4.64.1", + "@rollup/wasm-node": "4.64.5", "@stylistic/eslint-plugin": "^5.0.0", "@tony.ganchev/eslint-plugin-header": "~3.4.0", "@types/babel__core": "7.20.5", @@ -91,8 +91,8 @@ "@types/semver": "^7.3.12", "@types/yargs": "^17.0.20", "@types/yargs-parser": "^21.0.0", - "@typescript-eslint/eslint-plugin": "8.71.1", - "@typescript-eslint/parser": "8.71.1", + "@typescript-eslint/eslint-plugin": "8.71.2", + "@typescript-eslint/parser": "8.71.2", "ajv": "8.20.0", "buffer": "6.0.3", "esbuild": "0.28.2", @@ -100,7 +100,7 @@ "eslint": "10.12.0", "eslint-config-prettier": "10.1.8", "eslint-plugin-import": "2.32.0", - "express": "5.2.1", + "express": "5.3.0", "fast-glob": "3.3.3", "globals": "17.13.0", "http-proxy": "^1.18.1", @@ -119,9 +119,9 @@ "lodash": "^4.17.21", "magic-string": "1.4.3", "prettier": "^3.0.0", - "puppeteer": "25.12.0", + "puppeteer": "25.13.0", "quicktype-core": "26.0.0", - "rollup": "4.64.1", + "rollup": "4.64.5", "rollup-plugin-dts": "6.5.1", "rollup-plugin-sourcemaps2": "0.5.9", "semver": "7.8.5", diff --git a/packages/angular/build/package.json b/packages/angular/build/package.json index 2aa20f0c6b8f..a5227c45c526 100644 --- a/packages/angular/build/package.json +++ b/packages/angular/build/package.json @@ -24,27 +24,27 @@ "@inquirer/confirm": "6.3.3", "@parcel/watcher": "2.6.0", "@vitejs/plugin-basic-ssl": "2.3.0", - "beasties": "0.5.4", + "beasties": "0.5.5", "browserslist": "^4.26.0", "chokidar": "5.0.0", "esbuild": "0.28.2", "https-proxy-agent": "9.1.0", "jsonc-parser": "3.3.1", - "listr2": "11.1.1", + "listr2": "11.2.0", "magic-string": "1.4.3", "mrmime": "2.0.1", "oxc-parser": "0.153.0", "parse5-html-rewriting-stream": "8.0.1", "picomatch": "4.0.7", "piscina": "5.3.2", - "rolldown": "1.2.12", - "rolldown-plugin-dts": "0.28.6", + "rolldown": "1.2.13", + "rolldown-plugin-dts": "0.28.8", "sass": "1.105.1", "sass-embedded": "1.105.1", "semver": "7.8.5", "source-map-support": "0.5.21", "tinyglobby": "0.2.17", - "vite": "8.3.3", + "vite": "8.3.4", "xxhash-wasm": "1.1.0" }, "optionalDependencies": { @@ -54,15 +54,15 @@ "@angular-devkit/core": "workspace:*", "@angular/ssr": "workspace:*", "@oxc-project/types": "0.153.0", - "@vitest/coverage-v8": "5.0.3", + "@vitest/coverage-v8": "5.0.4", "istanbul-lib-instrument": "6.0.3", "jsdom": "30.1.2", "less": "4.9.1", "ng-packagr": "22.3.0-next.2", "postcss": "8.5.29", - "rollup": "4.64.1", + "rollup": "4.64.5", "rxjs": "7.8.2", - "vitest": "5.0.3" + "vitest": "5.0.4" }, "peerDependencies": { "@angular/compiler": "0.0.0-ANGULAR-FW-PEER-DEP", diff --git a/packages/angular/cli/package.json b/packages/angular/cli/package.json index ef6e3407b670..f558e7a6293d 100644 --- a/packages/angular/cli/package.json +++ b/packages/angular/cli/package.json @@ -21,16 +21,16 @@ "@angular-devkit/core": "workspace:0.0.0-PLACEHOLDER", "@angular-devkit/schematics": "workspace:0.0.0-PLACEHOLDER", "@inquirer/prompts": "8.7.3", - "@listr2/prompt-adapter-inquirer": "4.2.7", + "@listr2/prompt-adapter-inquirer": "4.3.1", "@modelcontextprotocol/server": "2.3.1", "@schematics/angular": "workspace:0.0.0-PLACEHOLDER", "jsonc-parser": "3.3.1", - "listr2": "11.1.1", + "listr2": "11.2.0", "npm-package-arg": "14.0.0", "parse5-html-rewriting-stream": "8.0.1", "semver": "7.8.5", "yargs": "18.2.0", - "zod": "4.6.5" + "zod": "4.6.7" }, "ng-update": { "migrations": "@schematics/angular/migrations/migration-collection.json", diff --git a/packages/angular/ssr/package.json b/packages/angular/ssr/package.json index 6e3596ca6aae..9d86125f4aad 100644 --- a/packages/angular/ssr/package.json +++ b/packages/angular/ssr/package.json @@ -22,7 +22,7 @@ "save": "dependencies" }, "dependencies": { - "beasties": "0.5.4", + "beasties": "0.5.5", "tslib": "^2.3.0" }, "peerDependencies": { diff --git a/packages/angular_devkit/build_angular/package.json b/packages/angular_devkit/build_angular/package.json index 6976448a01c0..502d27aa5975 100644 --- a/packages/angular_devkit/build_angular/package.json +++ b/packages/angular_devkit/build_angular/package.json @@ -25,7 +25,7 @@ "ansi-colors": "4.1.3", "autoprefixer": "10.6.1", "babel-loader": "10.1.1", - "beasties": "0.5.4", + "beasties": "0.5.5", "browserslist": "^4.26.0", "copy-webpack-plugin": "14.0.0", "css-loader": "7.1.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2d1df736b28c..b2b2fdfdffd9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,153 +7,153 @@ importers: configDependencies: {} packageManagerDependencies: pnpm: - specifier: 12.10.1 - version: 12.10.1 + specifier: 12.11.2 + version: 12.11.2 packages: - '@pnpm/exe.android-arm64@12.10.1': - resolution: {integrity: sha512-CVTlHPwNvadQCJD9bGSMzWIhFX8QpjtqC2c27dhdnn/9iKzEjZ3qL62o3gHpKbIuo6qn4WxTKRoaokgNdReBig==} + '@pnpm/exe.android-arm64@12.11.2': + resolution: {integrity: sha512-owLw13OfPkEoY+hLBNeeG+dCFhywr7q2d/EHPz4mNL2RhKnv8gNwMARkjkiDQu234aItVwFNDeGnmQXm+ikkAg==} cpu: [arm64] os: [android] - '@pnpm/exe.android-x64@12.10.1': - resolution: {integrity: sha512-NFiYLIaodY7da0XIebwcU3JoP7IK/lzF7zgKSSP+9H+QcFnQ1GDfBkuBKCYJzZ+Xu0WH54neIPLBBCaOjaaauA==} + '@pnpm/exe.android-x64@12.11.2': + resolution: {integrity: sha512-GYPkVebl4iokOA/4MPSpGoUVfFlsth7uqOCe1XiaiM23LAdvUOMJBObqHJijr89ZqjwHm9pO6vO45GRwJ2U2qA==} cpu: [x64] os: [android] - '@pnpm/exe.darwin-arm64@12.10.1': - resolution: {integrity: sha512-0O8tdQ8ijlPJudXspLMTcitMkdBEz6uUflazL5uQE0WMs85oQIp0U+5hfEktMFB64QqEhjqlvvujTwbzdr9oMg==} + '@pnpm/exe.darwin-arm64@12.11.2': + resolution: {integrity: sha512-n9M4On66y8FDxUAKgMO1FXt0qihyG4e+56p3/F0uo8Bx9KplW8BwKVnXigzCJ8aNM6sVVPkOE6M9XXbeVIxnZA==} cpu: [arm64] os: [darwin] - '@pnpm/exe.darwin-x64@12.10.1': - resolution: {integrity: sha512-ud+1/uZOKEo8P/AsPynOJc/LNwfI0j6WwCElibj71rU9l4nIBnsSn+wWTIPZPkZ4BBSH5+82azSnAARMyJ1lNA==} + '@pnpm/exe.darwin-x64@12.11.2': + resolution: {integrity: sha512-oSW7n3sBT0c0cyk4kj10T2Y6Mpm+OFEiCAWozgX039tdoI6yqJF1uaFD3sw7ugLdu6VV3+uY0pa1TUZIPdxDWA==} cpu: [x64] os: [darwin] - '@pnpm/exe.freebsd-x64@12.10.1': - resolution: {integrity: sha512-mj9PE5rf8uAfQQ2K66HSATMSut+lNiB4eSqFd5+azFVCMnxNSy/32xpZQJT21PhnN3Y4qbK+iKHe5nWAxSuRhw==} + '@pnpm/exe.freebsd-x64@12.11.2': + resolution: {integrity: sha512-qbzc3KoDpa/Lkf8vs3jnDe6dUUbso+6eLIyssYFMiliLpYNxn8dirk11YoNnOQcdHVB50v5RFls1Yid6ttT5pg==} cpu: [x64] os: [freebsd] - '@pnpm/exe.linux-arm64-musl@12.10.1': - resolution: {integrity: sha512-xba+00wZJ8Um6rBJJjWl88uJj0tydB8dtomvjlCLvi0uL32vpa9CRP8Vv26FIXvbiZ1bo2RCzYt/eChxJVV52w==} + '@pnpm/exe.linux-arm64-musl@12.11.2': + resolution: {integrity: sha512-uMEYDwKRktGwANubQ+kYCwmhNwg3Ik6qK89ahsbQ5cP30R/5FVJb/T99vr9XRUBC/A7mZI6eeT92oyVas9ACyg==} cpu: [arm64] os: [linux] libc: [musl] - '@pnpm/exe.linux-arm64@12.10.1': - resolution: {integrity: sha512-oBdMp69ScC9UnniG4qZAQVr2fBDSXjm4yk/72vkEVyrlwS23yMxcRQl7Qdo3sgXPAygY6TWnPRKm4rXzjoyW7w==} + '@pnpm/exe.linux-arm64@12.11.2': + resolution: {integrity: sha512-6e8ZAQUwFXAWHHHv5FesWqf/kEK04wuitBv5f/gxzkC0DiBfaixr+f+6JQede8SF4Ji5LcMwVFJbzAtffpWxEg==} cpu: [arm64] os: [linux] libc: [glibc] - '@pnpm/exe.linux-ppc64@12.10.1': - resolution: {integrity: sha512-Yyb3wu09h3c7mLme270uHFiVaAIUHC411Ru9LIU2BKUIstrGlXa9OqqVWoXaRgYRdFdOFknkwG7GNn6ygwLbnw==} + '@pnpm/exe.linux-ppc64@12.11.2': + resolution: {integrity: sha512-Ui8A4nepkVupx2VpuFfysEluMvWK6gTB5rgVts7Ss/+8dj0RD28x3F/seNeH/zSypgC6yKdV6qsKVQh/uffTuQ==} cpu: [ppc64] os: [linux] libc: [glibc] - '@pnpm/exe.linux-riscv64@12.10.1': - resolution: {integrity: sha512-PdkeUFFkybknnGkWP0H22eMpIiS4OZXL5BcQzF4lh+vmrW3IaC2HOkbANKgot/PKO0Kl77pzA/6PKFxgbgfXIQ==} + '@pnpm/exe.linux-riscv64@12.11.2': + resolution: {integrity: sha512-i1yLdQ5bu+wjQ+srtFoJAaY2gN/+oXHFdjul4llCeoDxHE0rTIG3R41NhHfCjyFPW4+CpbBT58933CL9sMOCnA==} cpu: [riscv64] os: [linux] libc: [glibc] - '@pnpm/exe.linux-s390x@12.10.1': - resolution: {integrity: sha512-1okKuHKJwJPAbofDxfhZWAUxEWtee4ZSf7Pah8kcvocaJkf2WxFJ5KVTiNIvDml5GLidDQsgf7Pcf/WHbCak7Q==} + '@pnpm/exe.linux-s390x@12.11.2': + resolution: {integrity: sha512-YS1/lhPjjTsN4QL50VaFZKRa3Uc/bDnhE8eKbJMFvuX06UuFS5YaiDg04APoZdfVSGqTfX27QAg7rfLMSWaqxA==} cpu: [s390x] os: [linux] libc: [glibc] - '@pnpm/exe.linux-x64-musl@12.10.1': - resolution: {integrity: sha512-e6IqzVNkPa7srFKJKnY23uWJ+qz0LaRWiTUo/sHfFXRRMRzB5uNOr6qWWip/jqhdGwU91n9J7LrEYZ6e0tRczw==} + '@pnpm/exe.linux-x64-musl@12.11.2': + resolution: {integrity: sha512-7eIxQR05fvJxCujUSKp5KTtehJ7QqrgqP/HD1+BcB/SaV2Be4XI1PEHiOgA1zxsiMIeMvTF6E4G4dYHrFjeXRg==} cpu: [x64] os: [linux] libc: [musl] - '@pnpm/exe.linux-x64@12.10.1': - resolution: {integrity: sha512-ZByV0DRgWzGaDSjT5ddRBASdwz+r/qPMYh7o6RGmPQjtRGNFbSl94xY2DcAM8mqCOZJUUDtAXQ+wpBXcdpKlkg==} + '@pnpm/exe.linux-x64@12.11.2': + resolution: {integrity: sha512-FK7QKe24AYgppJwO3mpooYptduuvIGqKJPi5ac7MdnWkjUy46JBfYhCW0grnkWKC8YOf0x+vGviuQqJEj3SpQQ==} cpu: [x64] os: [linux] libc: [glibc] - '@pnpm/exe.win32-arm64@12.10.1': - resolution: {integrity: sha512-I7QZHcjioG7orFeCRUFUHByJ1G0zFPnAlaGGyrUvb6MGkv5oeNwNPl7t+Gp+7zHfnMcgLGJ1a+Wfim0IDw3lOw==} + '@pnpm/exe.win32-arm64@12.11.2': + resolution: {integrity: sha512-PCTjVDdJb6VvraZxrEeFv6EqEA0hhIsAySx28e95J2Tqpi88hLpgOXgNqV0vpxq9A+b8GLQfyk/D+1UlJPv/YQ==} cpu: [arm64] os: [win32] - '@pnpm/exe.win32-x64@12.10.1': - resolution: {integrity: sha512-4WJFdp58EKlCj0zLobrXU0vpszSZIr4X/3y/uNbAQqGW0zE+VdruZB0gFc3L2kzsUzVwTYbaCn+XEhnCYSAlTg==} + '@pnpm/exe.win32-x64@12.11.2': + resolution: {integrity: sha512-8sgX86OvRjJ3yZs/TvGR2L31wH9ScPZ+f+geKI3ikuB0RRiK3i4LlTRO8OXN6pdRqj8epMde4312MCjj7JsJdA==} cpu: [x64] os: [win32] - pnpm@12.10.1: - resolution: {integrity: sha512-ukCjfrGjcNYP6oxM8dNkwTvMzvUY6YrSvO6VT1OdONo3RY5YJho/pV4GUjRQ6g//+fSXsTW+QfLBXBZCusrObA==} + pnpm@12.11.2: + resolution: {integrity: sha512-JaUWUqGWeFr18ovabf6NxYLr76SsHRgCIc4TkCMcX7dmN4IupLbkYzznSs3LCnf3Ja8RutOBd/3t2u6BipVcuQ==} engines: {node: '>=18.*'} hasBin: true snapshots: - '@pnpm/exe.android-arm64@12.10.1': + '@pnpm/exe.android-arm64@12.11.2': optional: true - '@pnpm/exe.android-x64@12.10.1': + '@pnpm/exe.android-x64@12.11.2': optional: true - '@pnpm/exe.darwin-arm64@12.10.1': + '@pnpm/exe.darwin-arm64@12.11.2': optional: true - '@pnpm/exe.darwin-x64@12.10.1': + '@pnpm/exe.darwin-x64@12.11.2': optional: true - '@pnpm/exe.freebsd-x64@12.10.1': + '@pnpm/exe.freebsd-x64@12.11.2': optional: true - '@pnpm/exe.linux-arm64-musl@12.10.1': + '@pnpm/exe.linux-arm64-musl@12.11.2': optional: true - '@pnpm/exe.linux-arm64@12.10.1': + '@pnpm/exe.linux-arm64@12.11.2': optional: true - '@pnpm/exe.linux-ppc64@12.10.1': + '@pnpm/exe.linux-ppc64@12.11.2': optional: true - '@pnpm/exe.linux-riscv64@12.10.1': + '@pnpm/exe.linux-riscv64@12.11.2': optional: true - '@pnpm/exe.linux-s390x@12.10.1': + '@pnpm/exe.linux-s390x@12.11.2': optional: true - '@pnpm/exe.linux-x64-musl@12.10.1': + '@pnpm/exe.linux-x64-musl@12.11.2': optional: true - '@pnpm/exe.linux-x64@12.10.1': + '@pnpm/exe.linux-x64@12.11.2': optional: true - '@pnpm/exe.win32-arm64@12.10.1': + '@pnpm/exe.win32-arm64@12.11.2': optional: true - '@pnpm/exe.win32-x64@12.10.1': + '@pnpm/exe.win32-x64@12.11.2': optional: true - pnpm@12.10.1: + pnpm@12.11.2: optionalDependencies: - '@pnpm/exe.android-arm64': 12.10.1 - '@pnpm/exe.android-x64': 12.10.1 - '@pnpm/exe.darwin-arm64': 12.10.1 - '@pnpm/exe.darwin-x64': 12.10.1 - '@pnpm/exe.freebsd-x64': 12.10.1 - '@pnpm/exe.linux-arm64': 12.10.1 - '@pnpm/exe.linux-arm64-musl': 12.10.1 - '@pnpm/exe.linux-ppc64': 12.10.1 - '@pnpm/exe.linux-riscv64': 12.10.1 - '@pnpm/exe.linux-s390x': 12.10.1 - '@pnpm/exe.linux-x64': 12.10.1 - '@pnpm/exe.linux-x64-musl': 12.10.1 - '@pnpm/exe.win32-arm64': 12.10.1 - '@pnpm/exe.win32-x64': 12.10.1 + '@pnpm/exe.android-arm64': 12.11.2 + '@pnpm/exe.android-x64': 12.11.2 + '@pnpm/exe.darwin-arm64': 12.11.2 + '@pnpm/exe.darwin-x64': 12.11.2 + '@pnpm/exe.freebsd-x64': 12.11.2 + '@pnpm/exe.linux-arm64': 12.11.2 + '@pnpm/exe.linux-arm64-musl': 12.11.2 + '@pnpm/exe.linux-ppc64': 12.11.2 + '@pnpm/exe.linux-riscv64': 12.11.2 + '@pnpm/exe.linux-s390x': 12.11.2 + '@pnpm/exe.linux-x64': 12.11.2 + '@pnpm/exe.linux-x64-musl': 12.11.2 + '@pnpm/exe.win32-arm64': 12.11.2 + '@pnpm/exe.win32-x64': 12.11.2 --- lockfileVersion: '9.0' @@ -245,16 +245,16 @@ importers: version: 10.0.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0)) '@rollup/plugin-commonjs': specifier: ^29.0.0 - version: 29.0.3(rollup@4.64.1) + version: 29.0.3(rollup@4.64.5) '@rollup/plugin-json': specifier: ^6.1.0 - version: 6.1.0(rollup@4.64.1) + version: 6.1.0(rollup@4.64.5) '@rollup/plugin-node-resolve': specifier: 16.0.3 - version: 16.0.3(rollup@4.64.1) + version: 16.0.3(rollup@4.64.5) '@rollup/wasm-node': - specifier: 4.64.1 - version: 4.64.1 + specifier: 4.64.5 + version: 4.64.5 '@stylistic/eslint-plugin': specifier: ^5.0.0 version: 5.10.0(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0)) @@ -316,11 +316,11 @@ importers: specifier: ^21.0.0 version: 21.0.3 '@typescript-eslint/eslint-plugin': - specifier: 8.71.1 - version: 8.71.1(@typescript-eslint/parser@8.71.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3))(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3) + specifier: 8.71.2 + version: 8.71.2(@typescript-eslint/parser@8.71.2(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3))(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3) '@typescript-eslint/parser': - specifier: 8.71.1 - version: 8.71.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3) + specifier: 8.71.2 + version: 8.71.2(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3) ajv: specifier: 8.20.0 version: 8.20.0 @@ -341,10 +341,10 @@ importers: version: 10.1.8(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0)) eslint-plugin-import: specifier: 2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.71.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3))(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0) + version: 2.32.0(@typescript-eslint/parser@8.71.2(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3))(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0) express: - specifier: 5.2.1 - version: 5.2.1(supports-color@11.0.0) + specifier: 5.3.0 + version: 5.3.0(supports-color@11.0.0) fast-glob: specifier: 3.3.3 version: 3.3.3 @@ -400,20 +400,20 @@ importers: specifier: ^3.0.0 version: 3.9.10 puppeteer: - specifier: 25.12.0 - version: 25.12.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + specifier: 25.13.0 + version: 25.13.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) quicktype-core: specifier: 26.0.0 version: 26.0.0 rollup: - specifier: 4.64.1 - version: 4.64.1 + specifier: 4.64.5 + version: 4.64.5 rollup-plugin-dts: specifier: 6.5.1 - version: 6.5.1(rollup@4.64.1)(typescript@6.0.3) + version: 6.5.1(rollup@4.64.5)(typescript@6.0.3) rollup-plugin-sourcemaps2: specifier: 0.5.9 - version: 0.5.9(@types/node@22.20.5)(rollup@4.64.1) + version: 0.5.9(@types/node@22.20.5)(rollup@4.64.5) semver: specifier: 7.8.5 version: 7.8.5 @@ -451,8 +451,8 @@ importers: specifier: workspace:* version: link:../../../packages/angular/ssr '@vitest/coverage-v8': - specifier: 5.0.3 - version: 5.0.3(vitest@5.0.3) + specifier: 5.0.4 + version: 5.0.4(vitest@5.0.4) browser-sync: specifier: 3.0.4 version: 3.0.4(bufferutil@4.1.0)(debug@4.4.3(supports-color@11.0.0))(supports-color@11.0.0)(utf-8-validate@6.0.6) @@ -469,8 +469,8 @@ importers: specifier: 7.8.2 version: 7.8.2 vitest: - specifier: 5.0.3 - version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@22.20.5)(@vitest/coverage-v8@5.0.3)(jsdom@30.1.2(@noble/hashes@1.8.0))(vite@8.3.3(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) + specifier: 5.0.4 + version: 5.0.4(@opentelemetry/api@1.9.1)(@types/node@22.20.5)(@vitest/coverage-v8@5.0.4)(jsdom@30.1.2(@noble/hashes@1.8.0))(vite@8.3.4(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) packages/angular/build: dependencies: @@ -491,10 +491,10 @@ importers: version: 2.6.0 '@vitejs/plugin-basic-ssl': specifier: 2.3.0 - version: 2.3.0(vite@8.3.3(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) + version: 2.3.0(vite@8.3.4(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) beasties: - specifier: 0.5.4 - version: 0.5.4 + specifier: 0.5.5 + version: 0.5.5 browserslist: specifier: ^4.26.0 version: 4.29.3 @@ -511,8 +511,8 @@ importers: specifier: 3.3.1 version: 3.3.1 listr2: - specifier: 11.1.1 - version: 11.1.1 + specifier: 11.2.0 + version: 11.2.0 magic-string: specifier: 1.4.3 version: 1.4.3 @@ -532,11 +532,11 @@ importers: specifier: 5.3.2 version: 5.3.2 rolldown: - specifier: 1.2.12 - version: 1.2.12 + specifier: 1.2.13 + version: 1.2.13 rolldown-plugin-dts: - specifier: 0.28.6 - version: 0.28.6(rolldown@1.2.12)(typescript@6.0.3) + specifier: 0.28.8 + version: 0.28.8(rolldown@1.2.13)(typescript@6.0.3) sass: specifier: 1.105.1 version: 1.105.1 @@ -553,8 +553,8 @@ importers: specifier: 0.2.17 version: 0.2.17 vite: - specifier: 8.3.3 - version: 8.3.3(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1) + specifier: 8.3.4 + version: 8.3.4(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1) xxhash-wasm: specifier: 1.1.0 version: 1.1.0 @@ -569,8 +569,8 @@ importers: specifier: 0.153.0 version: 0.153.0 '@vitest/coverage-v8': - specifier: 5.0.3 - version: 5.0.3(vitest@5.0.3) + specifier: 5.0.4 + version: 5.0.4(vitest@5.0.4) istanbul-lib-instrument: specifier: 6.0.3 version: 6.0.3(supports-color@11.0.0) @@ -587,14 +587,14 @@ importers: specifier: 8.5.29 version: 8.5.29 rollup: - specifier: 4.64.1 - version: 4.64.1 + specifier: 4.64.5 + version: 4.64.5 rxjs: specifier: 7.8.2 version: 7.8.2 vitest: - specifier: 5.0.3 - version: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@22.20.5)(@vitest/coverage-v8@5.0.3)(jsdom@30.1.2(@noble/hashes@1.8.0))(vite@8.3.3(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) + specifier: 5.0.4 + version: 5.0.4(@opentelemetry/api@1.9.1)(@types/node@22.20.5)(@vitest/coverage-v8@5.0.4)(jsdom@30.1.2(@noble/hashes@1.8.0))(vite@8.3.4(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) optionalDependencies: lmdb: specifier: 3.5.7 @@ -615,8 +615,8 @@ importers: specifier: 8.7.3 version: 8.7.3(@types/node@22.20.5) '@listr2/prompt-adapter-inquirer': - specifier: 4.2.7 - version: 4.2.7(@inquirer/prompts@8.7.3(@types/node@22.20.5))(@types/node@22.20.5)(listr2@11.1.1) + specifier: 4.3.1 + version: 4.3.1(@inquirer/prompts@8.7.3(@types/node@22.20.5))(@types/node@22.20.5)(listr2@11.2.0) '@modelcontextprotocol/server': specifier: 2.3.1 version: 2.3.1 @@ -627,8 +627,8 @@ importers: specifier: 3.3.1 version: 3.3.1 listr2: - specifier: 11.1.1 - version: 11.1.1 + specifier: 11.2.0 + version: 11.2.0 npm-package-arg: specifier: 14.0.0 version: 14.0.0 @@ -642,8 +642,8 @@ importers: specifier: 18.2.0 version: 18.2.0 zod: - specifier: 4.6.5 - version: 4.6.5 + specifier: 4.6.7 + version: 4.6.7 packages/angular/pwa: dependencies: @@ -660,8 +660,8 @@ importers: packages/angular/ssr: dependencies: beasties: - specifier: 0.5.4 - version: 0.5.4 + specifier: 0.5.5 + version: 0.5.5 tslib: specifier: ^2.3.0 version: 2.8.1 @@ -760,8 +760,8 @@ importers: specifier: 10.1.1 version: 10.1.1(@babel/core@8.0.7)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)) beasties: - specifier: 0.5.4 - version: 0.5.4 + specifier: 0.5.5 + version: 0.5.5 browserslist: specifier: ^4.26.0 version: 4.29.3 @@ -2634,12 +2634,12 @@ packages: '@leichtgewicht/ip-codec@2.0.5': resolution: {integrity: sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==} - '@listr2/prompt-adapter-inquirer@4.2.7': - resolution: {integrity: sha512-k180vxSv2KqmnDxoato6pCqEJsov4U5C0EVmldZkAdNeVBxY48A/LM6TCNPGIzDK/iZSfsZP0Mw+gbWc5hXLyA==} + '@listr2/prompt-adapter-inquirer@4.3.1': + resolution: {integrity: sha512-NnKK9IrkBPr3v9DxXz/MTxQ989bJEfH1Q6Qr+MA9XU0QRXEgAQJO4XjFs8OzPQI5WYScz0kXi9WNDkANr2bRVw==} engines: {node: '>=22.13.0'} peerDependencies: '@inquirer/prompts': '>= 3 < 9' - listr2: 11.1.0 + listr2: ^11.0.0 '@lmdb/lmdb-darwin-arm64@3.5.7': resolution: {integrity: sha512-Y0CUvoj3ToaPQGdiqtodR0yrbAToNV74ylGQGSsNzmACO6iqKIUdU2OyFhkB+AAYpyfCA6oYh8hxbtc7eZhklA==} @@ -3265,8 +3265,8 @@ packages: '@protobufjs/utf8@1.1.2': resolution: {integrity: sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==} - '@puppeteer/browsers@3.2.3': - resolution: {integrity: sha512-2Bt3m6dDAJqmZehn0wiXSYyQmuhyiHHZ7FjvrVaS1W2RoFGV6eCK71UvKYkNJjkwC1Q9nobjhvTMhLQztFVINA==} + '@puppeteer/browsers@3.2.4': + resolution: {integrity: sha512-okJ6yQMc0SBexOKxMi966omwAV1uAPwgF/YMZdb04gZQPXVjWHl9bmXjZYtIcsN1+PN3Bz4iFfGK3g+c6lZJ0Q==} engines: {node: '>=22.12.0'} hasBin: true peerDependencies: @@ -3284,36 +3284,72 @@ packages: cpu: [arm] os: [android] + '@rolldown/binding-android-arm-eabi@1.2.13': + resolution: {integrity: sha512-Vu/NICrgdRvUOeaJZIyB2FP63s6fO/4ud5l8dXmxDx9yDyn+mN0y+gsvsVviSli+T361Aqo0h46EuMoobrwawA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + '@rolldown/binding-android-arm64@1.2.12': resolution: {integrity: sha512-7KHFgQ5VJxIHcLlrwrc3Xbds7oTNQT7Pgi9gQCJKrd2VGab/UksIOYp6VD8MzCstGxOKMgNamPwUCfxPdP1OHg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] + '@rolldown/binding-android-arm64@1.2.13': + resolution: {integrity: sha512-6LEoIrGy5vvCd2boNnv2soPSUZj/PRvhp8R/t9KlX+mIZxThIE/ZqxrGXxmuNX0FuvQFvLdZr7S4HrYpYBVhEQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + '@rolldown/binding-darwin-arm64@1.2.12': resolution: {integrity: sha512-3YIhqHD96nA5SaYNRBR16HnGv4oavZvXfD/ayHM+oYZ0WD/8lBAtf6zQua4kEyAvpqrluKXl0lnOBoiNby7x9w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] + '@rolldown/binding-darwin-arm64@1.2.13': + resolution: {integrity: sha512-CaJSRzlQ6Q+zkDMVA9OkVxBjVoPRCDEE3v0FSJ9kIQBgRjFApA3Si4ijhbNVUji7ZJt+PfO0e46qy4nPInHUPA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + '@rolldown/binding-darwin-x64@1.2.12': resolution: {integrity: sha512-UuuJ35MFw4gmFOrE9pEqIV+K3syIKveph+Qc1/ljHZVdoDW4pz/JHR/eMVom+TZGl/5OOvGJOWaOCVt3ZfqhxA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] + '@rolldown/binding-darwin-x64@1.2.13': + resolution: {integrity: sha512-e4r340I5hxSzJkD3YJBxgzq/rJ3wwxwdLLb2FPt1Zpyem20nrQPT11DDEEkazwxaHumH8wpglsp/Ozgj/wT6mw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + '@rolldown/binding-freebsd-x64@1.2.12': resolution: {integrity: sha512-uMvssit0a4W+/7D8CbHUvG719mH3R2jwXAlh/XcPvuHTE0g++LymF88DCGNX0HM2rBOn0xrzgXktIB6fLSJBTQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] + '@rolldown/binding-freebsd-x64@1.2.13': + resolution: {integrity: sha512-hoBWDZ4/K/mJKVMbsgUd1jfpA2DiOrJ54mpegObU9TBHBBrtX4FLIXJJQRDPZ/2Dn91GvPob+Z2hwKJzf4E5SQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + '@rolldown/binding-linux-arm-gnueabihf@1.2.12': resolution: {integrity: sha512-XcFu0R0xWnwzSf4IQgFH1rJIckPN1pLy2R+4r9IDB7Yfu/ys9cVqfa4pBrMHj7a3gl8mIR4nRNPg0e5IvEVs6g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] + '@rolldown/binding-linux-arm-gnueabihf@1.2.13': + resolution: {integrity: sha512-oF9fZu3vTWnTiVAkDFxU9PJLt1nh20K9RRpuHsR7ZnE2L7XookBbDBVLojCVSLGbvtSlxeUNnjAj6DbNsKyzbg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + '@rolldown/binding-linux-arm64-gnu@1.2.12': resolution: {integrity: sha512-260UrKgn8tz39ak+SMDOirKzr7V04M9dWPw5llW00SwBivCZoWcRBKV1d8cXnRkUmSZA3BdiUmBHWk7734Ulpw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3321,6 +3357,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-arm64-gnu@1.2.13': + resolution: {integrity: sha512-DTpb/+jMiqWMPgphn4ksW1zW+XLJ6dJJ9FMvnIk9I291LhCctMPhMYJrP5t9p6C9qa3KXadDdUEZHBaPh3kNxQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-arm64-musl@1.2.12': resolution: {integrity: sha512-5YK1I9SqDkbPgc1IA8BgDl34suqUS2q0KWnBrirm0E51YjOs6eo6dV6jbQfNE/argHRSvd0QUGgtpIoYx+WWpw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3328,6 +3371,13 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-arm64-musl@1.2.13': + resolution: {integrity: sha512-xU+Kvv9N2A3SY35zFh1FWWNjxbadE/BKeqnkXe7vScU4GZsw757BlVmDLITZEq8DPpk6m7uoDYkK7P+x/uU5Ow==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + '@rolldown/binding-linux-ppc64-gnu@1.2.12': resolution: {integrity: sha512-Rkcrmp7eFRg74yL5fXEU91JEWbdEPLevWwGtXpmhbjlD1StScbWTmO94Bhly+Mo+ketKYkdmM1vNUKeWSlx8cQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3335,6 +3385,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-ppc64-gnu@1.2.13': + resolution: {integrity: sha512-XMk/hnhh25oQ756Lclb1Q11h4ll0xC0Esa5w4Vzp+mAE2S3AGJgeM0SonrIgY8fHhjarb6hcoTuwoFG0VVP2ig==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.2.12': resolution: {integrity: sha512-qvK4DuAsQc2BSjlx+Xr+IzOIvvxbGZqxFwdWfG6F518Erj0GGISyQbJ6pIappnOxlNPzNHvo/L0BwB30GZ+zVw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3342,6 +3399,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.2.13': + resolution: {integrity: sha512-U1BoTHYmlywE2n3HUWjzZ+8EQsKr+OwpxYuDWaubx42tUL8QSL7nOqRz/NVHanibbFP3M1Rxuprz/wNcbMKjqw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.2.12': resolution: {integrity: sha512-Q9uLBO53Xd4QIq1WOycVQyPP1O4HhraEV2qqb3uTrnVw6QZih9duY4vNXOivL1xoUS1/z+W8eF4NMfl2a8Sdjw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3349,6 +3413,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.2.13': + resolution: {integrity: sha512-J4cm80Pc6wEwV5AZ42o62sIQgDk+Y7R2s646jIwuvO+4V46QB58N4vVuMPWCBaNgursXLpmUWJV//WQAkPvHBQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-musl@1.2.12': resolution: {integrity: sha512-3IBxWFMjbOZskDPKv8Lf9BCnahlKuHthWkYnyIxOH/QcJrFcS4EmcenthApkwr/5+nEqZlLzeYbxeMaX7A5u4g==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3356,24 +3427,49 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-x64-musl@1.2.13': + resolution: {integrity: sha512-W0euZS40U4V6JkmEnVCIX9mcsL6cbXQ4X8c2w+MMOIjFg68TXUW+u3RT+2e1t1pv9mg/EP3pDtK3POXdQ7Rxyw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + '@rolldown/binding-openharmony-arm64@1.2.12': resolution: {integrity: sha512-xtX61xg4LKPkPWilZU1ynKClz5Gj4bf74LML4r3eVLWumKnGjoEr1OSHQhMdbBDoYTi+yjrujvpZe2pUnqCrrA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] + '@rolldown/binding-openharmony-arm64@1.2.13': + resolution: {integrity: sha512-do/AF/4n9MRshia3a5aXoy8xM2c6mgfT6D7H/dY6my5z+hfCIR4ab7mk4IRj++nsEQpKy39kd0DQnDq+r692tw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + '@rolldown/binding-win32-arm64-msvc@1.2.12': resolution: {integrity: sha512-At7fPB6PCaIjzgIhEZFxuT+BBFqiQibJDT4d3PhiR3f4E7bbMZF4aKblbFfEM3sETRDd1YiQx/+U/g/B/ou5Ew==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] + '@rolldown/binding-win32-arm64-msvc@1.2.13': + resolution: {integrity: sha512-6FtUf2cJZobutJdxnGYX8z0vtbgqU0b2v8vfBhkXb9wp2MppMFtkunE+IaOntyi01rkIQoPW2GHABtfzsC0BRQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + '@rolldown/binding-win32-x64-msvc@1.2.12': resolution: {integrity: sha512-WIw2haVKwjuYdXkHaoC0mF8Le71TuCBxjrdKqLbJGctbBABj+ClfmNvtbOnzpq3RokNo5+V1qhtSzJyXorsklQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] + '@rolldown/binding-win32-x64-msvc@1.2.13': + resolution: {integrity: sha512-UKhFaZTeTcbKrb3iU82m17jVcPEAoqDkCN5MBqgPyZSwp/cQmib21crTS0DdH7T1B7wZRWEI89YQAOJMet5yhg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} @@ -3413,146 +3509,146 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.64.1': - resolution: {integrity: sha512-QRU7UpoS9hd8Ij5I6fCVBxZ0UpdfAbZ5y7BWG5STFGMoM9jGzUP464yYAa3CzZxvG+jBwq1kI8L07xx0ReAdGA==} + '@rollup/rollup-android-arm-eabi@4.64.5': + resolution: {integrity: sha512-MrfgRQSpD5hkkRg6XI16B6EDLb+6+xp8xje6bpdSwkYw+qxrBKbUVrRAQu9h82UT+QumSIVQ8HXsXjPd2dlhqw==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.64.1': - resolution: {integrity: sha512-ttQF6Rp4MrNy9/2AOPmHmMXbNE8kIlNPYoGC3ksid9tonleMQALfrhTFJiQxobBvXYKG5Wcc8VGcHWTHR0ik8w==} + '@rollup/rollup-android-arm64@4.64.5': + resolution: {integrity: sha512-+uu2p/R9Tzn8GpoQyX1pAo5dmKT1DhXevfaCzqzmPFhnLjHLWw7uWkaVGlxmhwYoRiYYhsGfRcD5cTBpL7rgSw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.64.1': - resolution: {integrity: sha512-MvzZ+qbBi5jrafURHsASUF1qW/58tOJFt/gFVJo2znQWrKX4CSf/Lt/qGONtoA4yHsNL5QzgdXMuITZxAs62Vg==} + '@rollup/rollup-darwin-arm64@4.64.5': + resolution: {integrity: sha512-17dys+YEmzwzzFVHQAVDONg5FALXY9kd99HFEpfk4gJVHYxoh5bGea3D4t1fXXnwkTcOe25wPyd6nWS0I8IdLQ==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.64.1': - resolution: {integrity: sha512-9uj1VBuiPK5ij/+g0mCK17X+V/4SbErvRQMXIQjZAtbl4VcUhv63RhPZsFSWHrCRkTd3FKDtaVTrtT0+8bIhhQ==} + '@rollup/rollup-darwin-x64@4.64.5': + resolution: {integrity: sha512-wg0zQEKkEvFZf1UaaX1UELOoPs//OSKUG7D+yITuqOsAvza7LvHTv5Wu4nmMfzNG7EYI2jp2PJC7Id6OETmsYQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.64.1': - resolution: {integrity: sha512-FCoXm836IqcXWhWPRkqlLx3Hjnv9S7c8tg5MFwsgHB3aFCz1JjUy6b1ssrxEjEbqaHpnvRmNjUUHxsXuU85NYA==} + '@rollup/rollup-freebsd-arm64@4.64.5': + resolution: {integrity: sha512-CoJmWcpEMuwin+TZ/ev/H9uDyF/uxUKQSWXdmIPn/UBx/uGV9+4ebMp0FwnlhWR9PE1AdzYsKf3bZevhif38+A==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.64.1': - resolution: {integrity: sha512-Xa6Oxo86Ilx1hq1vNb69541NOuUyhGEH3Sc0g7eGkfsfRblWh4hAa4Lj2GWwZyfUVYL+Z4xK3TxhwIuZ3fNPLg==} + '@rollup/rollup-freebsd-x64@4.64.5': + resolution: {integrity: sha512-PxZnLAaTUAL5xG0W2BXLeYPKrK2b3LIASV2/e/Kf7PZvSLI1iAQIm9B9aJD+YyFIT7hc6qaMV3+OOO35R28LfA==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.64.1': - resolution: {integrity: sha512-Nkw7cVMu1yrczpzr42Mh1BZ5Ai5A4Fsz2Je/frbwHmazpQTJzP+qo7pNjdxHrxVj56ivKTJihNoN90OD1hGxBA==} + '@rollup/rollup-linux-arm-gnueabihf@4.64.5': + resolution: {integrity: sha512-uPo3IvnONjhbFXwWgroBeFwOicuhT7ZwQrnzkzmOtBJzeQbkUJUE1SJDfDI31ijQ5+ZUIA6sPrdUMxTSnxUWAg==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.64.1': - resolution: {integrity: sha512-JONaLM9mZPXbSetxMzYG3496qoJuWvG2ERCTrrVptfw/Fwe4UzrQoEx/mYEeZCRv/Xz0RldOLFeqDfqmH75/Zg==} + '@rollup/rollup-linux-arm-musleabihf@4.64.5': + resolution: {integrity: sha512-ywI8Jyuc4LyHYTjC0mw4yA1ulvZBkHusdpWnoiEBsmBuHvSnt90btTBGCZ+s/2y+YNNfVAEKy33nPo5UI9zTmg==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.64.1': - resolution: {integrity: sha512-OfimHma+prmdoobHI3tfYud2enQ2LXYaMu+iMUQH7IjJkykJ6qUmAs1M/scdQaEKRWysiKwTctsDa2LXvaO0xw==} + '@rollup/rollup-linux-arm64-gnu@4.64.5': + resolution: {integrity: sha512-tmuXJoQ/3ovSr637aykZMdQteU/CB2APAz2CrvsbibuoHZi1BS1Db13cVViBdEARGwXCLn1DSJ8wsjoThLJPGA==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.64.1': - resolution: {integrity: sha512-X5fwh2HM8EHbgfFwpf4m2x2pG/AHdQ2aPDPk+JCDwV4DPeM8yxYmKG1vvm123JSc9gBSu8tu9NECA99wHPztsw==} + '@rollup/rollup-linux-arm64-musl@4.64.5': + resolution: {integrity: sha512-5FMjSYNcUOHx7oW8Qu9KB6jGPpvF/8sG7+BDHwU/Ihh1/6FMJ9ySmsFG4tJ1qbNRuP8OLzCBDso4sF0mQaLuFQ==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.64.1': - resolution: {integrity: sha512-8dp2TxKdjiX/4f7Da9gF7BR29hygxOQlHxKNa8qxJHoqZ13ytrogFTpMPhtVEFrgFu9MSOabAn006PeoygavjA==} + '@rollup/rollup-linux-loong64-gnu@4.64.5': + resolution: {integrity: sha512-K8ZJ+neLDbUkIrL8dqF/5LtuVCrKwo27kREgOlxjBEjlOXwHvDnHLU8Z/UKv/B49qi7e8hsSDOyoJwhwqhvX4w==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.64.1': - resolution: {integrity: sha512-YuYDpRSZnU9qLf6sqyhiBdMRCw5ImECGLNqRjM2hZrJIEwAckameWkRJ3SUnn0oxSewZIib/4iLwyEXj40QqQQ==} + '@rollup/rollup-linux-loong64-musl@4.64.5': + resolution: {integrity: sha512-NlVxsq7PFPv0DBKGuNWRDKixQYQCjM53zl04mxEcKMBmJbCBIUm1JdPfIWDRHyOOFzzYPmLQzfeEwh4716ayQg==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.64.1': - resolution: {integrity: sha512-gGj3v7YYkysy7IbfclMI4PDtHaa6YX4nU1D5NR1fyvXAGqM4TDk28ZWvrpOkkK92eoQRryAludWz6jNjsm77Qg==} + '@rollup/rollup-linux-ppc64-gnu@4.64.5': + resolution: {integrity: sha512-ARhRHJYs5eCFet5azfrHD97vOkD8OzNW2RSMlvo5CcBqXaTOLfp0OHDtUQh7/K5AL5fUYoFp2fgC9KDg4vVYMQ==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.64.1': - resolution: {integrity: sha512-DTZVwvS94FUYpP0CjCfz2iT0XTmBfQGc/arx9IdwUbDImpe9h8dWuMT/oPUvcGiwLKMQoNmuFBx3AVajm+FNjA==} + '@rollup/rollup-linux-ppc64-musl@4.64.5': + resolution: {integrity: sha512-atSgreM5C7jpxd9aEXN+6vJ5wTd05iYw+S3FiQpw7VsoEl8B90llbq35ARON+GOHj5QlVQEq2vOKWCHTob/BSQ==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.64.1': - resolution: {integrity: sha512-NWnyiq2moc8iEHGyTjIFadJTy8VCvCU/rUBfor+3l30JOQKAifpmKdxX4ZxRRPSPE/rLhFpLADdzNjS3Ldctdw==} + '@rollup/rollup-linux-riscv64-gnu@4.64.5': + resolution: {integrity: sha512-vmlmwBFGnjVWxSRoVabNkyYuscSmg52Pd0fM8jEbNT3Jmka4A6HcB84x4uAmuumznWfBVaxKOqU6jbEgomWKCA==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.64.1': - resolution: {integrity: sha512-yIz+7L37g7bVOGLaUQmGqiYADH262krL4dtf5zU6QGldPgOairLEgW1FTs5pP0UFkHq5uf2qxDttOFsVAX6kxg==} + '@rollup/rollup-linux-riscv64-musl@4.64.5': + resolution: {integrity: sha512-hhJrP6S9WkbsbcHgUkvCBS5Cn8IdsG8XjlLZyxjnv9+NdoYfbbZE4TWJYr8apdaj1M5t5Y1id2StnEslxpNFyA==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.64.1': - resolution: {integrity: sha512-sRK+GWovJZV6ijyV/k1Ft3FL5+4DscF5OYsJolTbhVTTLFxKOPVjS0wxUUHakvL0vRw/cbFxZNeZLfM/EzuQhA==} + '@rollup/rollup-linux-s390x-gnu@4.64.5': + resolution: {integrity: sha512-NNVCyN9pGrwFmQa4bf+Cnf5aVH3g6ZpnlOg1Cs/H9swIHT9bRixijfzUqyEIWm1WtiAuR1LJ+rJH6zpBm8kgQA==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.64.1': - resolution: {integrity: sha512-T2C0NXqqD063yJdm8UGdcoudBATDODdphEXWS7rEoh0jOITfoEBv7LHfRBYVsy+pI7wwxgScoZpkFiQOf40ryQ==} + '@rollup/rollup-linux-x64-gnu@4.64.5': + resolution: {integrity: sha512-dR9nd6OKnvSS60Ifz/L7Mj5zzYyoqyRn2NwTuaOONKaa3xsVGXyp8YusMbvFyEOR94DxnwgcbgsFqkHd29ZSzQ==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.64.1': - resolution: {integrity: sha512-05wl8uRZMkcobB6YZrzskr2SiM0VOdzlFw3bAxOjKKTt3M6o3O0X/hE/8xk15u8oQY17xUCdTKcNMMg45ZAFog==} + '@rollup/rollup-linux-x64-musl@4.64.5': + resolution: {integrity: sha512-1tzsMjaqhsh3bAO6SJiJqh8hIr9sSPRd+i2vPPxJHod8/XYnf9TEnK0z/u3r1z1AkI347X0KbRSg9dWcxeGahw==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.64.1': - resolution: {integrity: sha512-NoRZK1VclOgn9x3b9vPJ3sTxwvQ/F+Hf93xurRKSFJKiwNZyQZnLxVpqlCejhDvesMLMF8VNN+Y4jHTFddV/Xg==} + '@rollup/rollup-openbsd-x64@4.64.5': + resolution: {integrity: sha512-01mWMQblKoXXsmk28KXtpbA96w7g/aOWUoV3AC16fdHdqkykGalqyyM+5u8M7uP5/MEMiiPv69Hv7iv/hEH/dA==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.64.1': - resolution: {integrity: sha512-SDkX4OkZBePUPf0/XsXVJLwS+O61CmkDKuIyk5CeWddK3vkE8AZjmWK+p1ILRez4wnbS5rTK+U9YmcbRyx2dHw==} + '@rollup/rollup-openharmony-arm64@4.64.5': + resolution: {integrity: sha512-trdnMPb/DNm4V/CgsaoGgr90HfQQ071wfK0KoIs4YpLvjBgVQGXhGabg2Z6nK4EcYNilrb9ZZPcsP6+zpJIdxQ==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.64.1': - resolution: {integrity: sha512-JQ7el/Plr3juYFxIVu9YXDPNl57XR2L8WIc87JX9wj0L3goV8fXQPQXb3DaHVXq61X/WCGWsTCQsQHo6/Mz5UQ==} + '@rollup/rollup-win32-arm64-msvc@4.64.5': + resolution: {integrity: sha512-x2LxZlfdfsw99T6/qb9EqE/Qi84JWzibjyOJyhJsgFJy6CafaTiqIXCCnslCGrV5XWNh7fwrS3FbRENcuKnooA==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.64.1': - resolution: {integrity: sha512-oZSlQ2H3ZDOz3ce1jEyuOZKuD0tPY/D2cKGMcMl0jhHQauBvkHHKAGR1OeRiMluvu3itzLRU2xCTUZptLayObA==} + '@rollup/rollup-win32-ia32-msvc@4.64.5': + resolution: {integrity: sha512-/Qd/9aDQIo0+jmItgBmPIs8195YVbDxRRApn47GyufgbutCDOh7eP5vSKKlI4QNFeaI+wKQAkSMsPnF3EuMpaA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.64.1': - resolution: {integrity: sha512-Do2m3jUeVAvUDpee/yVZYRqhO8Ecx4x5sX3EVGalqLx+OxecLDGx3sIwPEm1Nq+MFK2FV3pgdpwWP4624b85Og==} + '@rollup/rollup-win32-x64-gnu@4.64.5': + resolution: {integrity: sha512-ngUJ/XvOWrqbd2IMsfXfh2xXFLTP3sY7sCKvxbGvYdBZ1KmXFd3ewDZ9n3/GNzAUgzRuhLT/UvJRivbNoAQRBw==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.64.1': - resolution: {integrity: sha512-KpxCwRn1Qh3tmBHAqIAF4HtUCVKqZd0w57TsItWblx3QVeJLtXaSgeBFAj1WAvBSpBo+Mh9iZCjj6YW/HaBVMw==} + '@rollup/rollup-win32-x64-msvc@4.64.5': + resolution: {integrity: sha512-IhV6ew/DuzUWwHaYmlh7MrPCV3lKFUq/amTEwysi4r/mwNPAEfAMh5dYWeTSPTeMy2pFHGMEWYtPkHzfX3tG5A==} cpu: [x64] os: [win32] - '@rollup/wasm-node@4.64.1': - resolution: {integrity: sha512-NX7sXK/FT9RBgFxkMKB3jFcc3LCcUL/44PMJ8BBE0t0ljgXih0tZrUPUdZEN/JnN1N7i5axbGQtt5iPwlFJDQw==} + '@rollup/wasm-node@4.64.5': + resolution: {integrity: sha512-kN33cPixKuDMgrYkRnkAW7iwiDWzRhNUgVY+IpcniQNXuIvDAAv0cFgZsaLEFP1z8eqVGhKG13dy5hFN3yBy+g==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -3777,39 +3873,39 @@ packages: '@types/yarnpkg__lockfile@1.1.9': resolution: {integrity: sha512-GD4Fk15UoP5NLCNor51YdfL9MSdldKCqOC9EssrRw3HVfar9wUZ5y8Lfnp+qVD6hIinLr8ygklDYnmlnlQo12Q==} - '@typescript-eslint/eslint-plugin@8.71.1': - resolution: {integrity: sha512-nNlBf6HuotqMgZvSkWD5hNdemiBIxQ2NmrlgfcUIeZRs+BbakjscCQRq/Hb74EFVnFiSWWdL12JruqwBy3ERDw==} + '@typescript-eslint/eslint-plugin@8.71.2': + resolution: {integrity: sha512-K72/pvT7qpm8q3k8G5u93NCSN1RcLxX5h7Gw0bQpbMXviBHeY6Nx1WEwmk9wP+eKTSQ8ecxvcgt/ZX/rB938xQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.71.1 + '@typescript-eslint/parser': ^8.71.2 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.71.1': - resolution: {integrity: sha512-oM/5sAqz/l1v/zYK1qTOPrn2+JIrBGC1V6uNYucRO5gh6eT9vWJ/RhPbGE59byvZEUQ4VP6XkLBaS5Jti5jpvw==} + '@typescript-eslint/parser@8.71.2': + resolution: {integrity: sha512-aTtmZjp/x3gsGHkDs04/1I8kNogBJkpQaeGaN0PfiG43NzDEmW2n+OP5im9wfsvyX0yP1UZWBrAGtDBfH9jEVw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.71.1': - resolution: {integrity: sha512-Oijc9RUsohHjncg6iGi7gCtjnEjYt9FWv9u6ygK8uKcHK5eLjLAkqERQ9BaytbpceOFdk6kifPCS/zAZE+A99g==} + '@typescript-eslint/project-service@8.71.2': + resolution: {integrity: sha512-Pd68GsLVh5ZXlcEccFPdhSOvtHZ/2WU0XsA8zmXOS3F158lVlcTLhfQ6qvtL1RzbMie0Kp8xtbVwAg4nejKPHw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.71.1': - resolution: {integrity: sha512-1YUDZXdTnXLlob03SFHBipdyMBsDVm7zoSz0ytTJ39dk5J1TgsTK03VlR/dLXG/RLLUrPcYbD4rp23BmHxHP0w==} + '@typescript-eslint/scope-manager@8.71.2': + resolution: {integrity: sha512-YF4wgg5iUX5Obywoac27B56FhozMNFhdJSbh11H5GBAwmBtfyRhmgTQqW9tRNNmHDvsZ2CX6UGzoz+YfYn2Leg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.71.1': - resolution: {integrity: sha512-oTvkml5SxXhgg+WWKhod5qWQICDXtOB+/Hi9VdPKFAANJ2b7YOgMffgvzXuqog7R6A/JtrzRf128dsxummyWhg==} + '@typescript-eslint/tsconfig-utils@8.71.2': + resolution: {integrity: sha512-jz49TAWokm/7yWD9/o837nYax9DyALxIPOImdImvVzo6canBCZYzin8zJyqNR5k1j9K1DE0bVvr0XYB+99uAdg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.71.1': - resolution: {integrity: sha512-kH3t3jZCYv2PZSBEWPKTariLrCaoF1CLoPitYFBJOhAGEwWnSRAtGEifrfrpBa4K9JlwWNZotgA5w3/wLSk/FQ==} + '@typescript-eslint/type-utils@8.71.2': + resolution: {integrity: sha512-cC8UaalCViJkb3rH/xLIvidEwoFRtMZMUqDjjJMGEKaTFwYRHYBcoczlEGHuvkHEO8svRDrgZ0yQgOArFmwang==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -3819,21 +3915,25 @@ packages: resolution: {integrity: sha512-ybYnPTUwg3VQQOFEiBPLs8Jxl1ry2vXdn1kVKguomBbvxpetdu3MKTNDqFNUrlG8ylP9MpZosmXMFYlGQHk1oQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.71.1': - resolution: {integrity: sha512-pSKSEK1JJpHs6KiKVtABCE4iJK5d7FLFzDXQNBQ2oRY7LEd3UwOt3TZemTgu9syTIf56dJWlTn/pdmrO9oKUXQ==} + '@typescript-eslint/types@8.71.2': + resolution: {integrity: sha512-y5Ukl3oVp7e/VGxqIoEXoeb/Roj71PAJ4WG/N/RGj+eeDvKRLM15kGr9MijLbN0i03S52zxu31Z98E5gWChJKw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.71.2': + resolution: {integrity: sha512-DgNOEsl4pdYzwSL+N/Cl33tX1Hlw3FvId73LnKXfq7jnrF2viOEn7X+P7RBkkSWCVm92gnWd28GIC5vJuLREeA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.71.1': - resolution: {integrity: sha512-CBjT6gfAz3DW2j9Q4moFnqt208Aq+506sVGXfpRcyAeqn0EpayL0mjdWoCO2t3RC7GewNrFxdeehuEaPg6DMzQ==} + '@typescript-eslint/utils@8.71.2': + resolution: {integrity: sha512-RyKa1G1M9rKHDhrk+HJtiF1MvLD5Ux2JW3TSkzw+02pRALdpJb+QzG1Y5em+LvCgzGwgg8H7mBRFKljNz7ImPw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.71.1': - resolution: {integrity: sha512-0GxiUGqMU0qXJt58cBsiG3DP8lUmBaFo2vChtUX+CT7PnR3v/VGLLrzVP4K9r1lNiZXjHYefMBbPunplr09v6w==} + '@typescript-eslint/visitor-keys@8.71.2': + resolution: {integrity: sha512-zozlN0UA32bSG2zkKAgQyRYSbEISVoyU6vvkKYo2aSny74D8Jh4e+POkJ6Lk0dlezZi5x7TtD+88Xb06IB8nhg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@verdaccio/auth@8.1.5': @@ -3917,11 +4017,11 @@ packages: peerDependencies: vite: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@vitest/coverage-v8@5.0.3': - resolution: {integrity: sha512-+klsyz7BvT1vCU28Zkfzms1Ia78XD0V41U3FUtRaa3S+vOr/EXvK1O6BvVD7l1RzEjm6SONR2aybOvDDf9u0mQ==} + '@vitest/coverage-v8@5.0.4': + resolution: {integrity: sha512-P5YcQY8Y6RmoE9xRXI38rT8pssbcubEzqtYTM2XQoxOXMDn04nRaTI1SM8qCl9/NfW3ag9GlzdSXu7IwO5Ft8A==} peerDependencies: - '@vitest/browser': 5.0.3 - vitest: 5.0.3 + '@vitest/browser': 5.0.4 + vitest: 5.0.4 peerDependenciesMeta: '@vitest/browser': optional: true @@ -3934,10 +4034,10 @@ packages: resolution: {integrity: sha512-gUsfXZJbzPamoIY5TvHFiMMoXESBrUMo+xqaj+rYrWI69+EnvRlYBlP96ZnHPY4vX8kyUpgAnFUCg5wZG/HkDQ==} engines: {node: '>=22'} - '@vitest/mocker@5.0.3': - resolution: {integrity: sha512-T8sWAIbkSyAjkwTcaEc3Iu0o9A27X1/kdXrizhZkGuSKScRQtRzclfAMpOTcGdXCsqxeWlpGy3XjqaW8CpLORg==} + '@vitest/mocker@5.0.4': + resolution: {integrity: sha512-tqAlrYWce4iUxhr3ncNohejtCTOcHeE8XWrSNZY3OhPoDn01yeGv+gnaBy64ATp7o6pb03eIbBAjzmibpc9vIQ==} peerDependencies: - msw: ^2.4.9 + msw: ^2.4.9 || ^3.0.0 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: msw: @@ -3945,8 +4045,8 @@ packages: vite: optional: true - '@vitest/spy@5.0.3': - resolution: {integrity: sha512-XhFysQTB8AZ+P4gMi+Lpo99vg2AZi0qKpaB9yXQl37+CaMEAPO3iH/wGVnSyL5MPERiLezpqTVtrR6UZH5GCXg==} + '@vitest/spy@5.0.4': + resolution: {integrity: sha512-MZKk/gSkm2q+ICobMxCpH1mA+cCAWm8WV7UhxlqGjq/sJ3AGc1BqFOs5CRVXxH78wQtme9q/NAAgBquj4AcyMw==} '@webassemblyjs/ast@1.14.1': resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} @@ -4084,6 +4184,72 @@ packages: os: [win32] deprecated: yuku-codegen is pure JavaScript since 0.14 + '@yuku-core/binding-android-arm64@0.19.0': + resolution: {integrity: sha512-wdL2XmTiZixAOaHk9Z0JJZ8u9Qm8d333Zjpc6gaxXFX+UR5BlsfxZ7a2+2Rm71pamppsPYGUGFq2oVLbh6DISw==} + cpu: [arm64] + os: [android] + + '@yuku-core/binding-darwin-arm64@0.19.0': + resolution: {integrity: sha512-7sNJa6XJhyetnTy64jw3NEi4YgUcezHk1G5GH9FSvXAuC8wIlbaOwT9lgq5qo5sspjrZJQlBR1TWflP49uRpMw==} + cpu: [arm64] + os: [darwin] + + '@yuku-core/binding-darwin-x64@0.19.0': + resolution: {integrity: sha512-pTC7dYEc59isdyizc3nsuyFNBu2LU5wMYZ1be6UMr59PY/AJNtO1aBLWV0MgL/z7C1nv/2sX4TNjGgKLoeevJw==} + cpu: [x64] + os: [darwin] + + '@yuku-core/binding-freebsd-x64@0.19.0': + resolution: {integrity: sha512-xrZjF6XOEwyLOiDIfrwDdRCS6ghxcJeirNC1KivQhVcUwlRonaU79S3/Uiyx3lBylPnT8qKJ3/aMT+H52nGTJQ==} + cpu: [x64] + os: [freebsd] + + '@yuku-core/binding-linux-arm-gnu@0.19.0': + resolution: {integrity: sha512-0OyIH53C0I1CbADHn9FSdCfX5qbpeLwJhmOVhonFJNYheybOnkSJ50qGMfTJIb8y5zrwqvLs7FVBvz6Fk8maZg==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@yuku-core/binding-linux-arm-musl@0.19.0': + resolution: {integrity: sha512-z/iPfkCOCSXE34VXNt0uP1ORSW+4mEa9b5CiJcWZeqZH08g49bFU/jRM2T04f+Wpw5mJ6HIzNBiojxeAbrHjeg==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@yuku-core/binding-linux-arm64-gnu@0.19.0': + resolution: {integrity: sha512-jLNTi+gzaRwBJ+gwhCJ+rDb5dmx/8hEBx93UWd7hjMSqPTL1D1wvVSvXVAldV5kALvju7b0/m51EHEhs4+I1fA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@yuku-core/binding-linux-arm64-musl@0.19.0': + resolution: {integrity: sha512-YwyPIdW/rN2Fmv0MTFWi47FaB3F9g+2b+sJISyAw83Yd60RWH4T3Nx6XkAHHVN+uKJNBAd6So7/BVihSiFYvuQ==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@yuku-core/binding-linux-x64-gnu@0.19.0': + resolution: {integrity: sha512-/vskaAXVX3ESR43FiTdfiYS7z1b9uoQJwVQ/0RgUHgN2sWoAyCZs+aX4CgU7eKGIHTVfp9VFwv+c+2XchYiEtQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@yuku-core/binding-linux-x64-musl@0.19.0': + resolution: {integrity: sha512-FuXL5igeSKib9Rye02TdH+D6SQezTyGxIATMu1Qsn/QywrzwpGl35OLpS2C1x5vpGLeVE2XgiLd5mVPFHmIglQ==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@yuku-core/binding-win32-arm64@0.19.0': + resolution: {integrity: sha512-YuJAe7zEKT1Xa7LuHlhGJpPnYQeVtvo0rZvNjJRqkH0hQGOw4C8QeP30Tg5VKGzZfo2x8CjhjEhKt4TmLwfmdg==} + cpu: [arm64] + os: [win32] + + '@yuku-core/binding-win32-x64@0.19.0': + resolution: {integrity: sha512-o8iY/mXwlRkedp0LNTr4+TEfXTPQwoNZmv6k+1WIAd1ZXEn8xJJTBCtB0osaVvdZo/x/cNmV16UrWrrGpM5Mvw==} + cpu: [x64] + os: [win32] + '@yuku-parser/binding-android-arm64@0.10.2': resolution: {integrity: sha512-2VPBU9fRGRAQ2xPAvghnec3oou5Nrxm2Bezhf+13UMspAxQSkF/32r+ySKXSwIPA5/RivumDJDxAxc301Sgicw==} cpu: [arm64] @@ -4165,6 +4331,9 @@ packages: '@yuku-toolchain/types@0.10.2': resolution: {integrity: sha512-sSeo4SSSToiS+sSD+bwn/s94EEcaLJ7tG5LCp8gFYC1G5VzxzX7fqB6m9RU1yMD8KTpu6zdU/I1NlQf8hVBJ9Q==} + '@yuku-toolchain/types@0.19.0': + resolution: {integrity: sha512-tFkNbsP4WXX9UMUC5syJGdK9dPMLK0PPaIuXCcCYH75sZ8MrebfBZ2XvCILRTw8AgLivSSCfDa4R67iYBDa4Kg==} + JSONStream@1.3.5: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} hasBin: true @@ -4456,8 +4625,8 @@ packages: bcryptjs@2.4.3: resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==} - beasties@0.5.4: - resolution: {integrity: sha512-8/lOOjT+PElYCnaUbmhgd3Uad5R1VTQ4Wg0k4rK8bX04m5WEqHNmnlLy3Q/lJ7dk25XA+72gayzc/skTfKKpcA==} + beasties@0.5.5: + resolution: {integrity: sha512-4mUqdlIqPmHlX5qwkGmunWnhi406XcT5AfmwltoiDCToyGP2pSxS9ClfURL14IRwPYHq/JAIrtjNptbpSvUTPA==} engines: {node: '>=20.19.0'} before-after-hook@4.0.0: @@ -4626,8 +4795,8 @@ packages: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} - chromium-bidi@17.0.2: - resolution: {integrity: sha512-5v9GQFhTktFvotn/OFNJBmKLKRAb6n9r0bVCwf7sHgWc3/JryK0bj1nn93L3pHFrfgcsu6Be6EWsDi+1XHTGDg==} + chromium-bidi@157.0.8090-0: + resolution: {integrity: sha512-KJw7IQgqXwxpJgJlEIPg5mr2ZoqA+jkTRtc5EABI7sUJ3bu3cpI7NuEBoj4Gn1AsF78CaT9So5WQWspK3/wYag==} engines: {node: '>=20.19.0 <22.0.0 || >=22.12.0'} peerDependencies: devtools-protocol: '*' @@ -4750,6 +4919,10 @@ packages: resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} engines: {node: '>=18'} + content-disposition@2.0.1: + resolution: {integrity: sha512-e+H0ZXHSWYrENhQzw1LPuP4oF5MzVKmDU6d3hxlvaPEYLLg62MxtQNPRx4SYSuYJSBUgnQIG4HIN2tEtNv7Dog==} + engines: {node: '>=18'} + content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} @@ -4976,8 +5149,8 @@ packages: engines: {node: '>= 0.8.0'} hasBin: true - devtools-protocol@0.0.1687809: - resolution: {integrity: sha512-t7kSb+UKYdyxcmqy98U2P86ne6rCve3DIJ4+lp54i/hhClgFuG35JrLj23rO14Jw3sWDsp7i+22QhNU0+/qk8g==} + devtools-protocol@0.0.1696802: + resolution: {integrity: sha512-FO5/SENfvc2K8wRnWQflKcwuoTH4dBkXCWTQ9ebIWtuX8JM5+ZvCotaEmkfh21pO7TvIKGTM3hG4xFiq9WTwmg==} di@0.0.1: resolution: {integrity: sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==} @@ -5322,6 +5495,10 @@ packages: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} + express@5.3.0: + resolution: {integrity: sha512-qCqy1xSoaugxOD4IVHb1ZWdkvCF2W3aE2okKouWj8VwJ+ztskSiXoBnCSJqfKT+cVPJhuJqe9YLbY425+Zh00g==} + engines: {node: '>= 18'} + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -6371,8 +6548,8 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - listr2@11.1.1: - resolution: {integrity: sha512-zArGFXg2/nhA1vYBz789VpwzMQQXkGZiRxeguxFCsDrg4S+LOR22v4oQlSdTN7dR14XgOW+pW33UfvKf+i8nrQ==} + listr2@11.2.0: + resolution: {integrity: sha512-+H/hEo9EA7tyLY0ZihpDg76jHWolc0nCjbjnXFguSm4Epk+WYtL1w1tYs1kjEo229NmhgLmUrncyn81K1vBoRw==} engines: {node: '>=22.13.0'} lmdb@3.5.7: @@ -7181,12 +7358,12 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - puppeteer-core@25.12.0: - resolution: {integrity: sha512-z6LQUt5SH7jwGtGA+nMtJuEjZIsqPiwQ+EFHCYuVDQrJpvifNmmGuyDvTzAKPyFzihxgHc5f3aMzu2kn8Ps37A==} + puppeteer-core@25.13.0: + resolution: {integrity: sha512-cyBS0OEx3e9NS53B5F6+UazXtR7f9Tw0cR1/FbPW59/hV6JPZbkIiMnxK2543IkFp3rsGlLn1iPDLF77TJsJsA==} engines: {node: '>=22.12.0'} - puppeteer@25.12.0: - resolution: {integrity: sha512-agM9cYcxbvmU17w9qtF17s7/Vv7Dhbyig6AWwIgvQQLR2dKZdPqNvRPanac7xH4iMPcNYOCfyCkwqCnR4nVOcA==} + puppeteer@25.13.0: + resolution: {integrity: sha512-vB4KLXTT5QqlikcOQ/xV0RY18bBVtNyLUTfqJ9mW+penHyoM+5DmANYuDCI4jgBtiL0eD9I5ZFSafW6/a6Trpg==} engines: {node: '>=22.12.0'} hasBin: true @@ -7398,11 +7575,38 @@ packages: vue-tsc: optional: true + rolldown-plugin-dts@0.28.8: + resolution: {integrity: sha512-FVhfqxorCWcc20BVT5eVRfRjzLLl6mgzjcMR4gSBf0K4oQMXT0qoHhhzfXy0L7y83fQy7Ug5ZDNk90xM3/LiCQ==} + engines: {node: ^22.18.0 || ^24.11.0 || >=26.0.0} + peerDependencies: + '@typescript/native-preview': '*' + '@volar/typescript': ~2.4.0 + '@vue/language-core': ~3.2.0 || ~3.3.0 + rolldown: ^1.2.0 + typescript: ^5.0.0 || ^6.0.0 || ~7.0.0 + vue-tsc: ~3.2.0 || ~3.3.0 + peerDependenciesMeta: + '@typescript/native-preview': + optional: true + '@volar/typescript': + optional: true + '@vue/language-core': + optional: true + typescript: + optional: true + vue-tsc: + optional: true + rolldown@1.2.12: resolution: {integrity: sha512-8wafseiaG80xmXSfqidUNqZcylTlhmPZZt+za2m+js2sFZ8dTNlhIOV2WcbIPx2hgwPBJpEUGFAMZ9bgBBLTSQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + rolldown@1.2.13: + resolution: {integrity: sha512-/5apOkwWxtACcQtZ5WlrAsKS4JwXVThQPJZ3RqIruRY9UG9M8e0VlXN068xum/JRKA4aIUoJ13ghe/kGCvidiQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rollup-plugin-dts@6.5.1: resolution: {integrity: sha512-jODTXp3H7MK/Ur/ErtsrQ0G1GvaCmc3du+y5pNrdBMf6d7HlL2Nd/N6TkEr+f75CkUj01zEoEd7y2elH0eHi1Q==} engines: {node: '>=20'} @@ -7424,8 +7628,8 @@ packages: '@types/node': optional: true - rollup@4.64.1: - resolution: {integrity: sha512-7s4V+3J8ux75WNj9qwSJnrWmlCmZ2YHr2fojtHy5RiIMvhJv6DGe7HKKz7L6G1sq1Eg1fLC8SjYtAtDis1F4CQ==} + rollup@4.64.5: + resolution: {integrity: sha512-EAP5ZHcz2ijbgCWwPkpI7zh6bfsri2Ez5FtCy2dCp1k62duXzfG7DLGGh7RU2QQXWwavT+u4qpvDF/TWOiiGTw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -8261,8 +8465,8 @@ packages: verror@1.10.0: resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} - vite@8.3.3: - resolution: {integrity: sha512-cTAldKPImjg6c+gk48U19POPn3GCBzZwpdsN8ZMEEcbpes+6/wvfqUd0C2y3qYY4wsj8PwgFwrZ/1jBPVttMSg==} + vite@8.3.4: + resolution: {integrity: sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -8304,20 +8508,20 @@ packages: yaml: optional: true - vitest@5.0.3: - resolution: {integrity: sha512-xMw97S3rjdtj5dkVat7jCsqWBpvchs3RlpQctUqwJD0KkERk40vz2fJ77lDwW/Vzh/pk18eItYAzkodhSes3jQ==} + vitest@5.0.4: + resolution: {integrity: sha512-z0WxZRV2Sg48wF0FSgMq3TFG8JS38/Qr96vZVZdX6+Em9raQTvnXQvdTFJe2m3rfyJnEHeHQ/snceIdi8D1pVg==} engines: {node: ^22.12.0 || ^24.0.0 || >=26.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 5.0.3 - '@vitest/browser-preview': 5.0.3 + '@vitest/browser-playwright': 5.0.4 + '@vitest/browser-preview': 5.0.4 '@vitest/browser-webdriverio': ^5.0.0-beta.5 || >=5.0.0 - '@vitest/coverage-istanbul': 5.0.3 - '@vitest/coverage-v8': 5.0.3 - '@vitest/ui': 5.0.3 + '@vitest/coverage-istanbul': 5.0.4 + '@vitest/coverage-v8': 5.0.4 + '@vitest/ui': 5.0.4 happy-dom: '*' jsdom: '*' vite: ^6.4.0 || ^7.0.0 || ^8.0.0 @@ -8367,8 +8571,8 @@ packages: web-vitals@4.2.4: resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} - webdriver-bidi-protocol@0.4.3: - resolution: {integrity: sha512-uuN0goWfxP22B7J/uAgBpOYNPttC+XVseYE+rSY5+rQ+YBeVz/VORw8WbmLVcqW78zNg5A4qnjNXYUWR3il2ig==} + webdriver-bidi-protocol@1.0.1: + resolution: {integrity: sha512-WXWs/aXF2a6Al1Z2/V/7Gp2oPZOAAmHjJOTmv4KCXRJ122IMj3tSSMc6a4q3K4QOmhQbse/Ahr+oTVJOU2dUiw==} webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -8607,18 +8811,34 @@ packages: yuku-ast@0.10.2: resolution: {integrity: sha512-UnG9mA6giglCvSErft2/40TVFX750Sj1xgwddPLpG7J7rlr/P1wPADg9G2RK+d/1tNLtRVoLdMMOMVBB9561TQ==} + yuku-ast@0.19.0: + resolution: {integrity: sha512-PyCsiScaelhxBGzL8dyeJkLqvRZycoh78R31Vrt/WqYrm0hMFoKwIw/X7Dx5mBKLWAMlV9I9HEyBOHnj2gZVyw==} + engines: {node: '>=14.18.0'} + yuku-codegen@0.10.2: resolution: {integrity: sha512-hentl2dtrF6cPjiAirtkfxfFZBA6Hdm61UqRJ7cA0qrlDNMk9PZGOjw5w1mx3E0hu/6pHcJF4dJW+D0SXHPZOA==} + yuku-codegen@0.19.0: + resolution: {integrity: sha512-uymAKHjDuaP4BEpkXC/BSLz4DUEF5oArZ5AuD3888nb2miChjWSgpPdojEJxm3pjpXkgUaCRJQyNAbnMN33wHg==} + engines: {node: '>=14.18.0'} + + yuku-core@0.19.0: + resolution: {integrity: sha512-kYK9e1XdfirNhkipzW0wmMcSWcVF/CWnuugodfVYRCUwvoBefweL9HzB96OiKEhsx78V5WbUxbJqlizMX869Qg==} + engines: {node: '>=14.18.0'} + yuku-parser@0.10.2: resolution: {integrity: sha512-CgaU0/PPjCAIEZ3WQroosOxTY3eeKldAN3h+vk8pMNz4+jl1CZzBR4pW+K/rRPF112VooCL5FdjJoiMNjDrL2A==} - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + yuku-parser@0.19.0: + resolution: {integrity: sha512-XrBh9ZiQK5mJVRxZBAvD6LwRyAYrK3MFtH3+onyuxFL5hFD44EC3QOmIC1FjTj6H2MMwq46/NAI+NZxLZPZgxg==} + engines: {node: '>=14.18.0'} zod@4.6.5: resolution: {integrity: sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==} + zod@4.6.7: + resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==} + zone.js@0.16.3: resolution: {integrity: sha512-ihXL9+vhYyEhXz4TDNpHeAOZN9FVrbog0Il64OIEI28UP/n5AaI6gsccRuOHBfx+206agzyoK527bYIO0Foy6A==} @@ -10584,11 +10804,11 @@ snapshots: '@leichtgewicht/ip-codec@2.0.5': {} - '@listr2/prompt-adapter-inquirer@4.2.7(@inquirer/prompts@8.7.3(@types/node@22.20.5))(@types/node@22.20.5)(listr2@11.1.1)': + '@listr2/prompt-adapter-inquirer@4.3.1(@inquirer/prompts@8.7.3(@types/node@22.20.5))(@types/node@22.20.5)(listr2@11.2.0)': dependencies: '@inquirer/prompts': 8.7.3(@types/node@22.20.5) '@inquirer/type': 4.2.0(@types/node@22.20.5) - listr2: 11.1.1 + listr2: 11.2.0 transitivePeerDependencies: - '@types/node' @@ -10615,12 +10835,12 @@ snapshots: '@modelcontextprotocol/core@2.3.1': dependencies: - zod: 4.6.5 + zod: 4.6.7 '@modelcontextprotocol/server@2.3.1': dependencies: '@modelcontextprotocol/core': 2.3.1 - zod: 4.6.5 + zod: 4.6.7 '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4': optional: true @@ -11119,7 +11339,7 @@ snapshots: '@protobufjs/utf8@1.1.2': {} - '@puppeteer/browsers@3.2.3': + '@puppeteer/browsers@3.2.4': dependencies: modern-tar: 0.8.5 yargs: 18.2.0 @@ -11127,53 +11347,98 @@ snapshots: '@rolldown/binding-android-arm-eabi@1.2.12': optional: true + '@rolldown/binding-android-arm-eabi@1.2.13': + optional: true + '@rolldown/binding-android-arm64@1.2.12': optional: true + '@rolldown/binding-android-arm64@1.2.13': + optional: true + '@rolldown/binding-darwin-arm64@1.2.12': optional: true + '@rolldown/binding-darwin-arm64@1.2.13': + optional: true + '@rolldown/binding-darwin-x64@1.2.12': optional: true + '@rolldown/binding-darwin-x64@1.2.13': + optional: true + '@rolldown/binding-freebsd-x64@1.2.12': optional: true + '@rolldown/binding-freebsd-x64@1.2.13': + optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.2.12': optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.2.13': + optional: true + '@rolldown/binding-linux-arm64-gnu@1.2.12': optional: true + '@rolldown/binding-linux-arm64-gnu@1.2.13': + optional: true + '@rolldown/binding-linux-arm64-musl@1.2.12': optional: true + '@rolldown/binding-linux-arm64-musl@1.2.13': + optional: true + '@rolldown/binding-linux-ppc64-gnu@1.2.12': optional: true + '@rolldown/binding-linux-ppc64-gnu@1.2.13': + optional: true + '@rolldown/binding-linux-s390x-gnu@1.2.12': optional: true + '@rolldown/binding-linux-s390x-gnu@1.2.13': + optional: true + '@rolldown/binding-linux-x64-gnu@1.2.12': optional: true + '@rolldown/binding-linux-x64-gnu@1.2.13': + optional: true + '@rolldown/binding-linux-x64-musl@1.2.12': optional: true + '@rolldown/binding-linux-x64-musl@1.2.13': + optional: true + '@rolldown/binding-openharmony-arm64@1.2.12': optional: true + '@rolldown/binding-openharmony-arm64@1.2.13': + optional: true + '@rolldown/binding-win32-arm64-msvc@1.2.12': optional: true + '@rolldown/binding-win32-arm64-msvc@1.2.13': + optional: true + '@rolldown/binding-win32-x64-msvc@1.2.12': optional: true + '@rolldown/binding-win32-x64-msvc@1.2.13': + optional: true + '@rolldown/pluginutils@1.0.1': {} - '@rollup/plugin-commonjs@29.0.3(rollup@4.64.1)': + '@rollup/plugin-commonjs@29.0.3(rollup@4.64.5)': dependencies: - '@rollup/pluginutils': 5.4.0(rollup@4.64.1) + '@rollup/pluginutils': 5.4.0(rollup@4.64.5) commondir: 1.0.1 estree-walker: 2.0.2 fdir: 6.5.0(picomatch@4.0.7) @@ -11181,108 +11446,108 @@ snapshots: magic-string: 0.30.21 picomatch: 4.0.7 optionalDependencies: - rollup: 4.64.1 + rollup: 4.64.5 - '@rollup/plugin-json@6.1.0(rollup@4.64.1)': + '@rollup/plugin-json@6.1.0(rollup@4.64.5)': dependencies: - '@rollup/pluginutils': 5.4.0(rollup@4.64.1) + '@rollup/pluginutils': 5.4.0(rollup@4.64.5) optionalDependencies: - rollup: 4.64.1 + rollup: 4.64.5 - '@rollup/plugin-node-resolve@16.0.3(rollup@4.64.1)': + '@rollup/plugin-node-resolve@16.0.3(rollup@4.64.5)': dependencies: - '@rollup/pluginutils': 5.4.0(rollup@4.64.1) + '@rollup/pluginutils': 5.4.0(rollup@4.64.5) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.13 optionalDependencies: - rollup: 4.64.1 + rollup: 4.64.5 - '@rollup/pluginutils@5.4.0(rollup@4.64.1)': + '@rollup/pluginutils@5.4.0(rollup@4.64.5)': dependencies: '@types/estree': 1.0.9 estree-walker: 2.0.2 picomatch: 4.0.7 optionalDependencies: - rollup: 4.64.1 + rollup: 4.64.5 - '@rollup/rollup-android-arm-eabi@4.64.1': + '@rollup/rollup-android-arm-eabi@4.64.5': optional: true - '@rollup/rollup-android-arm64@4.64.1': + '@rollup/rollup-android-arm64@4.64.5': optional: true - '@rollup/rollup-darwin-arm64@4.64.1': + '@rollup/rollup-darwin-arm64@4.64.5': optional: true - '@rollup/rollup-darwin-x64@4.64.1': + '@rollup/rollup-darwin-x64@4.64.5': optional: true - '@rollup/rollup-freebsd-arm64@4.64.1': + '@rollup/rollup-freebsd-arm64@4.64.5': optional: true - '@rollup/rollup-freebsd-x64@4.64.1': + '@rollup/rollup-freebsd-x64@4.64.5': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.64.1': + '@rollup/rollup-linux-arm-gnueabihf@4.64.5': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.64.1': + '@rollup/rollup-linux-arm-musleabihf@4.64.5': optional: true - '@rollup/rollup-linux-arm64-gnu@4.64.1': + '@rollup/rollup-linux-arm64-gnu@4.64.5': optional: true - '@rollup/rollup-linux-arm64-musl@4.64.1': + '@rollup/rollup-linux-arm64-musl@4.64.5': optional: true - '@rollup/rollup-linux-loong64-gnu@4.64.1': + '@rollup/rollup-linux-loong64-gnu@4.64.5': optional: true - '@rollup/rollup-linux-loong64-musl@4.64.1': + '@rollup/rollup-linux-loong64-musl@4.64.5': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.64.1': + '@rollup/rollup-linux-ppc64-gnu@4.64.5': optional: true - '@rollup/rollup-linux-ppc64-musl@4.64.1': + '@rollup/rollup-linux-ppc64-musl@4.64.5': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.64.1': + '@rollup/rollup-linux-riscv64-gnu@4.64.5': optional: true - '@rollup/rollup-linux-riscv64-musl@4.64.1': + '@rollup/rollup-linux-riscv64-musl@4.64.5': optional: true - '@rollup/rollup-linux-s390x-gnu@4.64.1': + '@rollup/rollup-linux-s390x-gnu@4.64.5': optional: true - '@rollup/rollup-linux-x64-gnu@4.64.1': + '@rollup/rollup-linux-x64-gnu@4.64.5': optional: true - '@rollup/rollup-linux-x64-musl@4.64.1': + '@rollup/rollup-linux-x64-musl@4.64.5': optional: true - '@rollup/rollup-openbsd-x64@4.64.1': + '@rollup/rollup-openbsd-x64@4.64.5': optional: true - '@rollup/rollup-openharmony-arm64@4.64.1': + '@rollup/rollup-openharmony-arm64@4.64.5': optional: true - '@rollup/rollup-win32-arm64-msvc@4.64.1': + '@rollup/rollup-win32-arm64-msvc@4.64.5': optional: true - '@rollup/rollup-win32-ia32-msvc@4.64.1': + '@rollup/rollup-win32-ia32-msvc@4.64.5': optional: true - '@rollup/rollup-win32-x64-gnu@4.64.1': + '@rollup/rollup-win32-x64-gnu@4.64.5': optional: true - '@rollup/rollup-win32-x64-msvc@4.64.1': + '@rollup/rollup-win32-x64-msvc@4.64.5': optional: true - '@rollup/wasm-node@4.64.1': + '@rollup/wasm-node@4.64.5': dependencies: '@types/estree': 1.0.9 optionalDependencies: @@ -11548,14 +11813,14 @@ snapshots: '@types/yarnpkg__lockfile@1.1.9': {} - '@typescript-eslint/eslint-plugin@8.71.1(@typescript-eslint/parser@8.71.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3))(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3)': + '@typescript-eslint/eslint-plugin@8.71.2(@typescript-eslint/parser@8.71.2(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3))(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.71.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.71.1 - '@typescript-eslint/type-utils': 8.71.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.71.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.71.1 + '@typescript-eslint/parser': 8.71.2(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.71.2 + '@typescript-eslint/type-utils': 8.71.2(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.71.2(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.71.2 eslint: 10.12.0(jiti@2.7.0)(supports-color@11.0.0) ignore: 7.0.12 natural-compare: 1.4.0 @@ -11564,41 +11829,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.71.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3)': + '@typescript-eslint/parser@8.71.2(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/scope-manager': 8.71.1 - '@typescript-eslint/types': 8.71.1 - '@typescript-eslint/typescript-estree': 8.71.1(supports-color@11.0.0)(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.71.1 + '@typescript-eslint/scope-manager': 8.71.2 + '@typescript-eslint/types': 8.71.2 + '@typescript-eslint/typescript-estree': 8.71.2(supports-color@11.0.0)(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.71.2 debug: 4.4.3(supports-color@11.0.0) eslint: 10.12.0(jiti@2.7.0)(supports-color@11.0.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.71.1(supports-color@11.0.0)(typescript@6.0.3)': + '@typescript-eslint/project-service@8.71.2(supports-color@11.0.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.71.1(typescript@6.0.3) - '@typescript-eslint/types': 8.71.1 + '@typescript-eslint/tsconfig-utils': 8.71.2(typescript@6.0.3) + '@typescript-eslint/types': 8.71.2 debug: 4.4.3(supports-color@11.0.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.71.1': + '@typescript-eslint/scope-manager@8.71.2': dependencies: - '@typescript-eslint/types': 8.71.1 - '@typescript-eslint/visitor-keys': 8.71.1 + '@typescript-eslint/types': 8.71.2 + '@typescript-eslint/visitor-keys': 8.71.2 - '@typescript-eslint/tsconfig-utils@8.71.1(typescript@6.0.3)': + '@typescript-eslint/tsconfig-utils@8.71.2(typescript@6.0.3)': dependencies: typescript: 6.0.3 - '@typescript-eslint/type-utils@8.71.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.71.2(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.71.1 - '@typescript-eslint/typescript-estree': 8.71.1(supports-color@11.0.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.71.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3) + '@typescript-eslint/types': 8.71.2 + '@typescript-eslint/typescript-estree': 8.71.2(supports-color@11.0.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.71.2(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3) debug: 4.4.3(supports-color@11.0.0) eslint: 10.12.0(jiti@2.7.0)(supports-color@11.0.0) ts-api-utils: 2.5.0(typescript@6.0.3) @@ -11608,12 +11873,14 @@ snapshots: '@typescript-eslint/types@8.71.1': {} - '@typescript-eslint/typescript-estree@8.71.1(supports-color@11.0.0)(typescript@6.0.3)': + '@typescript-eslint/types@8.71.2': {} + + '@typescript-eslint/typescript-estree@8.71.2(supports-color@11.0.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.71.1(supports-color@11.0.0)(typescript@6.0.3) - '@typescript-eslint/tsconfig-utils': 8.71.1(typescript@6.0.3) - '@typescript-eslint/types': 8.71.1 - '@typescript-eslint/visitor-keys': 8.71.1 + '@typescript-eslint/project-service': 8.71.2(supports-color@11.0.0)(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.71.2(typescript@6.0.3) + '@typescript-eslint/types': 8.71.2 + '@typescript-eslint/visitor-keys': 8.71.2 debug: 4.4.3(supports-color@11.0.0) minimatch: 10.2.6 semver: 7.8.5 @@ -11623,20 +11890,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.71.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3)': + '@typescript-eslint/utils@8.71.2(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3)': dependencies: '@eslint-community/eslint-utils': 4.10.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0)) - '@typescript-eslint/scope-manager': 8.71.1 - '@typescript-eslint/types': 8.71.1 - '@typescript-eslint/typescript-estree': 8.71.1(supports-color@11.0.0)(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.71.2 + '@typescript-eslint/types': 8.71.2 + '@typescript-eslint/typescript-estree': 8.71.2(supports-color@11.0.0)(typescript@6.0.3) eslint: 10.12.0(jiti@2.7.0)(supports-color@11.0.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.71.1': + '@typescript-eslint/visitor-keys@8.71.2': dependencies: - '@typescript-eslint/types': 8.71.1 + '@typescript-eslint/types': 8.71.2 eslint-visitor-keys: 5.0.1 '@verdaccio/auth@8.1.5(supports-color@11.0.0)': @@ -11807,21 +12074,21 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitejs/plugin-basic-ssl@2.3.0(vite@8.3.3(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))': + '@vitejs/plugin-basic-ssl@2.3.0(vite@8.3.4(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))': dependencies: - vite: 8.3.3(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1) + vite: 8.3.4(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1) - '@vitest/coverage-v8@5.0.3(vitest@5.0.3)': + '@vitest/coverage-v8@5.0.4(vitest@5.0.4)': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/istanbul-lib-coverage': 1.0.2 '@vitest/istanbul-lib-report': 1.0.2 ast-v8-to-istanbul: 1.0.7 magicast: 0.5.5 - obug: 2.2.1 + obug: 3.0.0 std-env: 4.3.0 tinyrainbow: 3.2.0 - vitest: 5.0.3(@opentelemetry/api@1.9.1)(@types/node@22.20.5)(@vitest/coverage-v8@5.0.3)(jsdom@30.1.2(@noble/hashes@1.8.0))(vite@8.3.3(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) + vitest: 5.0.4(@opentelemetry/api@1.9.1)(@types/node@22.20.5)(@vitest/coverage-v8@5.0.4)(jsdom@30.1.2(@noble/hashes@1.8.0))(vite@8.3.4(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) '@vitest/istanbul-lib-coverage@1.0.2': {} @@ -11829,16 +12096,16 @@ snapshots: dependencies: '@vitest/istanbul-lib-coverage': 1.0.2 - '@vitest/mocker@5.0.3(vite@8.3.3(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))': + '@vitest/mocker@5.0.4(vite@8.3.4(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))': dependencies: '@jridgewell/trace-mapping': 0.3.31 - '@vitest/spy': 5.0.3 + '@vitest/spy': 5.0.4 estree-walker: 3.0.3 magic-string: 1.4.3 optionalDependencies: - vite: 8.3.3(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1) + vite: 8.3.4(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1) - '@vitest/spy@5.0.3': {} + '@vitest/spy@5.0.4': {} '@webassemblyjs/ast@1.14.1': dependencies: @@ -11960,6 +12227,42 @@ snapshots: '@yuku-codegen/binding-win32-x64@0.10.2': optional: true + '@yuku-core/binding-android-arm64@0.19.0': + optional: true + + '@yuku-core/binding-darwin-arm64@0.19.0': + optional: true + + '@yuku-core/binding-darwin-x64@0.19.0': + optional: true + + '@yuku-core/binding-freebsd-x64@0.19.0': + optional: true + + '@yuku-core/binding-linux-arm-gnu@0.19.0': + optional: true + + '@yuku-core/binding-linux-arm-musl@0.19.0': + optional: true + + '@yuku-core/binding-linux-arm64-gnu@0.19.0': + optional: true + + '@yuku-core/binding-linux-arm64-musl@0.19.0': + optional: true + + '@yuku-core/binding-linux-x64-gnu@0.19.0': + optional: true + + '@yuku-core/binding-linux-x64-musl@0.19.0': + optional: true + + '@yuku-core/binding-win32-arm64@0.19.0': + optional: true + + '@yuku-core/binding-win32-x64@0.19.0': + optional: true + '@yuku-parser/binding-android-arm64@0.10.2': optional: true @@ -11998,6 +12301,8 @@ snapshots: '@yuku-toolchain/types@0.10.2': {} + '@yuku-toolchain/types@0.19.0': {} + JSONStream@1.3.5: dependencies: jsonparse: 1.3.1 @@ -12261,7 +12566,7 @@ snapshots: bcryptjs@2.4.3: {} - beasties@0.5.4: + beasties@0.5.5: dependencies: css-select: 7.0.0 css-what: 8.0.0 @@ -12517,11 +12822,11 @@ snapshots: chrome-trace-event@1.0.4: {} - chromium-bidi@17.0.2(devtools-protocol@0.0.1687809): + chromium-bidi@157.0.8090-0(devtools-protocol@0.0.1696802): dependencies: - devtools-protocol: 0.0.1687809 + devtools-protocol: 0.0.1696802 mitt: 3.0.1 - zod: 3.25.76 + zod: 4.6.5 chunk-data@0.1.0: {} @@ -12655,6 +12960,8 @@ snapshots: content-disposition@1.1.0: {} + content-disposition@2.0.1: {} + content-type@1.0.5: {} content-type@2.1.0: {} @@ -12849,7 +13156,7 @@ snapshots: dev-ip@1.0.1: {} - devtools-protocol@0.0.1687809: {} + devtools-protocol@0.0.1696802: {} di@0.0.1: {} @@ -13161,17 +13468,17 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.14.0(@typescript-eslint/parser@8.71.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@11.0.0))(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0): + eslint-module-utils@2.14.0(@typescript-eslint/parser@8.71.2(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@11.0.0))(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0): dependencies: debug: 3.2.7(supports-color@11.0.0) optionalDependencies: - '@typescript-eslint/parser': 8.71.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.71.2(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3) eslint: 10.12.0(jiti@2.7.0)(supports-color@11.0.0) eslint-import-resolver-node: 0.3.10(supports-color@11.0.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.71.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3))(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.71.2(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3))(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.2.0 @@ -13182,7 +13489,7 @@ snapshots: doctrine: 2.1.0 eslint: 10.12.0(jiti@2.7.0)(supports-color@11.0.0) eslint-import-resolver-node: 0.3.10(supports-color@11.0.0) - eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.71.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@11.0.0))(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0) + eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.71.2(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10(supports-color@11.0.0))(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0) hasown: 2.0.4 is-core-module: 2.17.0 is-glob: 4.0.3 @@ -13194,7 +13501,7 @@ snapshots: string.prototype.trimend: 1.0.10 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.71.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.71.2(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0))(supports-color@11.0.0)(typescript@6.0.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -13369,6 +13676,39 @@ snapshots: transitivePeerDependencies: - supports-color + express@5.3.0(supports-color@11.0.0): + dependencies: + accepts: 2.0.0 + body-parser: 2.3.0(supports-color@11.0.0) + content-disposition: 2.0.1 + content-type: 2.1.0 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3(supports-color@11.0.0) + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1(supports-color@11.0.0) + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.8 + qs: 6.16.0 + range-parser: 1.3.0 + router: 2.2.0(supports-color@11.0.0) + send: 1.2.1(supports-color@11.0.0) + serve-static: 2.2.1(supports-color@11.0.0) + statuses: 2.0.2 + type-is: 2.1.0 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + extend@3.0.2: {} extsprintf@1.3.0: {} @@ -14573,7 +14913,7 @@ snapshots: lines-and-columns@1.2.4: {} - listr2@11.1.1: + listr2@11.2.0: dependencies: cli-truncate: 6.1.1 log-update: 8.0.0 @@ -15383,13 +15723,13 @@ snapshots: punycode@2.3.1: {} - puppeteer-core@25.12.0(bufferutil@4.1.0)(utf-8-validate@6.0.6): + puppeteer-core@25.13.0(bufferutil@4.1.0)(utf-8-validate@6.0.6): dependencies: - '@puppeteer/browsers': 3.2.3 - chromium-bidi: 17.0.2(devtools-protocol@0.0.1687809) - devtools-protocol: 0.0.1687809 + '@puppeteer/browsers': 3.2.4 + chromium-bidi: 157.0.8090-0(devtools-protocol@0.0.1696802) + devtools-protocol: 0.0.1696802 typed-query-selector: 2.12.3 - webdriver-bidi-protocol: 0.4.3 + webdriver-bidi-protocol: 1.0.1 ws: 8.22.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - bufferutil @@ -15397,13 +15737,13 @@ snapshots: - utf-8-validate - yauzl - puppeteer@25.12.0(bufferutil@4.1.0)(utf-8-validate@6.0.6): + puppeteer@25.13.0(bufferutil@4.1.0)(utf-8-validate@6.0.6): dependencies: - '@puppeteer/browsers': 3.2.3 - chromium-bidi: 17.0.2(devtools-protocol@0.0.1687809) - devtools-protocol: 0.0.1687809 + '@puppeteer/browsers': 3.2.4 + chromium-bidi: 157.0.8090-0(devtools-protocol@0.0.1696802) + devtools-protocol: 0.0.1696802 lilconfig: 3.1.3 - puppeteer-core: 25.12.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + puppeteer-core: 25.13.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) typed-query-selector: 2.12.3 transitivePeerDependencies: - bufferutil @@ -15644,6 +15984,20 @@ snapshots: transitivePeerDependencies: - oxc-resolver + rolldown-plugin-dts@0.28.8(rolldown@1.2.13)(typescript@6.0.3): + dependencies: + dts-resolver: 3.0.0 + get-tsconfig: 5.0.0-beta.6 + obug: 3.0.0 + rolldown: 1.2.13 + yuku-ast: 0.19.0 + yuku-codegen: 0.19.0 + yuku-parser: 0.19.0 + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - oxc-resolver + rolldown@1.2.12: dependencies: '@oxc-project/types': 0.152.0 @@ -15665,54 +16019,75 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.2.12 '@rolldown/binding-win32-x64-msvc': 1.2.12 - rollup-plugin-dts@6.5.1(rollup@4.64.1)(typescript@6.0.3): + rolldown@1.2.13: + dependencies: + '@oxc-project/types': 0.153.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm-eabi': 1.2.13 + '@rolldown/binding-android-arm64': 1.2.13 + '@rolldown/binding-darwin-arm64': 1.2.13 + '@rolldown/binding-darwin-x64': 1.2.13 + '@rolldown/binding-freebsd-x64': 1.2.13 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.13 + '@rolldown/binding-linux-arm64-gnu': 1.2.13 + '@rolldown/binding-linux-arm64-musl': 1.2.13 + '@rolldown/binding-linux-ppc64-gnu': 1.2.13 + '@rolldown/binding-linux-s390x-gnu': 1.2.13 + '@rolldown/binding-linux-x64-gnu': 1.2.13 + '@rolldown/binding-linux-x64-musl': 1.2.13 + '@rolldown/binding-openharmony-arm64': 1.2.13 + '@rolldown/binding-win32-arm64-msvc': 1.2.13 + '@rolldown/binding-win32-x64-msvc': 1.2.13 + + rollup-plugin-dts@6.5.1(rollup@4.64.5)(typescript@6.0.3): dependencies: '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.6.0 convert-source-map: 2.0.0 magic-string: 0.30.21 - rollup: 4.64.1 + rollup: 4.64.5 typescript: 6.0.3 optionalDependencies: '@babel/code-frame': 8.0.6 - rollup-plugin-sourcemaps2@0.5.9(@types/node@22.20.5)(rollup@4.64.1): + rollup-plugin-sourcemaps2@0.5.9(@types/node@22.20.5)(rollup@4.64.5): dependencies: - '@rollup/pluginutils': 5.4.0(rollup@4.64.1) - rollup: 4.64.1 + '@rollup/pluginutils': 5.4.0(rollup@4.64.5) + rollup: 4.64.5 optionalDependencies: '@types/node': 22.20.5 - rollup@4.64.1: + rollup@4.64.5: dependencies: '@types/estree': 1.0.9 optionalDependencies: '@napi-rs/lzma-linux-x64-gnu': 1.5.1 - '@rollup/rollup-android-arm-eabi': 4.64.1 - '@rollup/rollup-android-arm64': 4.64.1 - '@rollup/rollup-darwin-arm64': 4.64.1 - '@rollup/rollup-darwin-x64': 4.64.1 - '@rollup/rollup-freebsd-arm64': 4.64.1 - '@rollup/rollup-freebsd-x64': 4.64.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.64.1 - '@rollup/rollup-linux-arm-musleabihf': 4.64.1 - '@rollup/rollup-linux-arm64-gnu': 4.64.1 - '@rollup/rollup-linux-arm64-musl': 4.64.1 - '@rollup/rollup-linux-loong64-gnu': 4.64.1 - '@rollup/rollup-linux-loong64-musl': 4.64.1 - '@rollup/rollup-linux-ppc64-gnu': 4.64.1 - '@rollup/rollup-linux-ppc64-musl': 4.64.1 - '@rollup/rollup-linux-riscv64-gnu': 4.64.1 - '@rollup/rollup-linux-riscv64-musl': 4.64.1 - '@rollup/rollup-linux-s390x-gnu': 4.64.1 - '@rollup/rollup-linux-x64-gnu': 4.64.1 - '@rollup/rollup-linux-x64-musl': 4.64.1 - '@rollup/rollup-openbsd-x64': 4.64.1 - '@rollup/rollup-openharmony-arm64': 4.64.1 - '@rollup/rollup-win32-arm64-msvc': 4.64.1 - '@rollup/rollup-win32-ia32-msvc': 4.64.1 - '@rollup/rollup-win32-x64-gnu': 4.64.1 - '@rollup/rollup-win32-x64-msvc': 4.64.1 + '@rollup/rollup-android-arm-eabi': 4.64.5 + '@rollup/rollup-android-arm64': 4.64.5 + '@rollup/rollup-darwin-arm64': 4.64.5 + '@rollup/rollup-darwin-x64': 4.64.5 + '@rollup/rollup-freebsd-arm64': 4.64.5 + '@rollup/rollup-freebsd-x64': 4.64.5 + '@rollup/rollup-linux-arm-gnueabihf': 4.64.5 + '@rollup/rollup-linux-arm-musleabihf': 4.64.5 + '@rollup/rollup-linux-arm64-gnu': 4.64.5 + '@rollup/rollup-linux-arm64-musl': 4.64.5 + '@rollup/rollup-linux-loong64-gnu': 4.64.5 + '@rollup/rollup-linux-loong64-musl': 4.64.5 + '@rollup/rollup-linux-ppc64-gnu': 4.64.5 + '@rollup/rollup-linux-ppc64-musl': 4.64.5 + '@rollup/rollup-linux-riscv64-gnu': 4.64.5 + '@rollup/rollup-linux-riscv64-musl': 4.64.5 + '@rollup/rollup-linux-s390x-gnu': 4.64.5 + '@rollup/rollup-linux-x64-gnu': 4.64.5 + '@rollup/rollup-linux-x64-musl': 4.64.5 + '@rollup/rollup-openbsd-x64': 4.64.5 + '@rollup/rollup-openharmony-arm64': 4.64.5 + '@rollup/rollup-win32-arm64-msvc': 4.64.5 + '@rollup/rollup-win32-ia32-msvc': 4.64.5 + '@rollup/rollup-win32-x64-gnu': 4.64.5 + '@rollup/rollup-win32-x64-msvc': 4.64.5 fsevents: 2.3.3 router@2.2.0(supports-color@11.0.0): @@ -16657,7 +17032,7 @@ snapshots: core-util-is: 1.0.2 extsprintf: 1.3.0 - vite@8.3.3(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1): + vite@8.3.4(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1): dependencies: lightningcss: 1.33.0 picomatch: 4.0.7 @@ -16676,26 +17051,26 @@ snapshots: tsx: 4.23.15 yaml: 2.9.1 - vitest@5.0.3(@opentelemetry/api@1.9.1)(@types/node@22.20.5)(@vitest/coverage-v8@5.0.3)(jsdom@30.1.2(@noble/hashes@1.8.0))(vite@8.3.3(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)): + vitest@5.0.4(@opentelemetry/api@1.9.1)(@types/node@22.20.5)(@vitest/coverage-v8@5.0.4)(jsdom@30.1.2(@noble/hashes@1.8.0))(vite@8.3.4(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)): dependencies: '@types/chai': 5.2.3 - '@vitest/mocker': 5.0.3(vite@8.3.3(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) + '@vitest/mocker': 5.0.4(vite@8.3.4(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) chai: 6.3.0 es-module-lexer: 2.3.2 expect-type: 1.4.0 magic-string: 1.4.3 - obug: 2.2.1 + obug: 3.0.0 picomatch: 4.0.7 std-env: 4.3.0 tinybench: 6.2.2 tinyexec: 1.3.1 tinyglobby: 0.2.17 - vite: 8.3.3(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1) + vite: 8.3.4(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(less@4.9.1(supports-color@11.0.0))(sass-embedded@1.105.1)(sass@1.105.1)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1) why-is-node-running: 3.2.1 optionalDependencies: '@opentelemetry/api': 1.9.1 '@types/node': 22.20.5 - '@vitest/coverage-v8': 5.0.3(vitest@5.0.3) + '@vitest/coverage-v8': 5.0.4(vitest@5.0.4) jsdom: 30.1.2(@noble/hashes@1.8.0) transitivePeerDependencies: - msw @@ -16717,7 +17092,7 @@ snapshots: web-vitals@4.2.4: {} - webdriver-bidi-protocol@0.4.3: {} + webdriver-bidi-protocol@1.0.1: {} webidl-conversions@3.0.1: {} @@ -17002,6 +17377,10 @@ snapshots: dependencies: '@yuku-toolchain/types': 0.10.2 + yuku-ast@0.19.0: + dependencies: + '@yuku-toolchain/types': 0.19.0 + yuku-codegen@0.10.2: dependencies: '@yuku-toolchain/types': 0.10.2 @@ -17019,6 +17398,27 @@ snapshots: '@yuku-codegen/binding-win32-arm64': 0.10.2 '@yuku-codegen/binding-win32-x64': 0.10.2 + yuku-codegen@0.19.0: + dependencies: + '@yuku-toolchain/types': 0.19.0 + + yuku-core@0.19.0: + dependencies: + '@yuku-toolchain/types': 0.19.0 + optionalDependencies: + '@yuku-core/binding-android-arm64': 0.19.0 + '@yuku-core/binding-darwin-arm64': 0.19.0 + '@yuku-core/binding-darwin-x64': 0.19.0 + '@yuku-core/binding-freebsd-x64': 0.19.0 + '@yuku-core/binding-linux-arm-gnu': 0.19.0 + '@yuku-core/binding-linux-arm-musl': 0.19.0 + '@yuku-core/binding-linux-arm64-gnu': 0.19.0 + '@yuku-core/binding-linux-arm64-musl': 0.19.0 + '@yuku-core/binding-linux-x64-gnu': 0.19.0 + '@yuku-core/binding-linux-x64-musl': 0.19.0 + '@yuku-core/binding-win32-arm64': 0.19.0 + '@yuku-core/binding-win32-x64': 0.19.0 + yuku-parser@0.10.2: dependencies: '@yuku-toolchain/types': 0.10.2 @@ -17037,8 +17437,13 @@ snapshots: '@yuku-parser/binding-win32-arm64': 0.10.2 '@yuku-parser/binding-win32-x64': 0.10.2 - zod@3.25.76: {} + yuku-parser@0.19.0: + dependencies: + '@yuku-toolchain/types': 0.19.0 + yuku-core: 0.19.0 zod@4.6.5: {} + zod@4.6.7: {} + zone.js@0.16.3: {} From 1e97effe7bbc73553b1bf35a92e0df7169598ca3 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Tue, 13 Oct 2026 14:31:42 +0000 Subject: [PATCH 27/52] refactor(@angular/build): collect and log build errors in library builder Instead of throwing errors inside `buildAction` and `compileLibrary` during progress spinner execution, collect formatted diagnostic errors, warnings, and informational logs into `BuildActionResult` and log them via `context.logger` after `withProgress` completes, matching the behavior of the `application` builder. --- .../build/src/builders/library/builder.ts | 52 +++- .../builders/library/pipeline/build-action.ts | 294 ++++++++++-------- .../builders/library/pipeline/compilation.ts | 54 ++-- .../builders/library/pipeline/entry-points.ts | 65 ++++ .../library/tests/behavior/build_spec.ts | 6 + .../allowed-non-peer-dependencies_spec.ts | 10 +- 6 files changed, 317 insertions(+), 164 deletions(-) diff --git a/packages/angular/build/src/builders/library/builder.ts b/packages/angular/build/src/builders/library/builder.ts index 948f53ae568b..84b933e7ceb6 100644 --- a/packages/angular/build/src/builders/library/builder.ts +++ b/packages/angular/build/src/builders/library/builder.ts @@ -24,6 +24,7 @@ import { getSupportedBrowsers } from '../../utils/supported-browsers'; import { assertCompatibleAngularVersion } from '../../utils/version'; import type { BuildWatcher } from '../../utils/watcher'; import { normalizeLibraryOptions } from './options'; +import type { BuildActionResult } from './pipeline/build-action'; import { updateWatchedEntryPoints } from './pipeline/entry-points'; import type { createComponentStylesheetBundlerForLibrary } from './pipeline/stylesheet-bundler'; import { loadPackageJson } from './pipeline/utils'; @@ -185,6 +186,17 @@ export async function* executeLibraryBuilder( } } +/** + * Executes a single build iteration with progress reporting, logs any resulting + * messages, and registers newly discovered files with the watcher. + * + * @param message Progress spinner message to display while building. + * @param actionContext The build action context and state. + * @param withProgress Progress wrapper function (`withSpinner` or `withNoProgress`). + * @param watcher Optional file watcher for watch mode. + * @param buildAction The library build action function to execute. + * @returns A promise resolving to the Architect `BuilderOutput`. + */ async function executeBuild( message: string, actionContext: import('./pipeline/build-action').BuildActionContext, @@ -196,13 +208,16 @@ async function executeBuild( const { context, watchedCompilationFiles, isWatchMode, options } = actionContext; try { - await withProgress(message, () => buildAction(actionContext)); - logBuildResult(context.logger, startTime, true, options.outputPath); - if (isWatchMode) { + const result = await withProgress(message, () => buildAction(actionContext)); + logMessages(context.logger, result); + + const success = result.errors.length === 0; + logBuildResult(context.logger, startTime, success, options.outputPath); + if (success && isWatchMode) { logCumulativeDurations(); } - return { success: true }; + return { success }; } catch (error) { assertIsError(error); logBuildResult(context.logger, startTime, false); @@ -300,6 +315,7 @@ async function* runWatchLoop( assertIsError(error); await buildState.singleProgramCache?.compilationInstance.update?.(changedFiles); buildState.hasEmittedManifests = false; + yield { success: false, error: `Failed to reload 'package.json': ${error.message}`, @@ -343,8 +359,36 @@ async function* runWatchLoop( } } +/** + * Logs informational, warning, and error messages produced during a build iteration. + * + * @param logger The Architect logger API. + * @param result The build action result containing logs, warnings, and errors. + */ +function logMessages( + logger: logging.LoggerApi, + { logs, warnings, errors }: BuildActionResult, +): void { + if (logs.length) { + logger.info(logs.join('\n')); + } + + if (warnings.length) { + logger.warn(warnings.join('\n')); + } + + if (errors.length) { + logger.error(errors.join('\n')); + } +} + /** * Logs the build completion time and status. + * + * @param logger The Architect logger API. + * @param startTime High-resolution timestamp recorded when the build iteration started. + * @param success Whether the build iteration succeeded without errors. + * @param outputPath Optional output directory path to log on successful builds. */ function logBuildResult( logger: logging.LoggerApi, diff --git a/packages/angular/build/src/builders/library/pipeline/build-action.ts b/packages/angular/build/src/builders/library/pipeline/build-action.ts index a430312ac925..6d40f5fe4383 100644 --- a/packages/angular/build/src/builders/library/pipeline/build-action.ts +++ b/packages/angular/build/src/builders/library/pipeline/build-action.ts @@ -10,14 +10,30 @@ import type { BuilderContext } from '@angular-devkit/architect'; import path from 'node:path'; import type { ComponentStylesheetBundler } from '../../../tools/esbuild/angular/component-stylesheets'; import { emitFilesToDisk } from '../../../utils/emit-files-to-disk'; +import { assertIsError } from '../../../utils/error'; import { toPosixPath } from '../../../utils/path'; import type { NormalizedLibraryOptions, SingleBuildState } from '../types'; import { collectAssetsToEmit } from './assets'; -import { type BundleEntryPointInput, bundleEntryPoints } from './bundler'; -import { compileLibrary } from './compilation'; +import { bundleEntryPoints } from './bundler'; +import { type LibraryCompilationDiagnostics, compileLibrary } from './compilation'; +import { collectEntryPointsToBundle } from './entry-points'; import { generatePackageManifests } from './package-manifests'; import type { DiskOutputFile, OutputFile } from './utils'; +/** + * Result of executing a single library build iteration. + */ +export interface BuildActionResult { + /** Formatted error messages produced during the build. */ + errors: string[]; + + /** Formatted warning messages produced during the build. */ + warnings: string[]; + + /** Informational log messages produced during the build. */ + logs: string[]; +} + /** * Creates a fresh {@link SingleBuildState} instance. */ @@ -76,10 +92,9 @@ export interface BuildActionContext { * * @param actionContext The build action state and configuration. */ -export async function buildAction(actionContext: BuildActionContext): Promise { +export async function buildAction(actionContext: BuildActionContext): Promise { const { options, - context, stylesheetBundler, isWatchMode, watchedCompilationFiles, @@ -87,6 +102,10 @@ export async function buildAction(actionContext: BuildActionContext): Promise 0 || pendingChangedDtsFiles.size > 0 || hasModifiedWatchedFile(modifiedFiles, watchedCompilationFiles, posixPackageJsonPath); - const shouldGenerateManifests = !buildState.hasEmittedManifests; - if (shouldGenerateManifests) { - verifyAllowedDependencies(options); - } + try { + if (!buildState.hasEmittedManifests) { + const dependencyErrors = verifyAllowedDependencies(options); + if (dependencyErrors.length > 0) { + errors.push(...dependencyErrors); - const filesToEmit: OutputFile[] = []; - - if (shouldCompileEntryPoints) { - buildState.hasCompilationError = true; - buildState.hasEntryPointsChanges = false; - - const { - esmFiles, - dtsFiles, - changedEsmFiles, - changedDtsFiles, - referencedFiles, - cache, - diagnosePromise, - declarationMap, - compilationMode, - } = await compileLibrary( - options.entryPoints.values(), - options, - stylesheetBundler, - buildState.singleProgramCache, - modifiedFiles, - ); - buildState.singleProgramCache = cache; - if (buildState.compilationMode !== compilationMode) { - buildState.compilationMode = compilationMode; - buildState.hasEmittedManifests = false; + return { errors, warnings, logs }; + } } - for (const file of referencedFiles) { - watchedCompilationFiles.add(file); - } + const filesToEmit: OutputFile[] = []; - for (const file of changedEsmFiles) { - pendingChangedEsmFiles.add(file); - } - for (const file of changedDtsFiles) { - pendingChangedDtsFiles.add(file); - } + if (shouldCompileEntryPoints) { + buildState.hasCompilationError = true; + buildState.hasEntryPointsChanges = false; - const itemsToBundle: BundleEntryPointInput[] = []; + const { + esmFiles, + dtsFiles, + changedEsmFiles, + changedDtsFiles, + referencedFiles, + cache, + hasStylesheetErrors, + diagnosePromise, + declarationMap, + compilationMode, + } = await compileLibrary( + options.entryPoints.values(), + options, + stylesheetBundler, + buildState.singleProgramCache, + modifiedFiles, + ); + buildState.singleProgramCache = cache; + if (buildState.compilationMode !== compilationMode) { + buildState.compilationMode = compilationMode; + buildState.hasEmittedManifests = false; + } - for (const entryPoint of options.entryPoints.values()) { - const previousBundleResult = buildState.previousBundleResults.get(entryPoint.name); - const hasEsmChanges = - !previousBundleResult || - hasEntryPointChanges(previousBundleResult.esmModuleIds, pendingChangedEsmFiles); - const hasDtsChanges = - !previousBundleResult || - hasEntryPointChanges(previousBundleResult.dtsModuleIds, pendingChangedDtsFiles); - - if (hasEsmChanges || hasDtsChanges) { - context.logger.info(`Compiling ${entryPoint.displayName}...`); - itemsToBundle.push({ - entryPoint, - hasEsmChanges, - hasDtsChanges, - previousBundleResult, - }); + for (const file of referencedFiles) { + watchedCompilationFiles.add(file); + } + for (const file of changedEsmFiles) { + pendingChangedEsmFiles.add(file); + } + for (const file of changedDtsFiles) { + pendingChangedDtsFiles.add(file); } - } - let bundleOutput: Awaited>; - let warnings: string[]; - try { - [bundleOutput, warnings] = await Promise.all([ - bundleEntryPoints(itemsToBundle, esmFiles, dtsFiles, { - ...options, - declarationMap, - compilationMode, - }), - diagnosePromise, - ]); - } catch (error) { - // Prioritize TypeScript/Angular diagnostic errors over secondary bundler failures. - await diagnosePromise; - throw error; - } + const itemsToBundle = collectEntryPointsToBundle(options, buildState, logs); + + let bundleOutput: Awaited> | undefined; + let diagnostics: LibraryCompilationDiagnostics; + if (hasStylesheetErrors) { + diagnostics = await diagnosePromise; + } else { + try { + [bundleOutput, diagnostics] = await Promise.all([ + bundleEntryPoints(itemsToBundle, esmFiles, dtsFiles, { + ...options, + declarationMap, + compilationMode, + }), + diagnosePromise, + ]); + } catch (error) { + assertIsError(error); + // Prioritize TypeScript/Angular diagnostic errors over secondary bundler failures. + diagnostics = await diagnosePromise; + if (diagnostics.errors.length === 0) { + errors.push(error.message); + } + } + } + + warnings.push(...diagnostics.warnings, ...(bundleOutput?.warnings ?? [])); + if (diagnostics.errors.length > 0 || errors.length > 0 || !bundleOutput) { + errors.push(...diagnostics.errors); + + return { errors, warnings, logs }; + } - buildState.hasCompilationError = false; - pendingChangedEsmFiles.clear(); - pendingChangedDtsFiles.clear(); + buildState.hasCompilationError = false; + pendingChangedEsmFiles.clear(); + pendingChangedDtsFiles.clear(); - for (const warning of [...warnings, ...bundleOutput.warnings]) { - context.logger.warn(warning); + filesToEmit.push(...bundleOutput.filesToEmit); + for (const [name, bundleResult] of bundleOutput.bundleResults) { + buildState.previousBundleResults.set(name, bundleResult); + } } - filesToEmit.push(...bundleOutput.filesToEmit); - for (const [name, bundleResult] of bundleOutput.bundleResults) { - buildState.previousBundleResults.set(name, bundleResult); + let hasTslibImport = false; + for (const entryPoint of options.entryPoints.values()) { + if (buildState.previousBundleResults.get(entryPoint.name)?.hasTslibImport) { + hasTslibImport = true; + break; + } } - } - let hasTslibImport = false; - for (const entryPoint of options.entryPoints.values()) { - if (buildState.previousBundleResults.get(entryPoint.name)?.hasTslibImport) { - hasTslibImport = true; - break; + if (!buildState.hasEmittedManifests || buildState.hasEmittedTslib !== hasTslibImport) { + filesToEmit.push( + ...(await generatePackageManifests( + { + ...options, + compilationMode: buildState.compilationMode ?? options.compilationMode ?? 'partial', + }, + isWatchMode, + hasTslibImport, + )), + ); } - } - if (!buildState.hasEmittedManifests || buildState.hasEmittedTslib !== hasTslibImport) { - filesToEmit.push( - ...(await generatePackageManifests( - { - ...options, - compilationMode: buildState.compilationMode ?? options.compilationMode ?? 'partial', - }, - isWatchMode, - hasTslibImport, - )), - ); + const resolvedAssetsToEmit = (actionContext.assetsToEmit ??= await collectAssetsToEmit( + options.assets, + options.workspaceRoot, + buildState.hasEmittedAssets ? modifiedFiles : undefined, + )); + filesToEmit.push(...resolvedAssetsToEmit); + + await emitFilesToDisk(filesToEmit, (file) => path.join(options.outputPath, file.path)); + + buildState.hasEmittedManifests = true; + buildState.hasEmittedTslib = hasTslibImport; + buildState.hasEmittedAssets = true; + } catch (error) { + assertIsError(error); + errors.push(error.message); } - const resolvedAssetsToEmit = (actionContext.assetsToEmit ??= await collectAssetsToEmit( - options.assets, - options.workspaceRoot, - buildState.hasEmittedAssets ? modifiedFiles : undefined, - )); - filesToEmit.push(...resolvedAssetsToEmit); - - await emitFilesToDisk(filesToEmit, (file) => path.join(options.outputPath, file.path)); - - buildState.hasEmittedManifests = true; - buildState.hasEmittedTslib = hasTslibImport; - buildState.hasEmittedAssets = true; + return { errors, warnings, logs }; } +/** + * Checks whether any modified file (excluding `package.json`) is part of the + * tracked compilation file set. + * + * @param modifiedFiles Set of POSIX file paths modified since the last build. + * @param watchedCompilationFiles Set of POSIX file paths tracked for compilation. + * @param posixPackageJsonPath The normalized POSIX path to the library's `package.json`. + * @returns `true` if a watched compilation file was modified; otherwise `false`. + */ export function hasModifiedWatchedFile( modifiedFiles: ReadonlySet, watchedCompilationFiles: ReadonlySet, @@ -250,36 +279,29 @@ export function hasModifiedWatchedFile( return false; } -function hasEntryPointChanges( - moduleIds: ReadonlySet, - changedFiles: ReadonlySet, -): boolean { - if (changedFiles.size === 0) { - return false; - } - - for (const file of changedFiles) { - if (moduleIds.has(file)) { - return true; - } - } - - return false; -} - -function verifyAllowedDependencies(options: NormalizedLibraryOptions): void { +/** + * Validates that all direct and optional dependencies in `package.json` are + * permitted by `allowedNonPeerDependencies`. + * + * @param options The normalized library builder options. + * @returns An array of error messages for any disallowed dependencies. + */ +function verifyAllowedDependencies(options: NormalizedLibraryOptions): string[] { const { packageJson, allowedNonPeerDependencies } = options; const dependencies = { ...(packageJson.dependencies ?? {}), ...(packageJson.optionalDependencies ?? {}), }; + const errors: string[] = []; for (const dep of Object.keys(dependencies)) { if (!allowedNonPeerDependencies.some((regex) => regex.test(dep))) { - throw new Error( + errors.push( `Dependency '${dep}' must be explicitly allowed using the 'allowedNonPeerDependencies' option, ` + `or moved to 'peerDependencies' in 'package.json'.`, ); } } + + return errors; } diff --git a/packages/angular/build/src/builders/library/pipeline/compilation.ts b/packages/angular/build/src/builders/library/pipeline/compilation.ts index 51a8fb0d231e..afc5c319854e 100644 --- a/packages/angular/build/src/builders/library/pipeline/compilation.ts +++ b/packages/angular/build/src/builders/library/pipeline/compilation.ts @@ -20,6 +20,17 @@ import { isDeclarationFile, isDeclarationSourceMapFile } from './utils'; const EMITTED_EXTENSIONS = ['.js', '.mjs', '.cjs', '.d.ts', '.d.mts', '.d.cts']; +/** + * Formatted diagnostic messages produced during library compilation. + */ +export interface LibraryCompilationDiagnostics { + /** Formatted compilation error messages. */ + readonly errors: string[]; + + /** Formatted compilation warning messages. */ + readonly warnings: string[]; +} + /** * Output of the unified library compilation step. */ @@ -42,8 +53,11 @@ export interface LibraryCompilationOutput { /** Cached compilation state for subsequent incremental builds. */ readonly cache: SingleProgramCache; - /** Promise that resolves to formatted compilation warnings or rejects on diagnostic errors. */ - readonly diagnosePromise: Promise; + /** Whether any component stylesheet bundling errors occurred. */ + readonly hasStylesheetErrors: boolean; + + /** Promise that resolves to formatted compilation diagnostic errors and warnings. */ + readonly diagnosePromise: Promise; /** Effective declarationMap setting resolved from builder options and tsconfig. */ readonly declarationMap: boolean; @@ -145,8 +159,8 @@ export async function compileLibrary( 'library', ); - const emittedFiles = - stylesheetErrors.length === 0 ? await compilationInstance.emitAffectedFiles() : []; + const hasStylesheetErrors = stylesheetErrors.length > 0; + const emittedFiles = hasStylesheetErrors ? [] : await compilationInstance.emitAffectedFiles(); const diagnosePromise = runDiagnosticsAndFormat( compilationInstance, stylesheetErrors, @@ -154,9 +168,6 @@ export async function compileLibrary( colors, ); - // Prevent unhandled promise rejection if an error occurs before diagnosePromise is awaited. - diagnosePromise.catch(() => {}); - const esmFiles = cached?.esmFiles ?? new Map(); const dtsFiles = cached?.dtsFiles ?? new Map(); const changedEsmFiles = new Set(); @@ -225,6 +236,7 @@ export async function compileLibrary( dtsFiles, failedFiles: failedFiles.size > 0 ? failedFiles : undefined, }, + hasStylesheetErrors, diagnosePromise, declarationMap: !!compilerOptions.declarationMap, compilationMode: compilerOptions.compilationMode === 'full' ? 'full' : 'partial', @@ -238,34 +250,31 @@ export async function compileLibrary( } /** - * Validates stylesheet bundling results and runs TypeScript/Angular diagnostics. + * Formats stylesheet bundling diagnostics and TypeScript/Angular diagnostics. * * @param compilationInstance The active Angular compilation instance. * @param stylesheetErrors List of stylesheet bundling errors. * @param stylesheetWarnings List of stylesheet bundling warnings. * @param colors Whether diagnostic messages should be formatted with ANSI colors. - * @returns A promise resolving to formatted warning messages. - * @throws If stylesheet bundling errors or compilation errors occur. + * @returns A promise resolving to the formatted diagnostic errors and warnings. */ async function runDiagnosticsAndFormat( compilationInstance: AngularCompilation, stylesheetErrors: PartialMessage[], stylesheetWarnings: PartialMessage[], colors: boolean, -): Promise { - if (stylesheetErrors.length > 0) { - const formatted = await formatMessages(stylesheetErrors, { kind: 'error', color: colors }); - - throw new Error(`Failed to bundle stylesheet:\n${formatted.join('\n')}`); - } - +): Promise { + const errorsOut: string[] = []; const warningsOut: string[] = []; - if (useTypeChecking) { + if (stylesheetErrors.length > 0) { + const formatted = await formatMessages(stylesheetErrors, { kind: 'error', color: colors }); + errorsOut.push(...formatted); + } else if (useTypeChecking) { const { errors, warnings } = await compilationInstance.diagnoseFiles(); if (errors?.length) { - const errorMessages = await formatMessages(errors, { kind: 'error', color: colors }); - throw new Error(`Compilation failed with errors:\n${errorMessages.join('\n')}`); + const formatted = await formatMessages(errors, { kind: 'error', color: colors }); + errorsOut.push(...formatted); } if (warnings?.length) { @@ -282,5 +291,8 @@ async function runDiagnosticsAndFormat( warningsOut.push(...formattedStyleWarnings); } - return warningsOut; + return { + errors: errorsOut, + warnings: warningsOut, + }; } diff --git a/packages/angular/build/src/builders/library/pipeline/entry-points.ts b/packages/angular/build/src/builders/library/pipeline/entry-points.ts index 93a96307d9e4..7797f069fade 100644 --- a/packages/angular/build/src/builders/library/pipeline/entry-points.ts +++ b/packages/angular/build/src/builders/library/pipeline/entry-points.ts @@ -14,6 +14,7 @@ import type { PackageJsonData, SingleBuildState, } from '../types'; +import type { BundleEntryPointInput } from './bundler'; /** * Computes the base bundle file name for an entry point. @@ -270,3 +271,67 @@ export function updateWatchedEntryPoints( buildState.hasEntryPointsChanges = true; } } + +/** + * Determines which entry points have modified JavaScript or declaration files + * and collects them for bundling. + * + * @param options The normalized library builder options. + * @param buildState The state preserved across incremental builds. + * @param logs Array of informational log messages to append to when an entry point is queued. + * @returns The list of entry points that require bundling in the current build iteration. + */ +export function collectEntryPointsToBundle( + options: NormalizedLibraryOptions, + buildState: SingleBuildState, + logs: string[], +): BundleEntryPointInput[] { + const { pendingChangedEsmFiles, pendingChangedDtsFiles, previousBundleResults } = buildState; + const itemsToBundle: BundleEntryPointInput[] = []; + + for (const entryPoint of options.entryPoints.values()) { + const previousBundleResult = previousBundleResults.get(entryPoint.name); + const hasEsmChanges = + !previousBundleResult || + hasEntryPointChanges(previousBundleResult.esmModuleIds, pendingChangedEsmFiles); + const hasDtsChanges = + !previousBundleResult || + hasEntryPointChanges(previousBundleResult.dtsModuleIds, pendingChangedDtsFiles); + + if (hasEsmChanges || hasDtsChanges) { + logs.push(`Compiling ${entryPoint.displayName}...`); + itemsToBundle.push({ + entryPoint, + hasEsmChanges, + hasDtsChanges, + previousBundleResult, + }); + } + } + + return itemsToBundle; +} + +/** + * Checks whether any file in `changedFiles` belongs to the given entry point's `moduleIds`. + * + * @param moduleIds Set of module IDs referenced by the entry point's previous bundle. + * @param changedFiles Set of file paths that changed during compilation. + * @returns `true` if at least one changed file is part of `moduleIds`; otherwise `false`. + */ +function hasEntryPointChanges( + moduleIds: ReadonlySet, + changedFiles: ReadonlySet, +): boolean { + if (changedFiles.size === 0) { + return false; + } + + for (const file of changedFiles) { + if (moduleIds.has(file)) { + return true; + } + } + + return false; +} diff --git a/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts b/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts index e55a414c1ada..4f5c6736c1ff 100644 --- a/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts +++ b/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts @@ -216,6 +216,12 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => const { result, logs } = await harness.executeOnce({ outputLogsOnFailure: false }); expect(result?.success).toBeFalse(); + expect(logs).toContain( + jasmine.objectContaining({ + level: 'error', + message: jasmine.stringContaining('TS2322'), + }), + ); expect(logs).toContain( jasmine.objectContaining({ level: 'error', diff --git a/packages/angular/build/src/builders/library/tests/options/allowed-non-peer-dependencies_spec.ts b/packages/angular/build/src/builders/library/tests/options/allowed-non-peer-dependencies_spec.ts index caca7c594f26..c75699d068a3 100644 --- a/packages/angular/build/src/builders/library/tests/options/allowed-non-peer-dependencies_spec.ts +++ b/packages/angular/build/src/builders/library/tests/options/allowed-non-peer-dependencies_spec.ts @@ -24,10 +24,14 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => ...BASE_OPTIONS, }); - const { result } = await harness.executeOnce(); + const { result, logs } = await harness.executeOnce({ outputLogsOnFailure: false }); expect(result?.success).toBeFalse(); - expect(result?.error).toContain('allowedNonPeerDependencies'); - expect(result?.error).toContain('lodash-es'); + expect(logs).toContain( + jasmine.objectContaining({ + level: 'error', + message: jasmine.stringMatching(/lodash-es.*allowedNonPeerDependencies/), + }), + ); }); it('should succeed build when dependency matches allowedNonPeerDependencies pattern', async () => { From 0b9a52cc9516d28afa0d9ef0d07ec745967faf56 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Tue, 13 Oct 2026 07:00:46 +0000 Subject: [PATCH 28/52] fix(@angular/ssr): preserve preload metadata for nested empty-path routes Previously, `handleRoute` yielded a parent route's metadata before appending `loadChildren` preloads or traversing child routes, while `traverseRoutesConfig` appended a trailing slash only to empty-path routes. Under a non-empty parent, the parent ('/pricing') and its empty-path child ('/pricing/') received distinct keys during `getRoutesFromAngularRouterConfig` deduplication (`seenRoutes`) and were only merged later by `RouteTree.insert`. However, when an empty-path route was nested under another empty-path route (such as at the root '/' or under '/es' -> '' -> ''), both the parent and child received the same key, causing `seenRoutes` to keep the outer route's metadata and drop the descendant's accumulated `preload` and redirect metadata. Update `handleRoute` to append `loadChildren` preloads upfront and allow the first matching empty-path child route to override its parent's metadata for the same path, and remove the redundant `addTrailingSlash` keying in `traverseRoutesConfig`. Closes #34320 --- packages/angular/ssr/src/routes/ng-routes.ts | 96 ++++++++++++------- .../angular/ssr/test/routes/ng-routes_spec.ts | 91 ++++++++++++++++++ packages/angular/ssr/test/testing-utils.ts | 5 +- 3 files changed, 156 insertions(+), 36 deletions(-) diff --git a/packages/angular/ssr/src/routes/ng-routes.ts b/packages/angular/ssr/src/routes/ng-routes.ts index 915d7c2b9a47..816155c4df01 100644 --- a/packages/angular/ssr/src/routes/ng-routes.ts +++ b/packages/angular/ssr/src/routes/ng-routes.ts @@ -31,7 +31,7 @@ import { AngularAppManifest, getAngularAppManifest } from '../manifest'; import { AngularBootstrap, isNgModule } from '../utils/ng'; import { promiseWithAbort } from '../utils/promise'; import { VALID_REDIRECT_RESPONSE_CODES, isValidRedirectResponseCode } from '../utils/redirect'; -import { addTrailingSlash, joinUrlParts, stripLeadingSlash } from '../utils/url'; +import { joinUrlParts, stripLeadingSlash } from '../utils/url'; import { PrerenderFallback, RenderMode, @@ -170,12 +170,14 @@ async function* handleRoute(options: { } = options; const { redirectTo, loadChildren, loadComponent, children, ɵentryName } = route; - if (ɵentryName && loadComponent) { + if (ɵentryName && (loadComponent || loadChildren)) { appendPreloadToMetadata(ɵentryName, entryPointToBrowserMapping, metadata); } + const parentRoutes = new Map(); + if (metadata.renderMode === RenderMode.Prerender) { - yield* handleSSGRoute( + for await (const result of handleSSGRoute( serverConfigRouteTree, typeof redirectTo === 'string' ? redirectTo : undefined, parentRoute, @@ -183,7 +185,13 @@ async function* handleRoute(options: { parentInjector, invokeGetPrerenderParams, includePrerenderFallbackRoutes, - ); + )) { + if ('error' in result) { + yield result; + } else { + parentRoutes.set(result.route, result); + } + } } else if (redirectTo !== undefined) { if (metadata.status && !isValidRedirectResponseCode(metadata.status)) { yield { @@ -192,34 +200,23 @@ async function* handleRoute(options: { `Please use one of the following redirect response codes: ${[...VALID_REDIRECT_RESPONSE_CODES.values()].join(', ')}.`, }; } else if (typeof redirectTo === 'string') { - yield { + parentRoutes.set(metadata.route, { ...metadata, redirectTo: resolveRedirectTo(parentRoute, redirectTo), relativeRedirect: redirectTo[0] !== '/' ? true : undefined, - }; + }); } else { - yield metadata; + parentRoutes.set(metadata.route, metadata); } } else { - yield metadata; + parentRoutes.set(metadata.route, metadata); } - // Recursively process child routes - if (children?.length) { - yield* traverseRoutesConfig({ - ...options, - routes: children, - parentRoute: currentRoutePath, - parentPreloads: metadata.preload, - }); - } - - // Load and process lazy-loaded child routes - if (loadChildren) { - if (ɵentryName) { - appendPreloadToMetadata(ɵentryName, entryPointToBrowserMapping, metadata); - } + // Recursively process child and lazy-loaded routes + let childRoutes: Route[] | undefined = children; + let childInjector = parentInjector; + if (!childRoutes?.length && loadChildren) { const routeInjector = route.providers ? createEnvironmentInjector( route.providers, @@ -230,16 +227,48 @@ async function* handleRoute(options: { const loadedChildRoutes = await loadChildrenHelper(route, compiler, routeInjector); if (loadedChildRoutes) { - const { routes: childRoutes, injector = routeInjector } = loadedChildRoutes; - yield* traverseRoutesConfig({ - ...options, - routes: childRoutes, - parentInjector: injector, - parentRoute: currentRoutePath, - parentPreloads: metadata.preload, - }); + childRoutes = loadedChildRoutes.routes; + childInjector = loadedChildRoutes.injector ?? routeInjector; } } + + if (!childRoutes?.length) { + yield* parentRoutes.values(); + + return; + } + + const childResults: (RouteTreeNodeMetadata | { error: string })[] = []; + const overriddenParentRoutes = new Set(); + const traverseChildRoutes = traverseRoutesConfig({ + ...options, + routes: childRoutes, + parentInjector: childInjector, + parentRoute: currentRoutePath, + parentPreloads: metadata.preload, + }); + + for await (const result of traverseChildRoutes) { + if ('error' in result) { + childResults.push(result); + continue; + } + + // If a child route resolves to the exact same path as the parent (i.e., an empty-path child), + // let the first matching child override the parent's metadata so accumulated preloads and + // redirects from the activated descendant chain are preserved. + if (parentRoutes.has(result.route)) { + if (!overriddenParentRoutes.has(result.route)) { + overriddenParentRoutes.add(result.route); + parentRoutes.set(result.route, result); + } + } else { + childResults.push(result); + } + } + + yield* parentRoutes.values(); + yield* childResults; } catch (error) { yield { error: `Error in handleRoute for '${options.currentRoutePath}': ${(error as Error).message}`, @@ -344,10 +373,7 @@ async function* traverseRoutesConfig(options: { renderMode: RenderMode.Prerender, ...matchedMetaData, preload: parentPreloads, - // Match Angular router behavior - // ['one', 'two', ''] -> 'one/two/' - // ['one', 'two', 'three'] -> 'one/two/three' - route: path === '' ? addTrailingSlash(currentRoutePath) : currentRoutePath, + route: currentRoutePath, presentInClientRouter: undefined, }, currentRoutePath, diff --git a/packages/angular/ssr/test/routes/ng-routes_spec.ts b/packages/angular/ssr/test/routes/ng-routes_spec.ts index 1af823f8f2ba..93b8e446ccb4 100644 --- a/packages/angular/ssr/test/routes/ng-routes_spec.ts +++ b/packages/angular/ssr/test/routes/ng-routes_spec.ts @@ -1044,4 +1044,95 @@ describe('extractRoutesAndCreateRouteTree', () => { expect(isDiscoveringRoutes).toBeTrue(); }); + + it('should preserve preload metadata for routes under nested empty-path routes', async () => { + setAngularAppTestingManifest( + [ + { + path: '', + children: [ + { + path: '', + pathMatch: 'full', + loadChildren: () => [ + { + path: '', + loadComponent: () => DummyComponent, + ɵentryName: 'home-page', + } as Route, + ], + ɵentryName: 'home-routes', + } as Route, + { + path: '', + children: [ + { + path: 'pricing', + loadChildren: () => [ + { + path: '', + loadComponent: () => DummyComponent, + ɵentryName: 'pricing-page', + } as Route, + ], + ɵentryName: 'pricing-routes', + } as Route, + ], + }, + ], + }, + { + path: 'es', + children: [ + { + path: '', + pathMatch: 'full', + loadChildren: () => [ + { + path: '', + loadComponent: () => DummyComponent, + ɵentryName: 'home-page', + } as Route, + ], + ɵentryName: 'home-routes', + } as Route, + ], + }, + ], + [{ path: '**', renderMode: RenderMode.Prerender }], + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + { + 'home-routes': ['chunk-home-routes.js'], + 'home-page': ['chunk-home-page.js'], + 'pricing-routes': ['chunk-pricing-routes.js'], + 'pricing-page': ['chunk-pricing-page.js'], + }, + ); + + const { routeTree, errors } = await extractRoutesAndCreateRouteTree({ url }); + expect(errors).toHaveSize(0); + expect(routeTree.toObject()).toEqual([ + { + route: '/', + renderMode: RenderMode.Prerender, + preload: ['chunk-home-routes.js', 'chunk-home-page.js'], + }, + { + route: '/pricing', + renderMode: RenderMode.Prerender, + preload: ['chunk-pricing-routes.js', 'chunk-pricing-page.js'], + }, + { + route: '/es', + renderMode: RenderMode.Prerender, + preload: ['chunk-home-routes.js', 'chunk-home-page.js'], + }, + ]); + }); }); diff --git a/packages/angular/ssr/test/testing-utils.ts b/packages/angular/ssr/test/testing-utils.ts index 6f825507c7a3..dad622d2e802 100644 --- a/packages/angular/ssr/test/testing-utils.ts +++ b/packages/angular/ssr/test/testing-utils.ts @@ -17,7 +17,7 @@ import { bootstrapApplication } from '@angular/platform-browser'; import { RouterOutlet, Routes, provideRouter } from '@angular/router'; import { type CompactPlan, compileSheet, encodePlan } from 'beasties/compiler'; import { destroyAngularServerApp } from '../src/app'; -import { ServerAsset, setAngularAppManifest } from '../src/manifest'; +import { AngularAppManifest, ServerAsset, setAngularAppManifest } from '../src/manifest'; import { ServerRoute, provideServerRendering, withRoutes } from '../src/routes/route-config'; @Component({ @@ -44,6 +44,7 @@ class AppComponent {} * root component and all its children. * @param inlineCriticalCss - An optional record of stylesheet paths to CSS content to be compiled into critical CSS plans. * @param nonce - An optional Content Security Policy (CSP) nonce to be used for inlined critical CSS. + * @param entryPointToBrowserMapping - An optional mapping of entry-point names to their associated browser bundles. */ export function setAngularAppTestingManifest( routes: Routes, @@ -55,6 +56,7 @@ export function setAngularAppTestingManifest( extraProviders: Array = [], inlineCriticalCss?: Record, nonce?: string, + entryPointToBrowserMapping?: AngularAppManifest['entryPointToBrowserMapping'], ): void { destroyAngularServerApp(); @@ -70,6 +72,7 @@ export function setAngularAppTestingManifest( setAngularAppManifest({ criticalCssPlans, nonce, + entryPointToBrowserMapping, baseHref, locale, assets: { From 639d31f11b102a12776ae8dce6369d6edd1b6ff3 Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Wed, 14 Oct 2026 08:38:24 +0200 Subject: [PATCH 29/52] feat(@schematics/angular): add use-library-builder migration to migrate from ng-packagr Adds an optional migration for v22.3.0 to migrate library projects from ng-packagr to the @angular/build:library builder. --- .../migrations/migration-collection.json | 7 + .../use-library-builder/migration.ts | 587 ++++++++++++++++++ .../use-library-builder/migration_spec.ts | 430 +++++++++++++ .../angular/utility/workspace-models.ts | 1 + 4 files changed, 1025 insertions(+) create mode 100644 packages/schematics/angular/migrations/use-library-builder/migration.ts create mode 100644 packages/schematics/angular/migrations/use-library-builder/migration_spec.ts diff --git a/packages/schematics/angular/migrations/migration-collection.json b/packages/schematics/angular/migrations/migration-collection.json index db1b95f987ef..9147e229b97c 100644 --- a/packages/schematics/angular/migrations/migration-collection.json +++ b/packages/schematics/angular/migrations/migration-collection.json @@ -29,6 +29,13 @@ "version": "22.0.0", "factory": "./update-workspace-config/migration", "description": "Update the angular workspace configuration." + }, + "use-library-builder": { + "version": "22.3.0", + "factory": "./use-library-builder/migration", + "description": "Migrate library projects from 'ng-packagr' to the new '@angular/build:library' builder.", + "optional": true, + "recommended": false } } } diff --git a/packages/schematics/angular/migrations/use-library-builder/migration.ts b/packages/schematics/angular/migrations/use-library-builder/migration.ts new file mode 100644 index 000000000000..68f9e8738e25 --- /dev/null +++ b/packages/schematics/angular/migrations/use-library-builder/migration.ts @@ -0,0 +1,587 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { type JsonObject, type JsonValue, isJsonObject } from '@angular-devkit/core'; +import { + type Rule, + type SchematicContext, + SchematicsException, + type Tree, + chain, +} from '@angular-devkit/schematics'; +import { dirname, join, normalize, relative } from 'node:path/posix'; +import { + DependencyType, + ExistingBehavior, + addDependency, + removeDependency, +} from '../../utility/dependency'; +import { JSONFile } from '../../utility/json-file'; +import { latestVersions } from '../../utility/latest-versions'; +import { + type TargetDefinition, + allTargetOptions, + allWorkspaceTargets, + updateWorkspace, +} from '../../utility/workspace'; +import { Builders, ProjectType } from '../../utility/workspace-models'; + +/** + * Represents the configuration structure of an `ng-package.json` file or + * the `ngPackage` section within a `package.json` file. + */ +interface NgPackageConfig { + dest?: string; + assets?: (string | { glob: string; input: string; output: string })[]; + allowedNonPeerDependencies?: string[]; + inlineStyleLanguage?: string; + keepLifecycleScripts?: boolean; + deleteDestPath?: boolean; + lib?: { + entryFile?: string; + styleIncludePaths?: string[]; + sass?: { + fatalDeprecations?: string[]; + silenceDeprecations?: string[]; + futureDeprecations?: string[]; + }; + }; +} + +/** + * Metadata describing a discovered secondary entry point in a library project. + */ +interface SecondaryEntryPoint { + subpath: string; + entryPoint: string; + configFile: string; +} + +/** + * Normalizes a workspace-relative POSIX path, converting `'.'` or `'/'` to `''`. + * + * @param path The path string to normalize. + * @returns The normalized workspace-relative path. + */ +function normalizeRelativePath(path: string): string { + const normalized = normalize(path).replace(/^\/+|\/+$/g, ''); + + return normalized === '.' ? '' : normalized; +} + +/** + * Reads and parses an `ng-packagr` configuration from either an `ng-package.json` + * file or the `ngPackage` property of a `package.json` file. + * + * @param tree The virtual file system tree. + * @param filePath The workspace-relative path to the configuration file. + * @returns The parsed `NgPackageConfig`, or `undefined` if the file does not exist or cannot be parsed. + */ +function parseNgPackageFile(tree: Tree, filePath: string): NgPackageConfig | undefined { + if (!tree.exists(filePath)) { + return undefined; + } + + try { + const json = new JSONFile(tree, filePath); + if (filePath.endsWith('/package.json') || filePath === 'package.json') { + const ngPackage = json.get(['ngPackage']) as JsonValue; + + return isJsonObject(ngPackage) ? (ngPackage as NgPackageConfig) : undefined; + } + + const content = json.get([]) as JsonValue; + + return isJsonObject(content) ? (content as NgPackageConfig) : undefined; + } catch { + return undefined; + } +} + +/** + * Resolves the TypeScript entry file path for a library entry point directory. + * Uses the explicitly configured `entryFile` when provided, or checks common + * default locations. + * + * @param tree The virtual file system tree. + * @param dir The directory of the primary or secondary entry point. + * @param configuredEntry The optional `lib.entryFile` path from `ng-package.json`. + * @returns The resolved entry file path relative to `dir`. + */ +function resolveEntryFile(tree: Tree, dir: string, configuredEntry?: string): string { + if (configuredEntry) { + return configuredEntry; + } + + const candidates = [ + 'src/public-api.ts', + 'src/public_api.ts', + 'public-api.ts', + 'public_api.ts', + 'src/index.ts', + 'index.ts', + ]; + + for (const candidate of candidates) { + if (tree.exists(join(dir, candidate))) { + return candidate; + } + } + + throw new SchematicsException( + `Could not find an entry file for library entry point at "${dir || '.'}".`, + ); +} + +/** + * Traverses a library project directory to discover all secondary entry points + * defined by nested `ng-package.json` files or `package.json` files containing an `ngPackage` field. + * + * @param tree The virtual file system tree. + * @param projectRoot The root directory of the library project. + * @param primaryProjectFile The workspace-relative path to the primary `ng-packagr` configuration file. + * @returns An array of discovered secondary entry points. + */ +function findSecondaryEntryPoints( + tree: Tree, + projectRoot: string, + primaryProjectFile: string, +): SecondaryEntryPoint[] { + const secondaryEntryPoints: SecondaryEntryPoint[] = []; + const normalizedRoot = normalizeRelativePath(projectRoot); + const normalizedPrimary = primaryProjectFile ? normalizeRelativePath(primaryProjectFile) : ''; + const rootDir = tree.getDir(normalizedRoot); + const directories = [rootDir]; + + for (const current of directories) { + const currentPath = normalizeRelativePath(current.path); + + if (currentPath !== normalizedRoot) { + const ngPackageJsonPath = join(currentPath, 'ng-package.json'); + const packageJsonPath = join(currentPath, 'package.json'); + + if ( + current.subfiles.some((f) => f === 'ng-package.json') && + ngPackageJsonPath !== normalizedPrimary + ) { + const config = parseNgPackageFile(tree, ngPackageJsonPath); + const subpath = relative(normalizedRoot, currentPath); + const entryFile = resolveEntryFile(tree, currentPath, config?.lib?.entryFile); + secondaryEntryPoints.push({ + subpath, + entryPoint: join(currentPath, entryFile), + configFile: ngPackageJsonPath, + }); + } else if ( + current.subfiles.some((f) => f === 'package.json') && + packageJsonPath !== normalizedPrimary + ) { + const config = parseNgPackageFile(tree, packageJsonPath); + if (config) { + const subpath = relative(normalizedRoot, currentPath); + const entryFile = resolveEntryFile(tree, currentPath, config.lib?.entryFile); + secondaryEntryPoints.push({ + subpath, + entryPoint: join(currentPath, entryFile), + configFile: packageJsonPath, + }); + } + } + } + + for (const subdir of current.subdirs) { + if ( + subdir === 'node_modules' || + subdir === 'dist' || + subdir === 'out-tsc' || + subdir.startsWith('.') + ) { + continue; + } + directories.push(current.dir(subdir)); + } + } + + return secondaryEntryPoints; +} + +/** + * Transfers `ng-packagr` configuration options onto the library's `build` target in `angular.json`. + * + * @param projectRoot The normalized root directory of the library project. + * @param projectDir The directory containing the primary `ng-packagr` configuration file. + * @param buildTarget The library's `build` target definition in `angular.json`. + * @param ngPackageConfig The parsed `NgPackageConfig`, if available. + * @param tree The virtual file system tree. + */ +function migrateTargetOptions( + projectRoot: string, + projectDir: string, + buildTarget: TargetDefinition, + ngPackageConfig: NgPackageConfig | undefined, + tree: Tree, +): void { + buildTarget.builder = Builders.BuildLibrary; + buildTarget.options ??= {}; + + const devTsConfig = buildTarget.configurations?.['development']?.['tsConfig']; + if (typeof buildTarget.options['tsConfig'] !== 'string') { + if (typeof devTsConfig === 'string') { + buildTarget.options['tsConfig'] = devTsConfig; + delete buildTarget.configurations?.['development']?.['tsConfig']; + } else if (tree.exists(join(projectRoot, 'tsconfig.lib.json'))) { + buildTarget.options['tsConfig'] = join(projectRoot, 'tsconfig.lib.json'); + } + } else if (devTsConfig === buildTarget.options['tsConfig']) { + delete buildTarget.configurations?.['development']?.['tsConfig']; + } + + if (ngPackageConfig?.dest && typeof buildTarget.options['outputPath'] !== 'string') { + buildTarget.options['outputPath'] = join(projectDir, ngPackageConfig.dest); + } + + if (ngPackageConfig?.assets?.length) { + const existingAssets = Array.isArray(buildTarget.options['assets']) + ? buildTarget.options['assets'] + : []; + const migratedAssets = ngPackageConfig.assets.map((asset) => { + if (typeof asset === 'string') { + return join(projectDir, asset); + } + if (isJsonObject(asset) && typeof asset['input'] === 'string') { + return { + ...asset, + input: join(projectDir, asset['input']), + }; + } + + return asset; + }); + buildTarget.options['assets'] = [...existingAssets, ...migratedAssets]; + } + + if (ngPackageConfig?.lib?.styleIncludePaths?.length || ngPackageConfig?.lib?.sass) { + const stylePreprocessorOptions = buildTarget.options['stylePreprocessorOptions']; + const existingPreprocessorOptions: JsonObject = + stylePreprocessorOptions && isJsonObject(stylePreprocessorOptions) + ? { ...stylePreprocessorOptions } + : {}; + + if (ngPackageConfig.lib.styleIncludePaths?.length) { + const existingIncludePaths = Array.isArray(existingPreprocessorOptions['includePaths']) + ? (existingPreprocessorOptions['includePaths'] as string[]) + : []; + const migratedIncludePaths = ngPackageConfig.lib.styleIncludePaths.map((p) => + join(projectDir, p), + ); + existingPreprocessorOptions['includePaths'] = [ + ...existingIncludePaths, + ...migratedIncludePaths, + ]; + } + if (ngPackageConfig.lib.sass) { + existingPreprocessorOptions['sass'] = ngPackageConfig.lib.sass; + } + + buildTarget.options['stylePreprocessorOptions'] = existingPreprocessorOptions; + } + + if (ngPackageConfig?.allowedNonPeerDependencies?.length) { + buildTarget.options['allowedNonPeerDependencies'] = ngPackageConfig.allowedNonPeerDependencies; + } + if (ngPackageConfig?.inlineStyleLanguage) { + buildTarget.options['inlineStyleLanguage'] = ngPackageConfig.inlineStyleLanguage; + } + if (ngPackageConfig?.keepLifecycleScripts !== undefined) { + buildTarget.options['keepLifecycleScripts'] = ngPackageConfig.keepLifecycleScripts; + } + if (ngPackageConfig?.deleteDestPath !== undefined) { + buildTarget.options['deleteOutputPath'] = ngPackageConfig.deleteDestPath; + } + + for (const [, options] of allTargetOptions(buildTarget, false)) { + delete options['project']; + } + + // Configure development configuration with full compilation mode unless already specified in tsconfig + buildTarget.configurations ??= {}; + buildTarget.configurations['development'] ??= {}; + + const effectiveDevTsConfig = + typeof buildTarget.configurations['development']['tsConfig'] === 'string' + ? buildTarget.configurations['development']['tsConfig'] + : typeof buildTarget.options['tsConfig'] === 'string' + ? buildTarget.options['tsConfig'] + : undefined; + + let hasDevTsConfigCompilationMode = false; + if (effectiveDevTsConfig && tree.exists(effectiveDevTsConfig)) { + try { + const tsConfigJson = new JSONFile(tree, effectiveDevTsConfig); + hasDevTsConfigCompilationMode = + tsConfigJson.get(['angularCompilerOptions', 'compilationMode']) !== undefined; + } catch { + // Ignore parse errors + } + } + + if (!hasDevTsConfigCompilationMode) { + buildTarget.configurations['development']['compilationMode'] ??= 'full'; + } +} + +/** + * Migrates a single library project's `build` target from `ng-packagr` to `@angular/build:library`, + * transferring configuration options to `angular.json`, writing entry points to `package.json#exports`, + * and cleaning up obsolete `ng-packagr` configuration files. + * + * @param projectRoot The root directory of the library project. + * @param buildTarget The library's `build` target definition in `angular.json`. + * @param tree The virtual file system tree. + * @param context The schematic execution context. + * @returns `true` if the library target was migrated, or `false` if it was skipped. + */ +function updateLibraryTarget( + projectRoot: string, + buildTarget: TargetDefinition, + tree: Tree, + context: SchematicContext, +): boolean { + const normalizedProjectRoot = normalizeRelativePath(projectRoot); + let primaryProjectFile = + typeof buildTarget.options?.['project'] === 'string' + ? normalizeRelativePath(buildTarget.options['project']) + : ''; + if (!primaryProjectFile) { + for (const [, options] of allTargetOptions(buildTarget, true)) { + if (typeof options['project'] === 'string') { + primaryProjectFile = normalizeRelativePath(options['project']); + break; + } + } + } + if (!primaryProjectFile) { + const defaultNgPackageJson = join(normalizedProjectRoot, 'ng-package.json'); + const defaultPackageJson = join(normalizedProjectRoot, 'package.json'); + if (tree.exists(defaultNgPackageJson)) { + primaryProjectFile = defaultNgPackageJson; + } else if (tree.exists(defaultPackageJson)) { + primaryProjectFile = defaultPackageJson; + } + } + + if (/\.[cm]?js$/.test(primaryProjectFile)) { + context.logger.warn( + `Skipping project at "${projectRoot}" because JavaScript ng-packagr ` + + `configuration files ("${primaryProjectFile}") cannot be automatically migrated.`, + ); + + return false; + } + + const ngPackageConfig = primaryProjectFile + ? parseNgPackageFile(tree, primaryProjectFile) + : undefined; + + const projectDir = primaryProjectFile + ? normalizeRelativePath(dirname(primaryProjectFile)) + : normalizedProjectRoot; + const primaryEntryFile = resolveEntryFile(tree, projectDir, ngPackageConfig?.lib?.entryFile); + const primaryEntryFilePath = join(projectDir, primaryEntryFile); + const secondaryEntryPoints = findSecondaryEntryPoints( + tree, + normalizedProjectRoot, + primaryProjectFile, + ); + + const toRelativeExportPath = (filePath: string): string => { + const rel = relative(normalizedProjectRoot, filePath); + + return rel.startsWith('./') || rel.startsWith('../') ? rel : `./${rel}`; + }; + + const entryPointExports: Record = { + '.': toRelativeExportPath(primaryEntryFilePath), + }; + for (const secondary of secondaryEntryPoints) { + const exportKey = + secondary.subpath.startsWith('./') || secondary.subpath.startsWith('../') + ? secondary.subpath + : `./${secondary.subpath}`; + entryPointExports[exportKey] = toRelativeExportPath(secondary.entryPoint); + } + + migrateTargetOptions(normalizedProjectRoot, projectDir, buildTarget, ngPackageConfig, tree); + + const packageJsonPath = join(normalizedProjectRoot, 'package.json'); + + // Delete primary ng-package.json if it exists + if ( + primaryProjectFile && + primaryProjectFile.endsWith('ng-package.json') && + tree.exists(primaryProjectFile) + ) { + tree.delete(primaryProjectFile); + } else if ( + primaryProjectFile && + primaryProjectFile !== packageJsonPath && + (primaryProjectFile.endsWith('/package.json') || primaryProjectFile === 'package.json') && + tree.exists(primaryProjectFile) + ) { + const json = new JSONFile(tree, primaryProjectFile); + json.remove(['ngPackage']); + } + + // Update library package.json with exports and remove ngPackage + if (tree.exists(packageJsonPath)) { + updateLibraryPackageJson(tree, packageJsonPath, entryPointExports); + } + + // Delete secondary configuration files + for (const secondary of secondaryEntryPoints) { + if (secondary.configFile.endsWith('ng-package.json') && tree.exists(secondary.configFile)) { + tree.delete(secondary.configFile); + } else if ( + (secondary.configFile.endsWith('/package.json') || secondary.configFile === 'package.json') && + tree.exists(secondary.configFile) + ) { + const json = new JSONFile(tree, secondary.configFile); + json.remove(['ngPackage']); + const remaining = json.get([]) as JsonValue; + if ( + isJsonObject(remaining) && + Object.keys(remaining).filter((k) => k !== '$schema').length === 0 + ) { + tree.delete(secondary.configFile); + } + } + } + + context.logger.info( + `Updated project at "${projectRoot}" to use the new '@angular/build:library' builder with ${ + Object.keys(entryPointExports).length + } entry point(s).`, + ); + + return true; +} + +/** + * Updates the library's `package.json` file by removing the legacy `ngPackage` configuration + * and `tslib` dependency, and merging the discovered entry points into the `exports` map. + * + * @param tree The virtual file system tree. + * @param packageJsonPath The workspace-relative path to the library's `package.json`. + * @param entryPointExports Map of export subpaths to relative entry file paths. + */ +function updateLibraryPackageJson( + tree: Tree, + packageJsonPath: string, + entryPointExports: Record, +): void { + const json = new JSONFile(tree, packageJsonPath); + json.remove(['ngPackage']); + + for (const depType of [ + 'dependencies', + 'peerDependencies', + 'devDependencies', + 'optionalDependencies', + ]) { + json.remove([depType, 'tslib']); + const deps = json.get([depType]) as JsonValue; + if (isJsonObject(deps) && Object.keys(deps).length === 0) { + json.remove([depType]); + } + } + + const existingExports = json.get(['exports']) as JsonValue; + let existingExportsObj: Record = {}; + if (isJsonObject(existingExports)) { + const keys = Object.keys(existingExports); + if (keys.some((k) => k.startsWith('.'))) { + existingExportsObj = existingExports; + } else if (keys.length > 0) { + existingExportsObj = { '.': existingExports }; + } + } + + const updatedExports: Record = { + ...existingExportsObj, + }; + + for (const [subpath, targetPath] of Object.entries(entryPointExports)) { + const current = updatedExports[subpath]; + if (current && isJsonObject(current)) { + updatedExports[subpath] = { + ...current, + default: targetPath, + }; + } else { + updatedExports[subpath] = targetPath; + } + } + + json.modify(['exports'], updatedExports); +} + +/** + * Migration main entrypoint for use-library-builder. + */ +export default function (): Rule { + return (tree, context) => + updateWorkspace((workspace) => { + let hasMigratedLibrary = false; + + for (const [, project] of workspace.projects) { + if (project.extensions.projectType !== ProjectType.Library) { + continue; + } + + const buildTarget = project.targets.get('build'); + if ( + !buildTarget || + buildTarget.builder === Builders.BuildLibrary || + (buildTarget.builder !== Builders.NgPackagr && + buildTarget.builder !== Builders.BuildNgPackagr) + ) { + continue; + } + + if (updateLibraryTarget(project.root, buildTarget, tree, context)) { + hasMigratedLibrary = true; + } + } + + if (!hasMigratedLibrary) { + return; + } + + const rules: Rule[] = [ + addDependency('@angular/build', latestVersions.AngularBuild, { + type: DependencyType.Dev, + existing: ExistingBehavior.Skip, + }), + ]; + + // Check if any targets still use ng-packagr across the workspace + let hasNgPackagrUsage = false; + for (const [, target] of allWorkspaceTargets(workspace)) { + if (target.builder === Builders.NgPackagr || target.builder === Builders.BuildNgPackagr) { + hasNgPackagrUsage = true; + break; + } + } + + if (!hasNgPackagrUsage) { + rules.push(removeDependency('ng-packagr')); + } + + return chain(rules); + }); +} diff --git a/packages/schematics/angular/migrations/use-library-builder/migration_spec.ts b/packages/schematics/angular/migrations/use-library-builder/migration_spec.ts new file mode 100644 index 000000000000..11192f8e5897 --- /dev/null +++ b/packages/schematics/angular/migrations/use-library-builder/migration_spec.ts @@ -0,0 +1,430 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { EmptyTree } from '@angular-devkit/schematics'; +import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; +import { Builders, ProjectType, type WorkspaceSchema } from '../../utility/workspace-models'; + +function createWorkspaceConfig(tree: UnitTestTree) { + const angularConfig: WorkspaceSchema = { + version: 1, + projects: { + 'my-lib': { + root: 'projects/my-lib', + sourceRoot: 'projects/my-lib/src', + projectType: ProjectType.Library, + prefix: 'lib', + architect: { + build: { + builder: Builders.NgPackagr, + options: { + project: 'projects/my-lib/ng-package.json', + tsConfig: 'projects/my-lib/tsconfig.lib.json', + }, + configurations: { + production: { + tsConfig: 'projects/my-lib/tsconfig.lib.prod.json', + }, + }, + }, + }, + }, + }, + }; + + tree.create('/angular.json', JSON.stringify(angularConfig, undefined, 2)); + tree.create( + '/package.json', + JSON.stringify( + { + devDependencies: { + 'ng-packagr': '^18.0.0', + }, + }, + undefined, + 2, + ), + ); + tree.create( + '/projects/my-lib/package.json', + JSON.stringify( + { + name: 'my-lib', + version: '0.0.1', + dependencies: { + tslib: '^2.3.0', + }, + }, + undefined, + 2, + ), + ); + tree.create( + '/projects/my-lib/ng-package.json', + JSON.stringify( + { + dest: '../../dist/my-lib', + lib: { + entryFile: 'src/public-api.ts', + }, + }, + undefined, + 2, + ), + ); +} + +describe('Migration to use the library builder', () => { + const schematicName = 'use-library-builder'; + const schematicRunner = new SchematicTestRunner( + 'migrations', + require.resolve('../migration-collection.json'), + ); + + let tree: UnitTestTree; + beforeEach(() => { + tree = new UnitTestTree(new EmptyTree()); + createWorkspaceConfig(tree); + }); + + it('should migrate library project using ng-packagr to @angular/build:library', async () => { + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const { + projects: { 'my-lib': lib }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } = newTree.readJson('/angular.json') as any; + + const { builder, options, configurations } = lib.architect['build']; + expect(builder).toBe(Builders.BuildLibrary); + expect(options.project).toBeUndefined(); + expect(options.entryPoints).toBeUndefined(); + expect(options.tsConfig).toBe('projects/my-lib/tsconfig.lib.json'); + expect(options.outputPath).toBe('dist/my-lib'); + expect(configurations.development).toEqual({ + compilationMode: 'full', + }); + + const libPkg = newTree.readJson('/projects/my-lib/package.json') as { + dependencies: unknown; + exports: unknown; + }; + expect(libPkg.dependencies).toBeUndefined(); + expect(libPkg.exports).toEqual({ + '.': './src/public-api.ts', + }); + + expect(newTree.exists('/projects/my-lib/ng-package.json')).toBe(false); + }); + + it('should migrate @angular/build:ng-packagr and promote tsConfig from development configuration', async () => { + const angularJson = JSON.parse(tree.readContent('/angular.json')); + angularJson.projects['my-lib'].architect.build = { + builder: Builders.BuildNgPackagr, + configurations: { + production: { + tsConfig: 'projects/my-lib/tsconfig.lib.prod.json', + }, + development: { + tsConfig: 'projects/my-lib/tsconfig.lib.json', + }, + }, + }; + tree.overwrite('/angular.json', JSON.stringify(angularJson, undefined, 2)); + + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const { + projects: { 'my-lib': lib }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } = newTree.readJson('/angular.json') as any; + + const { builder, options, configurations } = lib.architect['build']; + expect(builder).toBe(Builders.BuildLibrary); + expect(options.tsConfig).toBe('projects/my-lib/tsconfig.lib.json'); + expect(configurations.development).toEqual({ + compilationMode: 'full', + }); + }); + + it('should not set compilationMode in development configuration if already defined in tsconfig.lib.json', async () => { + tree.create( + '/projects/my-lib/tsconfig.lib.json', + JSON.stringify( + { + compilerOptions: { + declaration: true, + declarationMap: true, + }, + angularCompilerOptions: { + compilationMode: 'partial', + }, + }, + undefined, + 2, + ), + ); + + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const { + projects: { 'my-lib': lib }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } = newTree.readJson('/angular.json') as any; + + const { configurations } = lib.architect['build']; + expect(configurations.development).toEqual({}); + }); + + it('should discover and migrate secondary entry points into package.json exports', async () => { + tree.create( + '/projects/my-lib/testing/ng-package.json', + JSON.stringify( + { + lib: { + entryFile: 'src/public-api.ts', + }, + }, + undefined, + 2, + ), + ); + tree.create( + '/projects/my-lib/schematics/package.json', + JSON.stringify( + { + ngPackage: { + lib: { + entryFile: 'index.ts', + }, + }, + }, + undefined, + 2, + ), + ); + + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const { + projects: { 'my-lib': lib }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } = newTree.readJson('/angular.json') as any; + + const { options } = lib.architect['build']; + expect(options.entryPoints).toBeUndefined(); + + const libPkg = newTree.readJson('/projects/my-lib/package.json') as { exports: unknown }; + expect(libPkg.exports).toEqual({ + '.': './src/public-api.ts', + './schematics': './schematics/index.ts', + './testing': './testing/src/public-api.ts', + }); + + expect(newTree.exists('/projects/my-lib/testing/ng-package.json')).toBe(false); + expect(newTree.exists('/projects/my-lib/schematics/package.json')).toBe(false); + }); + + it('should preserve existing custom exports in package.json when adding entry points', async () => { + tree.overwrite( + '/projects/my-lib/package.json', + JSON.stringify( + { + name: 'my-lib', + version: '0.0.1', + exports: { + './theming': { + sass: './src/_theming.scss', + }, + }, + }, + undefined, + 2, + ), + ); + + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const libPkg = newTree.readJson('/projects/my-lib/package.json') as { exports: unknown }; + expect(libPkg.exports).toEqual({ + './theming': { + sass: './src/_theming.scss', + }, + '.': './src/public-api.ts', + }); + }); + + it('should preserve root condition-only exports in package.json', async () => { + tree.overwrite( + '/projects/my-lib/package.json', + JSON.stringify( + { + name: 'my-lib', + version: '0.0.1', + exports: { + sass: './src/_index.scss', + }, + }, + undefined, + 2, + ), + ); + + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const libPkg = newTree.readJson('/projects/my-lib/package.json') as { exports: unknown }; + expect(libPkg.exports).toEqual({ + '.': { + sass: './src/_index.scss', + default: './src/public-api.ts', + }, + }); + }); + + it('should migrate assets, styleIncludePaths, and sass options from ng-package.json', async () => { + tree.overwrite( + '/projects/my-lib/ng-package.json', + JSON.stringify( + { + dest: '../../dist/my-lib', + assets: ['CHANGELOG.md'], + allowedNonPeerDependencies: ['lodash-es'], + inlineStyleLanguage: 'scss', + keepLifecycleScripts: true, + deleteDestPath: false, + lib: { + entryFile: 'src/public-api.ts', + styleIncludePaths: ['../theme'], + sass: { + silenceDeprecations: ['import'], + }, + }, + }, + undefined, + 2, + ), + ); + + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const { + projects: { 'my-lib': lib }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } = newTree.readJson('/angular.json') as any; + + const { options } = lib.architect['build']; + expect(options.assets).toEqual(['projects/my-lib/CHANGELOG.md']); + expect(options.allowedNonPeerDependencies).toEqual(['lodash-es']); + expect(options.inlineStyleLanguage).toBe('scss'); + expect(options.keepLifecycleScripts).toBe(true); + expect(options.deleteOutputPath).toBe(false); + expect(options.stylePreprocessorOptions).toEqual({ + includePaths: ['projects/theme'], + sass: { + silenceDeprecations: ['import'], + }, + }); + }); + + it('should preserve existing stylePreprocessorOptions.includePaths when migrating styleIncludePaths', async () => { + const angularJson = JSON.parse(tree.readContent('/angular.json')); + angularJson.projects['my-lib'].architect.build.options.stylePreprocessorOptions = { + includePaths: ['existing/styles'], + }; + tree.overwrite('/angular.json', JSON.stringify(angularJson, undefined, 2)); + + tree.overwrite( + '/projects/my-lib/ng-package.json', + JSON.stringify( + { + lib: { + entryFile: 'src/public-api.ts', + styleIncludePaths: ['../theme'], + }, + }, + undefined, + 2, + ), + ); + + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const { + projects: { 'my-lib': lib }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } = newTree.readJson('/angular.json') as any; + + expect(lib.architect['build'].options.stylePreprocessorOptions).toEqual({ + includePaths: ['existing/styles', 'projects/theme'], + }); + }); + + it('should throw an error when entry file is not configured and no default candidate exists', async () => { + tree.overwrite('/projects/my-lib/ng-package.json', JSON.stringify({}, undefined, 2)); + + await expectAsync(schematicRunner.runSchematic(schematicName, {}, tree)).toBeRejectedWithError( + 'Could not find an entry file for library entry point at "projects/my-lib".', + ); + }); + + it('should migrate package.json with ngPackage configuration', async () => { + tree.overwrite( + '/projects/my-lib/package.json', + JSON.stringify( + { + name: 'my-lib', + ngPackage: { + lib: { + entryFile: 'src/public-api.ts', + }, + }, + }, + undefined, + 2, + ), + ); + + // Point angular.json to package.json + const angularJson = JSON.parse(tree.readContent('/angular.json')); + angularJson.projects['my-lib'].architect.build.options.project = 'projects/my-lib/package.json'; + tree.overwrite('/angular.json', JSON.stringify(angularJson, undefined, 2)); + + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const libPkg = newTree.readJson('/projects/my-lib/package.json') as { + ngPackage?: unknown; + name: string; + exports: unknown; + }; + expect(libPkg.ngPackage).toBeUndefined(); + expect(libPkg.name).toBe('my-lib'); + expect(libPkg.exports).toEqual({ + '.': './src/public-api.ts', + }); + }); + + it('should skip libraries with JavaScript ng-packagr config files and retain ng-packagr dependency', async () => { + const angularJson = JSON.parse(tree.readContent('/angular.json')); + angularJson.projects['my-lib'].architect.build.options.project = + 'projects/my-lib/ng-package.cjs'; + tree.overwrite('/angular.json', JSON.stringify(angularJson, undefined, 2)); + + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const { + projects: { 'my-lib': lib }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } = newTree.readJson('/angular.json') as any; + + expect(lib.architect['build'].builder).toBe(Builders.NgPackagr); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const rootPkg = newTree.readJson('/package.json') as any; + expect(rootPkg.devDependencies['ng-packagr']).toBeDefined(); + expect(rootPkg.devDependencies['@angular/build']).toBeUndefined(); + }); + + it('should remove ng-packagr and add @angular/build when no library uses ng-packagr', async () => { + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const rootPkg = newTree.readJson('/package.json') as any; + + expect(rootPkg.devDependencies['ng-packagr']).toBeUndefined(); + expect(rootPkg.devDependencies['@angular/build']).toBeDefined(); + }); +}); diff --git a/packages/schematics/angular/utility/workspace-models.ts b/packages/schematics/angular/utility/workspace-models.ts index d1ae1b146835..51c9c9dbdc9f 100644 --- a/packages/schematics/angular/utility/workspace-models.ts +++ b/packages/schematics/angular/utility/workspace-models.ts @@ -36,6 +36,7 @@ export enum Builders { ExtractI18n = '@angular-devkit/build-angular:extract-i18n', BuildExtractI18n = '@angular/build:extract-i18n', BuildApplication = '@angular/build:application', + BuildLibrary = '@angular/build:library', } export interface FileReplacements { From 6b94a2c904c647dcbdfab5a218aaf08e7eec7cf4 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Wed, 14 Oct 2026 09:36:09 +0000 Subject: [PATCH 30/52] refactor(@angular/build): add deleteFilesFromDisk utility and rename emit-files-to-disk Rename 'emit-files-to-disk.ts' to 'disk-files.ts' and introduce 'deleteFilesFromDisk' to delete removed output files with bounded concurrency. --- .../build/src/builders/application/index.ts | 12 +-- .../builders/library/pipeline/build-action.ts | 2 +- packages/angular/build/src/private.ts | 2 +- .../{emit-files-to-disk.ts => disk-files.ts} | 18 ++++- .../build/src/utils/disk-files_spec.ts | 75 +++++++++++++++++++ .../src/utils/emit-files-to-disk_spec.ts | 53 ------------- .../angular/build/src/utils/test-files.ts | 2 +- 7 files changed, 97 insertions(+), 67 deletions(-) rename packages/angular/build/src/utils/{emit-files-to-disk.ts => disk-files.ts} (79%) create mode 100644 packages/angular/build/src/utils/disk-files_spec.ts delete mode 100644 packages/angular/build/src/utils/emit-files-to-disk_spec.ts diff --git a/packages/angular/build/src/builders/application/index.ts b/packages/angular/build/src/builders/application/index.ts index f1b16a27e394..db2cee237896 100644 --- a/packages/angular/build/src/builders/application/index.ts +++ b/packages/angular/build/src/builders/application/index.ts @@ -8,13 +8,12 @@ import { Builder, BuilderContext, BuilderOutput, createBuilder } from '@angular-devkit/architect'; import assert from 'node:assert'; -import fs from 'node:fs/promises'; import path from 'node:path'; import { BuildOutputFileType } from '../../tools/esbuild/bundler-files'; import { createJsonBuildManifest } from '../../tools/esbuild/utils'; import { colors as ansiColors } from '../../utils/color'; import { deleteOutputDir } from '../../utils/delete-output-dir'; -import { emitFilesToDisk } from '../../utils/emit-files-to-disk'; +import { deleteFilesFromDisk, emitFilesToDisk } from '../../utils/disk-files'; import { bazelEsbuildPluginPath, useJSONBuildLogs } from '../../utils/environment-options'; import { isSubDirectory } from '../../utils/path'; import { purgeStaleBuildCache } from '../../utils/purge-cache'; @@ -215,13 +214,10 @@ export async function* buildApplication( // Delete any removed files if incremental if (result.kind === ResultKind.Incremental && result.removed?.length) { try { - await Promise.all( - result.removed.map((file) => { - const fullFilePath = generateFullPath(file.path, file.type, outputOptions); - - return fs.rm(fullFilePath, { force: true, maxRetries: 3 }); - }), + const filesToDelete = result.removed.map((file) => + generateFullPath(file.path, file.type, outputOptions), ); + await deleteFilesFromDisk(filesToDelete); } catch (error) { context.logger.error(error instanceof Error ? error.message : String(error)); yield { success: false }; diff --git a/packages/angular/build/src/builders/library/pipeline/build-action.ts b/packages/angular/build/src/builders/library/pipeline/build-action.ts index 6d40f5fe4383..acdc69c61bff 100644 --- a/packages/angular/build/src/builders/library/pipeline/build-action.ts +++ b/packages/angular/build/src/builders/library/pipeline/build-action.ts @@ -9,7 +9,7 @@ import type { BuilderContext } from '@angular-devkit/architect'; import path from 'node:path'; import type { ComponentStylesheetBundler } from '../../../tools/esbuild/angular/component-stylesheets'; -import { emitFilesToDisk } from '../../../utils/emit-files-to-disk'; +import { emitFilesToDisk } from '../../../utils/disk-files'; import { assertIsError } from '../../../utils/error'; import { toPosixPath } from '../../../utils/path'; import type { NormalizedLibraryOptions, SingleBuildState } from '../types'; diff --git a/packages/angular/build/src/private.ts b/packages/angular/build/src/private.ts index 6f98e4f8f0e9..e95ad26af3fc 100644 --- a/packages/angular/build/src/private.ts +++ b/packages/angular/build/src/private.ts @@ -72,7 +72,7 @@ export { ComponentStylesheetBundler } from './tools/esbuild/angular/component-st export * from './utils/bundle-calculator'; export { checkPort } from './utils/check-port'; export { deleteOutputDir } from './utils/delete-output-dir'; -export { emitFilesToDisk } from './utils/emit-files-to-disk'; +export { emitFilesToDisk } from './utils/disk-files'; export { type I18nOptions, createI18nOptions, loadTranslations } from './utils/i18n-options'; export { IndexHtmlGenerator, diff --git a/packages/angular/build/src/utils/emit-files-to-disk.ts b/packages/angular/build/src/utils/disk-files.ts similarity index 79% rename from packages/angular/build/src/utils/emit-files-to-disk.ts rename to packages/angular/build/src/utils/disk-files.ts index b6df74088451..dbbe34ee919e 100644 --- a/packages/angular/build/src/utils/emit-files-to-disk.ts +++ b/packages/angular/build/src/utils/disk-files.ts @@ -6,14 +6,14 @@ * found in the LICENSE file at https://angular.dev/license */ -import { constants, cp, mkdir, writeFile } from 'node:fs/promises'; +import { constants, cp, mkdir, rm, writeFile } from 'node:fs/promises'; import { dirname } from 'node:path'; import { runConcurrent } from './concurrency'; /** * Maximum number of concurrent file system write/copy operations to avoid open file descriptor exhaustion. */ -const MAX_CONCURRENT_WRITES = 64; +const MAX_CONCURRENT_OPS = 64; /** * Represents a file that can be emitted to disk from memory or copied from an existing path on disk. @@ -38,7 +38,7 @@ export async function emitFilesToDisk( const directoryCreationPromises = new Map>(); - await runConcurrent(files, MAX_CONCURRENT_WRITES, async (file) => { + await runConcurrent(files, MAX_CONCURRENT_OPS, async (file) => { const fullFilePath = resolveDestinationPath(file); if (!fullFilePath) { return; @@ -69,3 +69,15 @@ export async function emitFilesToDisk( }); }); } + +/** + * Deletes a collection of files from disk with bounded concurrency. + * @param files The collection of files to delete. + */ +export async function deleteFilesFromDisk(files: readonly string[]): Promise { + if (files.length === 0) { + return; + } + + await runConcurrent(files, MAX_CONCURRENT_OPS, (file) => rm(file, { force: true })); +} diff --git a/packages/angular/build/src/utils/disk-files_spec.ts b/packages/angular/build/src/utils/disk-files_spec.ts new file mode 100644 index 000000000000..4a9422bd4373 --- /dev/null +++ b/packages/angular/build/src/utils/disk-files_spec.ts @@ -0,0 +1,75 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import assert from 'node:assert'; +import { existsSync } from 'node:fs'; +import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import { type EmittableFile, deleteFilesFromDisk, emitFilesToDisk } from './disk-files'; + +describe('disk-files', () => { + let tempRoot: string; + + beforeEach(async () => { + const baseTmpDir = process.env['TEST_TMPDIR']; + assert(baseTmpDir, 'TEST_TMPDIR is not set'); + tempRoot = await mkdtemp(join(baseTmpDir, 'angular-cli-disk-files-test-')); + }); + + afterEach(async () => { + if (tempRoot) { + await rm(tempRoot, { recursive: true, force: true }); + } + }); + + describe('emitFilesToDisk', () => { + it('should write memory files and copy disk files while creating nested directories', async () => { + const sourceFile = join(tempRoot, 'source-asset.txt'); + await writeFile(sourceFile, 'from-disk'); + + const files: (EmittableFile & { path: string })[] = [ + { + origin: 'memory', + path: 'nested/a/mem1.txt', + contents: new TextEncoder().encode('mem-1'), + }, + { origin: 'memory', path: 'nested/a/mem2.txt', contents: 'mem-2' }, + { origin: 'disk', path: 'nested/b/disk1.txt', source: sourceFile }, + { origin: 'disk', path: 'nested/c/disk2.txt', source: sourceFile }, + { origin: 'memory', path: 'skipped/file.txt', contents: 'should-not-exist' }, + ]; + + const outDir = join(tempRoot, 'out'); + await emitFilesToDisk(files, (file) => + file.path.startsWith('skipped/') ? undefined : join(outDir, file.path), + ); + + expect(await readFile(join(outDir, 'nested/a/mem1.txt'), 'utf-8')).toBe('mem-1'); + expect(await readFile(join(outDir, 'nested/a/mem2.txt'), 'utf-8')).toBe('mem-2'); + expect(await readFile(join(outDir, 'nested/b/disk1.txt'), 'utf-8')).toBe('from-disk'); + expect(await readFile(join(outDir, 'nested/c/disk2.txt'), 'utf-8')).toBe('from-disk'); + expect(existsSync(join(outDir, 'skipped/file.txt'))).toBeFalse(); + }); + }); + + describe('deleteFilesFromDisk', () => { + it('should delete existing files and ignore non-existent files', async () => { + const fileA = join(tempRoot, 'a.txt'); + const fileB = join(tempRoot, 'b.txt'); + const nonExistent = join(tempRoot, 'missing.txt'); + + await writeFile(fileA, 'a'); + await writeFile(fileB, 'b'); + + await deleteFilesFromDisk([fileA, nonExistent]); + + expect(existsSync(fileA)).toBeFalse(); + expect(existsSync(fileB)).toBeTrue(); + }); + }); +}); diff --git a/packages/angular/build/src/utils/emit-files-to-disk_spec.ts b/packages/angular/build/src/utils/emit-files-to-disk_spec.ts deleted file mode 100644 index 028653028b43..000000000000 --- a/packages/angular/build/src/utils/emit-files-to-disk_spec.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import assert from 'node:assert'; -import { existsSync } from 'node:fs'; -import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; -import { join } from 'node:path'; -import { type EmittableFile, emitFilesToDisk } from './emit-files-to-disk'; - -describe('emitFilesToDisk', () => { - let tempRoot: string; - - beforeEach(async () => { - const baseTmpDir = process.env['TEST_TMPDIR']; - assert(baseTmpDir, 'TEST_TMPDIR is not set'); - tempRoot = await mkdtemp(join(baseTmpDir, 'angular-cli-emit-files-test-')); - }); - - afterEach(async () => { - if (tempRoot) { - await rm(tempRoot, { recursive: true, force: true }); - } - }); - - it('should write memory files and copy disk files while creating nested directories', async () => { - const sourceFile = join(tempRoot, 'source-asset.txt'); - await writeFile(sourceFile, 'from-disk'); - - const files: (EmittableFile & { path: string })[] = [ - { origin: 'memory', path: 'nested/a/mem1.txt', contents: new TextEncoder().encode('mem-1') }, - { origin: 'memory', path: 'nested/a/mem2.txt', contents: 'mem-2' }, - { origin: 'disk', path: 'nested/b/disk1.txt', source: sourceFile }, - { origin: 'disk', path: 'nested/c/disk2.txt', source: sourceFile }, - { origin: 'memory', path: 'skipped/file.txt', contents: 'should-not-exist' }, - ]; - - const outDir = join(tempRoot, 'out'); - await emitFilesToDisk(files, (file) => - file.path.startsWith('skipped/') ? undefined : join(outDir, file.path), - ); - - expect(await readFile(join(outDir, 'nested/a/mem1.txt'), 'utf-8')).toBe('mem-1'); - expect(await readFile(join(outDir, 'nested/a/mem2.txt'), 'utf-8')).toBe('mem-2'); - expect(await readFile(join(outDir, 'nested/b/disk1.txt'), 'utf-8')).toBe('from-disk'); - expect(await readFile(join(outDir, 'nested/c/disk2.txt'), 'utf-8')).toBe('from-disk'); - expect(existsSync(join(outDir, 'skipped/file.txt'))).toBeFalse(); - }); -}); diff --git a/packages/angular/build/src/utils/test-files.ts b/packages/angular/build/src/utils/test-files.ts index db480686b66a..763c762ac19f 100644 --- a/packages/angular/build/src/utils/test-files.ts +++ b/packages/angular/build/src/utils/test-files.ts @@ -9,7 +9,7 @@ import path from 'node:path'; import { ResultFile } from '../builders/application/results'; import { BuildOutputFileType } from '../tools/esbuild/bundler-files'; -import { emitFilesToDisk } from './emit-files-to-disk'; +import { emitFilesToDisk } from './disk-files'; /** * Writes a collection of build result files to a specified directory. From 01afbf418cf6a7688f3f131988eeba3cdac2bde4 Mon Sep 17 00:00:00 2001 From: Julien Venet Date: Tue, 13 Oct 2026 13:22:08 -0400 Subject: [PATCH 31/52] fix(@angular/build): sort discovered unit-test files for deterministic builds --- .../src/builders/unit-test/test-discovery.ts | 6 ++-- .../builders/unit-test/test-discovery_spec.ts | 34 ++++++++++++++++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/packages/angular/build/src/builders/unit-test/test-discovery.ts b/packages/angular/build/src/builders/unit-test/test-discovery.ts index f2fc8c221646..2452675a9abf 100644 --- a/packages/angular/build/src/builders/unit-test/test-discovery.ts +++ b/packages/angular/build/src/builders/unit-test/test-discovery.ts @@ -74,8 +74,10 @@ export async function findTests( } } - // 3. Combine and de-duplicate results - return [...resolvedTestFiles]; + // 3. Combine, de-duplicate and sort the results. The glob crawls directories asynchronously and + // returns matches in a varying order; the order feeds the build entry points, so an unsorted list + // makes the output (chunk contents and names) differ between two builds of the same sources. + return [...resolvedTestFiles].sort(); } interface TestEntrypointsOptions { diff --git a/packages/angular/build/src/builders/unit-test/test-discovery_spec.ts b/packages/angular/build/src/builders/unit-test/test-discovery_spec.ts index 764924d9552b..91c33fd0120a 100644 --- a/packages/angular/build/src/builders/unit-test/test-discovery_spec.ts +++ b/packages/angular/build/src/builders/unit-test/test-discovery_spec.ts @@ -6,8 +6,40 @@ * found in the LICENSE file at https://angular.dev/license */ +import assert from 'node:assert'; +import { promises as fs } from 'node:fs'; +import { join } from 'node:path'; import { initializeHash } from '../../utils/hash'; -import { generateNameFromPath, getTestEntrypoints } from './test-discovery'; +import { toPosixPath } from '../../utils/path'; +import { findTests, generateNameFromPath, getTestEntrypoints } from './test-discovery'; + +describe('findTests', () => { + let projectSourceRoot: string; + + beforeEach(async () => { + const baseTmpDir = process.env['TEST_TMPDIR']; + assert(baseTmpDir, 'TEST_TMPDIR is not set'); + projectSourceRoot = await fs.mkdtemp(join(baseTmpDir, 'angular-find-tests-')); + }); + + afterEach(async () => { + await fs.rm(projectSourceRoot, { recursive: true, force: true }); + }); + + it('should return the test files sorted, regardless of the crawl order', async () => { + const files = ['z/z.spec.ts', 'a/b/c.spec.ts', 'm.spec.ts', 'a/a.spec.ts', 'b/x/y.spec.ts']; + for (const file of files) { + const path = join(projectSourceRoot, file); + await fs.mkdir(join(path, '..'), { recursive: true }); + await fs.writeFile(path, ''); + } + + const result = await findTests(['**/*.spec.ts'], [], projectSourceRoot, projectSourceRoot); + + const expected = files.map((file) => toPosixPath(join(projectSourceRoot, file))).sort(); + expect(result).toEqual(expected); + }); +}); describe('getTestEntrypoints', () => { beforeAll(async () => { From b39a5fcdac288e317f3b00468c09173a1d306f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Turbi=C5=84ski?= Date: Tue, 13 Oct 2026 20:01:06 +0000 Subject: [PATCH 32/52] fix(@angular-devkit/schematics): avoid stack overflow when chaining many rules The chain rule nested one observable per rule, so subscribing to a chain of a few thousand rules exceeded the call stack and the result never settled. Each rule result is now awaited before the next rule runs. --- .../angular_devkit/schematics/src/rules/base.ts | 10 +++++----- .../schematics/src/rules/base_spec.ts | 13 +++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/packages/angular_devkit/schematics/src/rules/base.ts b/packages/angular_devkit/schematics/src/rules/base.ts index ec380f2aeb0d..1f5d3023c28e 100644 --- a/packages/angular_devkit/schematics/src/rules/base.ts +++ b/packages/angular_devkit/schematics/src/rules/base.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import { Observable, concat, map, mapTo, toArray } from 'rxjs'; +import { concat, lastValueFrom, map, mapTo, toArray } from 'rxjs'; import { FileOperator, Rule, Source } from '../engine/interface'; import { SchematicsException } from '../exception/exception'; import { FilterHostTree, HostTree } from '../tree/host-tree'; @@ -34,18 +34,18 @@ export function empty(): Source { */ export function chain(rules: Iterable | AsyncIterable): Rule { return async (initialTree, context) => { - let intermediateTree: Observable | undefined; + let intermediateTree = initialTree; if (Symbol.asyncIterator in rules) { for await (const rule of rules) { - intermediateTree = callRule(rule, intermediateTree ?? initialTree, context); + intermediateTree = await lastValueFrom(callRule(rule, intermediateTree, context)); } } else { for (const rule of rules) { - intermediateTree = callRule(rule, intermediateTree ?? initialTree, context); + intermediateTree = await lastValueFrom(callRule(rule, intermediateTree, context)); } } - return () => intermediateTree; + return intermediateTree; }; } diff --git a/packages/angular_devkit/schematics/src/rules/base_spec.ts b/packages/angular_devkit/schematics/src/rules/base_spec.ts index b3578ca8c00a..6eb299ef9890 100644 --- a/packages/angular_devkit/schematics/src/rules/base_spec.ts +++ b/packages/angular_devkit/schematics/src/rules/base_spec.ts @@ -140,6 +140,19 @@ describe('chain', () => { expect(rulesCalled[2]).toBe(tree2); expect(result).toBe(tree3); }); + + it('works with a large number of rules', async () => { + const tree0 = empty(); + let callCount = 0; + const rules: Rule[] = Array.from({ length: 20_000 }, () => () => { + callCount++; + }); + + const result = await lastValueFrom(callRule(chain(rules), tree0, context)); + + expect(result).toBe(tree0); + expect(callCount).toBe(20_000); + }); }); describe('apply', () => { From 7714a8537589afc6180443cc36acd5149a459c57 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Tue, 13 Oct 2026 09:44:41 -0400 Subject: [PATCH 33/52] fix(@angular/build): resolve unimported NgModule scopes when filtering unit-test files When `rootFiles` overrides are provided (such as during `unit-test` runs), the initial TypeScript program is restricted to those entry points and their transitive imports. If a test imports a non-standalone `@Component` directly without importing its declaring `@NgModule`, the `NgModule` may be omitted from the program and leave the component without its compilation scope. Preserve the full `tsconfig` root file set as `fallbackRootNames` for application builds when `rootFiles` is a subset of the `tsconfig` files. If AOT analysis detects a non-standalone component lacking an owning `NgModule` scope (`getOwningNgModule(component) === null`) and additional uncompiled `tsconfig` files exist, recreate and re-analyze the Angular program with the full root file set so all `NgModule` declarations can be discovered. --- .../unit-test/tests/options/include_spec.ts | 167 ++++++++++++++++++ .../compilation/angular-compilation_spec.ts | 79 ++++++++- .../angular/compilation/aot-compilation.ts | 102 ++++++++++- .../compilation/typescript-compilation.ts | 25 ++- 4 files changed, 364 insertions(+), 9 deletions(-) diff --git a/packages/angular/build/src/builders/unit-test/tests/options/include_spec.ts b/packages/angular/build/src/builders/unit-test/tests/options/include_spec.ts index d3d4e19a30f9..4ba7c9eaa051 100644 --- a/packages/angular/build/src/builders/unit-test/tests/options/include_spec.ts +++ b/packages/angular/build/src/builders/unit-test/tests/options/include_spec.ts @@ -110,5 +110,172 @@ describeBuilder(execute, UNIT_TEST_BUILDER_INFO, (harness) => { const { result } = await harness.executeOnce(); expect(result?.success).toBeTrue(); }); + + it('should not compile unimported application files when testing standalone code', async () => { + await harness.writeFiles({ + 'src/tsconfig.spec.json': JSON.stringify({ + extends: '../tsconfig.json', + compilerOptions: { + outDir: '../out-tsc/spec', + types: ['jasmine', '@angular/localize'], + }, + files: ['polyfills.ts'], + include: ['**/*.ts', '**/*.d.ts'], + }), + 'src/app/services/test.service.spec.ts': ` + describe('TestService', () => { + it('should succeed', () => { + expect(true).toBe(true); + }); + });`, + 'src/app/unused-broken.ts': ` + // This unimported file has a TypeScript error and should not be compiled for standalone tests + export const invalidNumber: number = 'not a number'; + `, + }); + + harness.useTarget('test', { + ...BASE_OPTIONS, + include: ['src/app/services/test.service.spec.ts'], + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + }); + + it('should resolve NgModule scope when testing a non-standalone component without importing the NgModule', async () => { + await harness.writeFiles({ + 'src/tsconfig.spec.json': JSON.stringify({ + extends: '../tsconfig.json', + compilerOptions: { + outDir: '../out-tsc/spec', + types: ['jasmine', '@angular/localize'], + }, + files: ['polyfills.ts'], + include: ['**/*.ts', '**/*.d.ts'], + }), + 'src/app/app.ts': ` + import { Component } from '@angular/core'; + + @Component({ + selector: 'app-root', + template: '

Hello, {{ title }}

', + standalone: false, + }) + export class App { + title = 'test'; + } + `, + 'src/app/app-module.ts': ` + import { NgModule } from '@angular/core'; + import { BrowserModule } from '@angular/platform-browser'; + import { RouterModule } from '@angular/router'; + import { App } from './app'; + + @NgModule({ + declarations: [App], + imports: [BrowserModule, RouterModule.forRoot([])], + bootstrap: [App], + }) + export class AppModule {} + `, + 'src/app/app.spec.ts': ` + import { TestBed } from '@angular/core/testing'; + import { RouterModule } from '@angular/router'; + import { App } from './app'; + + describe('App', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [RouterModule.forRoot([])], + declarations: [App], + }).compileComponents(); + }); + + it('should create the app', () => { + const fixture = TestBed.createComponent(App); + expect(fixture.componentInstance).toBeTruthy(); + }); + }); + `, + }); + + harness.useTarget('test', { + ...BASE_OPTIONS, + include: ['src/app/app.spec.ts'], + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + }); + + it('should not compile unimported files when a non-standalone component NgModule is imported by the test', async () => { + await harness.writeFiles({ + 'src/tsconfig.spec.json': JSON.stringify({ + extends: '../tsconfig.json', + compilerOptions: { + outDir: '../out-tsc/spec', + types: ['jasmine', '@angular/localize'], + }, + files: ['polyfills.ts'], + include: ['**/*.ts', '**/*.d.ts'], + }), + 'src/app/app.ts': ` + import { Component } from '@angular/core'; + + @Component({ + selector: 'app-root', + template: '

Hello, {{ title }}

', + standalone: false, + }) + export class App { + title = 'test'; + } + `, + 'src/app/app-module.ts': ` + import { NgModule } from '@angular/core'; + import { BrowserModule } from '@angular/platform-browser'; + import { RouterModule } from '@angular/router'; + import { App } from './app'; + + @NgModule({ + declarations: [App], + imports: [BrowserModule, RouterModule.forRoot([])], + bootstrap: [App], + }) + export class AppModule {} + `, + 'src/app/app.spec.ts': ` + import { TestBed } from '@angular/core/testing'; + import { App } from './app'; + import { AppModule } from './app-module'; + + describe('App', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [AppModule], + }).compileComponents(); + }); + + it('should create the app', () => { + const fixture = TestBed.createComponent(App); + expect(fixture.componentInstance).toBeTruthy(); + }); + }); + `, + 'src/app/unused-broken.ts': ` + // This unimported file has a TypeScript error and should not be compiled when AppModule is already imported + export const invalidNumber: number = 'not a number'; + `, + }); + + harness.useTarget('test', { + ...BASE_OPTIONS, + include: ['src/app/app.spec.ts'], + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + }); }); }); diff --git a/packages/angular/build/src/tools/angular/compilation/angular-compilation_spec.ts b/packages/angular/build/src/tools/angular/compilation/angular-compilation_spec.ts index 2d001dfeff7c..3c09b87f69d7 100644 --- a/packages/angular/build/src/tools/angular/compilation/angular-compilation_spec.ts +++ b/packages/angular/build/src/tools/angular/compilation/angular-compilation_spec.ts @@ -91,8 +91,12 @@ describe('AngularCompilation', () => { return this.sourceFiles; } - public async testLoadConfiguration(tsconfig: string, overrides?: CompilerOptionOverrides) { - return this.loadConfiguration(tsconfig, overrides); + public async testLoadConfiguration( + tsconfig: string, + overrides?: CompilerOptionOverrides, + buildType?: 'application' | 'library', + ) { + return this.loadConfiguration(tsconfig, overrides, buildType); } } @@ -162,12 +166,83 @@ describe('AngularCompilation', () => { jasmine.any(Map), ); expect(result.rootNames).toEqual(['/src/main.ts']); + expect(result.fallbackRootNames).toBeUndefined(); expect(result.compilerOptions.target).toBe(ts.ScriptTarget.ES2022); expect(result.compilerOptions.inlineSources).toBe(true); expect(result.warnings.length).toBeGreaterThan(0); expect(result.tsConfigFiles).toEqual(['tsconfig.json']); }); + it('filters rootNames to rootFiles while retaining ambient declaration files and setting fallbackRootNames', async () => { + const compilation = new MockTypeScriptCompilation(); + const mockReadConfig = jasmine.createSpy('readConfiguration').and.returnValue({ + options: { target: ts.ScriptTarget.ES2022 }, + rootNames: [ + '/src/app/included.spec.ts', + '/src/app/excluded.spec.ts', + '/src/app/app-module.ts', + '/src/env.d.ts', + '/src/types.d.mts', + '/src/legacy.d.cts', + ], + errors: [], + }); + spyOn(TypeScriptCompilation, 'loadCompilerCli').and.resolveTo({ + readConfiguration: mockReadConfig, + } as unknown as typeof import('@angular/compiler-cli')); + + const result = await compilation.testLoadConfiguration('tsconfig.spec.json', { + rootFiles: ['/src/app/included.spec.ts'], + }); + + expect(result.rootNames).toEqual([ + '/src/app/included.spec.ts', + '/src/env.d.ts', + '/src/types.d.mts', + '/src/legacy.d.cts', + ]); + expect(result.fallbackRootNames).toEqual([ + '/src/app/included.spec.ts', + '/src/app/excluded.spec.ts', + '/src/app/app-module.ts', + '/src/env.d.ts', + '/src/types.d.mts', + '/src/legacy.d.cts', + ]); + }); + + it('omits fallbackRootNames when buildType is "library" or when rootFiles covers all tsconfig files', async () => { + const compilation = new MockTypeScriptCompilation(); + const mockReadConfig = jasmine.createSpy('readConfiguration').and.returnValue({ + options: { target: ts.ScriptTarget.ES2022 }, + rootNames: ['/src/public-api.ts', '/src/internal.ts', '/src/env.d.ts'], + errors: [], + }); + spyOn(TypeScriptCompilation, 'loadCompilerCli').and.resolveTo({ + readConfiguration: mockReadConfig, + } as unknown as typeof import('@angular/compiler-cli')); + + const libraryResult = await compilation.testLoadConfiguration( + 'tsconfig.lib.json', + { rootFiles: ['/src/public-api.ts'] }, + 'library', + ); + expect(libraryResult.rootNames).toEqual(['/src/public-api.ts', '/src/env.d.ts']); + expect(libraryResult.fallbackRootNames).toBeUndefined(); + + const fullSetResult = await compilation.testLoadConfiguration( + 'tsconfig.app.json', + { rootFiles: ['/src/public-api.ts', '/src/internal.ts'] }, + 'application', + ); + expect(fullSetResult.rootNames).toEqual([ + '/src/public-api.ts', + '/src/internal.ts', + '/src/env.d.ts', + ]); + expect(fullSetResult.fallbackRootNames).toBeUndefined(); + }); + it('passes extendedConfigCache to readConfiguration and invalidates entries on config change', async () => { const compilation = new MockTypeScriptCompilation(); let passedCache: Map | undefined; diff --git a/packages/angular/build/src/tools/angular/compilation/aot-compilation.ts b/packages/angular/build/src/tools/angular/compilation/aot-compilation.ts index 749962e3def6..4ca1480f646c 100644 --- a/packages/angular/build/src/tools/angular/compilation/aot-compilation.ts +++ b/packages/angular/build/src/tools/angular/compilation/aot-compilation.ts @@ -72,6 +72,7 @@ class AngularCompilationState { public readonly useTypeScriptTranspilation: boolean, public readonly diagnosticCache = new WeakMap(), public readonly filesWithoutDtsSignature = new Set(), + public readonly useFallbackRootNames = false, ) {} get angularCompiler() { @@ -100,6 +101,7 @@ export class AotCompilation extends TypeScriptCompilation { const { compilerOptions, rootNames, + fallbackRootNames, errors: configurationDiagnostics, warnings, tsConfigFiles, @@ -165,13 +167,48 @@ export class AotCompilation extends TypeScriptCompilation { this.sourceFiles, ); + // If a previous watch rebuild already fell back to the full tsconfig root file set, + // start directly with fallbackRootNames to avoid repeating the two-step check. + let useFallbackRootNames = this.#state?.useFallbackRootNames ?? false; + // Create the Angular specific program that contains the Angular compiler - const angularProgram = profileSync( + let angularProgram = profileSync( 'NG_CREATE_PROGRAM', - () => new NgtscProgram(rootNames, compilerOptions, host, this.#state?.angularProgram), + () => + new NgtscProgram( + (useFallbackRootNames && fallbackRootNames) || rootNames, + compilerOptions, + host, + this.#state?.angularProgram, + ), ); - const angularCompiler = angularProgram.compiler; - const angularTypeScriptProgram = angularProgram.getTsProgram(); + let angularCompiler = angularProgram.compiler; + + await profileAsync('NG_ANALYZE_PROGRAM', () => angularCompiler.analyzeAsync()); + + let angularTypeScriptProgram = angularProgram.getTsProgram(); + + // When rootFiles filtering is active and a non-standalone component without a resolved + // NgModule scope is encountered, its declaring NgModule may not be directly imported by + // the test entry points. Fall back to the full tsconfig root file set if it contains + // additional uncompiled files so the Angular compiler can discover all NgModules and + // resolve component compilation scopes. + if ( + !useFallbackRootNames && + fallbackRootNames?.some((file) => !angularTypeScriptProgram.getSourceFile(file)) && + hasUnscopedComponent(angularCompiler) + ) { + useFallbackRootNames = true; + angularProgram = profileSync( + 'NG_CREATE_PROGRAM_FALLBACK', + () => new NgtscProgram(fallbackRootNames, compilerOptions, host, angularProgram), + ); + angularCompiler = angularProgram.compiler; + + await profileAsync('NG_ANALYZE_PROGRAM_FALLBACK', () => angularCompiler.analyzeAsync()); + angularTypeScriptProgram = angularProgram.getTsProgram(); + } + ensureSourceFileVersions(angularTypeScriptProgram); let oldProgram = this.#state?.typeScriptProgram; @@ -200,8 +237,6 @@ export class AotCompilation extends TypeScriptCompilation { } } - await profileAsync('NG_ANALYZE_PROGRAM', () => angularCompiler.analyzeAsync()); - let templateUpdates; if (useHmr && hostOptions.modifiedFiles && this.#state) { const componentNodes = collectHmrCandidates( @@ -315,6 +350,7 @@ export class AotCompilation extends TypeScriptCompilation { useTypeScriptTranspilation, this.#state?.diagnosticCache, filesWithoutDtsSignature, + useFallbackRootNames, ); return { @@ -810,3 +846,57 @@ function populatePreviousDtsSignatures( compilerOptions.noEmitOnError = prevNoEmitOnError; } } + +/** + * Checks whether the analyzed Angular program contains any non-standalone `@Component` + * declarations in user source files that lack an owning `NgModule` scope. + */ +function hasUnscopedComponent(angularCompiler: ng.NgCompiler): boolean { + // `incrementalCompilation.state` is typed as the `IncrementalState` union + // (`AnalyzedIncrementalState | DeltaIncrementalState | FreshIncrementalState`), where only + // `AnalyzedIncrementalState` (populated once `analyzeAsync()` completes) contains + // `priorAnalysis`. Because the `IncrementalStateKind` discriminant enum is not re-exported + // from `@angular/compiler-cli`, narrow the union via `'priorAnalysis' in state`. + const state = angularCompiler.incrementalCompilation.state; + if (!('priorAnalysis' in state)) { + return false; + } + + let templateTypeChecker: ReturnType | undefined; + + for (const [sourceFile, records] of state.priorAnalysis) { + if (records.length === 0 || angularCompiler.ignoreForEmit.has(sourceFile)) { + continue; + } + + for (const { node } of records) { + if (!ts.isClassDeclaration(node)) { + continue; + } + + const meta = angularCompiler.getMeta(node); + if (meta && 'isComponent' in meta && meta.isComponent && !meta.isStandalone) { + if (!templateTypeChecker) { + // `NgtscProgram` initializes `NgCompiler` with `enableTemplateTypeChecker = false`, which + // guards the public `getTemplateTypeChecker()` getter. Temporarily enable the flag after + // `analyzeAsync()` has already constructed `TemplateTypeCheckerImpl` so we can query + // `getOwningNgModule()` without altering `typeCheckingConfig.enableTemplateTypeChecker`. + const compiler = angularCompiler as { enableTemplateTypeChecker: boolean }; + const previous = compiler.enableTemplateTypeChecker; + try { + compiler.enableTemplateTypeChecker = true; + templateTypeChecker = angularCompiler.getTemplateTypeChecker(); + } finally { + compiler.enableTemplateTypeChecker = previous; + } + } + + if (templateTypeChecker.getOwningNgModule(node) === null) { + return true; + } + } + } + } + + return false; +} diff --git a/packages/angular/build/src/tools/angular/compilation/typescript-compilation.ts b/packages/angular/build/src/tools/angular/compilation/typescript-compilation.ts index eba7a10a5cb4..6601500fbcc9 100644 --- a/packages/angular/build/src/tools/angular/compilation/typescript-compilation.ts +++ b/packages/angular/build/src/tools/angular/compilation/typescript-compilation.ts @@ -18,6 +18,7 @@ import { convertTypeScriptDiagnostic } from './diagnostics'; export interface TransformedConfiguration { compilerOptions: ng.CompilerOptions; rootNames: string[]; + fallbackRootNames?: string[]; errors: ts.Diagnostic[]; warnings: PartialMessage[]; tsConfigFiles: readonly string[]; @@ -75,16 +76,37 @@ export abstract class TypeScriptCompilation extends AngularCompilation { const tsConfigFiles = [toPosixPath(tsconfig), ...this.#extendedConfigCache.keys()]; let rootNames = originalRootNames; + let fallbackRootNames: string[] | undefined; if (compilerOptionOverrides?.rootFiles?.length) { + // When explicit rootFiles are provided (e.g., filtered unit test entry points), restrict + // the initial program to only those entry points so TypeScript resolves only their + // transitive imports and skips unrelated or non-included test/application files. const rootFilesSet = new Set( compilerOptionOverrides.rootFiles.map((file) => canonicalizePath(toPosixPath(file))), ); + const fallbackFilesSet = new Set(rootFilesSet); for (const file of originalRootNames) { + const canonicalFile = canonicalizePath(toPosixPath(file)); + // Ambient declaration files (.d.ts) are not imported directly, so they must always be + // retained from the tsconfig to preserve global type definitions. if (/\.d\.[cm]?ts$/i.test(file)) { - rootFilesSet.add(canonicalizePath(toPosixPath(file))); + rootFilesSet.add(canonicalFile); } + fallbackFilesSet.add(canonicalFile); } rootNames = [...rootFilesSet]; + // For application builds (including unit tests), preserve the full set of tsconfig root + // files as a fallback in case the AOT compilation encounters a non-standalone component + // whose declaring NgModule is not directly imported by the entry points. Note that when a + // test tsconfig uses broad globs (e.g., `src/**/*.ts`), this fallback set will also include + // non-included spec files; this is an acceptable trade-off to keep compilation agnostic of + // test-file naming conventions and only occurs for legacy non-standalone components lacking + // explicit NgModule imports. Library builds are excluded because all public NgModules must + // be reachable from the library entry points and should never resolve compilation scope from + // unexported tsconfig files. + if (buildType === 'application' && fallbackFilesSet.size > rootFilesSet.size) { + fallbackRootNames = [...fallbackFilesSet]; + } } const { compilerOptions, warnings } = transformCompilerOptions( @@ -98,6 +120,7 @@ export abstract class TypeScriptCompilation extends AngularCompilation { return { compilerOptions, rootNames, + fallbackRootNames, errors, warnings, tsConfigFiles, From f479c11d4deda6b5aad1c9adaa89fb6a547ebc12 Mon Sep 17 00:00:00 2001 From: Angular Robot Date: Wed, 14 Oct 2026 15:55:57 +0000 Subject: [PATCH 34/52] build: update cross-repo angular dependencies See associated pull request for more information. --- package.json | 4 ++-- pnpm-lock.yaml | 24 +++++++++++----------- tests/e2e/ng-snapshot/package.json | 32 +++++++++++++++--------------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/package.json b/package.json index c2efa7133c4f..6a7407853c21 100644 --- a/package.json +++ b/package.json @@ -48,13 +48,13 @@ }, "devDependencies": { "@angular/animations": "22.3.0-next.1", - "@angular/cdk": "22.3.0-next.1", + "@angular/cdk": "22.3.0-next.2", "@angular/common": "22.3.0-next.1", "@angular/compiler": "22.3.0-next.1", "@angular/core": "22.3.0-next.1", "@angular/forms": "22.3.0-next.1", "@angular/localize": "22.3.0-next.1", - "@angular/material": "22.3.0-next.1", + "@angular/material": "22.3.0-next.2", "@angular/ng-dev": "https://github.com/angular/dev-infra-private-ng-dev-builds.git#fa4308affb4a0dde34ebc95196b58550752485a2", "@angular/platform-browser": "22.3.0-next.1", "@angular/platform-server": "22.3.0-next.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b2b2fdfdffd9..e38b036ee3d9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -187,8 +187,8 @@ importers: specifier: 22.3.0-next.1 version: 22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)) '@angular/cdk': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(1e228ab395252fe57958c1335d3a301f) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(1e228ab395252fe57958c1335d3a301f) '@angular/common': specifier: 22.3.0-next.1 version: 22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) @@ -205,8 +205,8 @@ importers: specifier: 22.3.0-next.1 version: 22.3.0-next.1(@angular/compiler-cli@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(typescript@6.0.3))(@angular/compiler@22.3.0-next.1) '@angular/material': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(837417520965053888cf2615dc986a27) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(1acbd77e3019024ea0df0dc9f59ed8c0) '@angular/ng-dev': specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#fa4308affb4a0dde34ebc95196b58550752485a2 version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/fa4308affb4a0dde34ebc95196b58550752485a2 @@ -1035,8 +1035,8 @@ packages: peerDependencies: '@angular/core': 22.3.0-next.1 - '@angular/cdk@22.3.0-next.1': - resolution: {integrity: sha512-WAOIXq+8KtLn59xdt7rRKgdxO3VUCGSlSzoUJQez4EM+/MFa8GPMTHZ392ewBA3R2XpEJNFbSIH61A0+yfNBMg==} + '@angular/cdk@22.3.0-next.2': + resolution: {integrity: sha512-UlleZDkYVds93nKOJ32g393Ca7XyrG+c8r5XoQG3aQHKe5L+lc5HjmPGAJ1Y80iotUQG3NFsgwLnweCGV12yWw==} peerDependencies: '@angular/common': ^22.0.0-0 || ^22.1.0-0 || ^22.2.0-0 || ^22.3.0-0 || ^23.0.0-0 '@angular/core': ^22.0.0-0 || ^22.1.0-0 || ^22.2.0-0 || ^22.3.0-0 || ^23.0.0-0 @@ -1096,10 +1096,10 @@ packages: '@angular/compiler': 22.3.0-next.1 '@angular/compiler-cli': 22.3.0-next.1 - '@angular/material@22.3.0-next.1': - resolution: {integrity: sha512-iQrlvYiHEwY9p7c8CIa9pPXfWDuE+4cU3c64X3w8i7ChDBSj/dzsGK31X4EstZ+PXozDzcLH+JXuHkWPg81CVQ==} + '@angular/material@22.3.0-next.2': + resolution: {integrity: sha512-4l6+DzUtwIH+SYrZdT54Lg7sNvFu6+MmLxlQQB8TtC5V5EijqOv1rjLmp+mFFgpVFmwlZwdGS8vJfRvkzKLY2w==} peerDependencies: - '@angular/cdk': 22.3.0-next.1 + '@angular/cdk': 22.3.0-next.2 '@angular/common': ^22.0.0-0 || ^22.1.0-0 || ^22.2.0-0 || ^22.3.0-0 || ^23.0.0-0 '@angular/core': ^22.0.0-0 || ^22.1.0-0 || ^22.2.0-0 || ^22.3.0-0 || ^23.0.0-0 '@angular/forms': ^22.0.0-0 || ^22.1.0-0 || ^22.2.0-0 || ^22.3.0-0 || ^23.0.0-0 @@ -8870,7 +8870,7 @@ snapshots: '@angular/core': 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3) tslib: 2.8.1 - '@angular/cdk@22.3.0-next.1(1e228ab395252fe57958c1335d3a301f)': + '@angular/cdk@22.3.0-next.2(1e228ab395252fe57958c1335d3a301f)': dependencies: '@angular/common': 22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) '@angular/core': 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3) @@ -8930,9 +8930,9 @@ snapshots: tinyglobby: 0.2.17 yargs: 18.2.0 - '@angular/material@22.3.0-next.1(837417520965053888cf2615dc986a27)': + '@angular/material@22.3.0-next.2(1acbd77e3019024ea0df0dc9f59ed8c0)': dependencies: - '@angular/cdk': 22.3.0-next.1(1e228ab395252fe57958c1335d3a301f) + '@angular/cdk': 22.3.0-next.2(1e228ab395252fe57958c1335d3a301f) '@angular/common': 22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) '@angular/core': 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3) '@angular/forms': 22.3.0-next.1(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2) diff --git a/tests/e2e/ng-snapshot/package.json b/tests/e2e/ng-snapshot/package.json index 0618eb046f57..8550a3c4bb4c 100644 --- a/tests/e2e/ng-snapshot/package.json +++ b/tests/e2e/ng-snapshot/package.json @@ -2,21 +2,21 @@ "description": "snapshot versions of Angular for e2e testing", "private": true, "dependencies": { - "@angular/animations": "github:angular/animations-builds#7ef64e48fbd50c668e386243a1d4c2f1ef84675b", - "@angular/cdk": "github:angular/cdk-builds#8aa05501715c9b9b0fc95625f52b3b536c35cc4a", - "@angular/common": "github:angular/common-builds#96bb8a452e96a75e2130519f1301b25a08e408ec", - "@angular/compiler": "github:angular/compiler-builds#c94e6865d332afa0694d24049624ef23d1923089", - "@angular/compiler-cli": "github:angular/compiler-cli-builds#2d4f2f5eede86c9f3fa7ec4e8ce4cf03fc502d54", - "@angular/core": "github:angular/core-builds#f43cfb919a0da367f40da1bd07e67cd1845388c2", - "@angular/forms": "github:angular/forms-builds#a181c75be824e20dcc653e7e029217014aaae777", - "@angular/language-service": "github:angular/language-service-builds#3224af77e1a302a3ba6a5620fce41879c8c8158e", - "@angular/localize": "github:angular/localize-builds#b1148951f8251042228b544facb01d24f40d7380", - "@angular/material": "github:angular/material-builds#5f4d7a4724a306e1e24d55f53564eebfa22dbdd4", - "@angular/material-moment-adapter": "github:angular/material-moment-adapter-builds#a600a485f5c91b376684763cbf00b158f85502f0", - "@angular/platform-browser": "github:angular/platform-browser-builds#b8cd3c70f3e83ccc2675345dbaef19406c274814", - "@angular/platform-browser-dynamic": "github:angular/platform-browser-dynamic-builds#81f80d43de410f7d4a2f0da625ca5882b7c3f71a", - "@angular/platform-server": "github:angular/platform-server-builds#b94ffc850d236d03d53460c6bb72b23eb7e21920", - "@angular/router": "github:angular/router-builds#cbe6196b50ea6948bb8ade7ac32f26029d37ca45", - "@angular/service-worker": "github:angular/service-worker-builds#5bb5c383c8e2323d28a2347a784327e031a4b101" + "@angular/animations": "github:angular/animations-builds#f2f4920079874bc3ff7233cae1bfc044f540aaea", + "@angular/cdk": "github:angular/cdk-builds#47633891913bba784f30c7e96a832ce5aee6b5ca", + "@angular/common": "github:angular/common-builds#50cb684a62ab0a76b5cac1f43e419dcef95695c5", + "@angular/compiler": "github:angular/compiler-builds#121ce74dc256084d4df6189faec0897906c81e7f", + "@angular/compiler-cli": "github:angular/compiler-cli-builds#13f5a3741ae88163e4830805d5fdb3be10975600", + "@angular/core": "github:angular/core-builds#803e8bc85644b8ae2f7626a2128b2597bad464f5", + "@angular/forms": "github:angular/forms-builds#dfc8f809fc98e7350bfb3c0cc4ed76c2f898e8a2", + "@angular/language-service": "github:angular/language-service-builds#26e3a3900301c3d6a9ab6a25567c1038e7a8556d", + "@angular/localize": "github:angular/localize-builds#152ad1e6420c1f2f6592f920c81e39dbcb5f5493", + "@angular/material": "github:angular/material-builds#e39e747aad22eb1ee2981f8f7b39a3b8ec788381", + "@angular/material-moment-adapter": "github:angular/material-moment-adapter-builds#f0e6679098e0bfdb8f98b2c7a2c271ec2d128994", + "@angular/platform-browser": "github:angular/platform-browser-builds#c87936c6c5381b369a60bcd311836c711b68d498", + "@angular/platform-browser-dynamic": "github:angular/platform-browser-dynamic-builds#abdac4b65aa34f8a1c9580631d22ae478579e111", + "@angular/platform-server": "github:angular/platform-server-builds#11bfbc1463ebaff83489b1b560ff49e9fb281fb1", + "@angular/router": "github:angular/router-builds#5457840c68f0afb075100b2d923de1219b450838", + "@angular/service-worker": "github:angular/service-worker-builds#94c8e94f4903c4271b9da3eedea9402e3af87043" } } From a3b6d48f477626c8eaed4a689551fb6f7c285a7d Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Wed, 14 Oct 2026 18:57:25 +0200 Subject: [PATCH 35/52] refactor(@angular/build): normalize library builder paths to POSIX format Normalize paths at option and compilation boundaries in the library builder to POSIX format and update TSDoc comments across the library builder pipeline. --- .../build/src/builders/library/builder.ts | 27 +++++++----- .../build/src/builders/library/options.ts | 34 +++++++++++---- .../src/builders/library/pipeline/assets.ts | 29 ++++++------- .../builders/library/pipeline/build-action.ts | 25 ++++++----- .../src/builders/library/pipeline/bundler.ts | 43 ++++++++----------- .../builders/library/pipeline/compilation.ts | 21 +++++---- .../builders/library/pipeline/entry-points.ts | 30 ++++++++----- .../library/pipeline/package-manifests.ts | 2 +- .../library/pipeline/stylesheet-bundler.ts | 5 ++- .../src/builders/library/pipeline/utils.ts | 25 +++++------ .../build/src/builders/library/types.ts | 35 +++++++++++---- .../build/src/utils/delete-output-dir.ts | 5 ++- .../src/utils/normalize-asset-patterns.ts | 15 ++++--- 13 files changed, 171 insertions(+), 125 deletions(-) diff --git a/packages/angular/build/src/builders/library/builder.ts b/packages/angular/build/src/builders/library/builder.ts index 84b933e7ceb6..c3c2149adf5b 100644 --- a/packages/angular/build/src/builders/library/builder.ts +++ b/packages/angular/build/src/builders/library/builder.ts @@ -111,13 +111,10 @@ export async function* executeLibraryBuilder( ); // Track all referenced compilation files for watch mode - const watchedCompilationFiles = new Set([ - toPosixPath(tsConfigPath), - toPosixPath(packageJsonPath), - ]); + const watchedCompilationFiles = new Set([tsConfigPath, packageJsonPath]); for (const entryPoint of normalizedOptions.entryPoints.values()) { - watchedCompilationFiles.add(toPosixPath(entryPoint.entryFilePath)); + watchedCompilationFiles.add(entryPoint.entryFilePath); } if (isWatchMode) { @@ -237,6 +234,17 @@ async function executeBuild( /** * Runs the watch loop, rebuilding the library as watched files are modified. + * + * @param watcher The file watcher instance. + * @param options The normalized library builder options with POSIX paths. + * @param stylesheetBundler The component stylesheet bundler instance. + * @param watchedCompilationFiles Set of POSIX file paths tracked for compilation. + * @param context The Architect builder context. + * @param withProgress Progress wrapper function (`withSpinner` or `withNoProgress`). + * @param buildState The state preserved across incremental builds. + * @param buildAction The library build action function to execute. + * @param hasModifiedWatchedFile Helper to check whether watched compilation files changed. + * @param signal Optional abort signal to terminate the watch loop. */ async function* runWatchLoop( watcher: BuildWatcher, @@ -253,7 +261,6 @@ async function* runWatchLoop( const { collectAssetsToEmit } = await import('./pipeline/assets'); const { workspaceRoot, packageJsonPath, assets, clearScreen } = options; - const posixPackageJsonPath = toPosixPath(packageJsonPath); for await (const changes of watcher) { if (signal?.aborted) { @@ -293,13 +300,13 @@ async function* runWatchLoop( // Check if package.json was modified let hasPackageJsonChanges = false; - if (changedFiles.has(posixPackageJsonPath)) { + if (changedFiles.has(packageJsonPath)) { try { const packageJson = await loadPackageJson(packageJsonPath); - options.packageJson = packageJson; if (!packageJson.name) { throw new Error(`The package.json at '${packageJsonPath}' must contain a 'name'.`); } + options.packageJson = packageJson; options.packageName = packageJson.name; updateWatchedEntryPoints( @@ -328,7 +335,7 @@ async function* runWatchLoop( !buildState.singleProgramCache || buildState.hasCompilationError || buildState.hasEntryPointsChanges || - hasModifiedWatchedFile(changedFiles, watchedCompilationFiles, posixPackageJsonPath); + hasModifiedWatchedFile(changedFiles, watchedCompilationFiles, packageJsonPath); const assetsToEmit = await collectAssetsToEmit( assets, @@ -388,7 +395,7 @@ function logMessages( * @param logger The Architect logger API. * @param startTime High-resolution timestamp recorded when the build iteration started. * @param success Whether the build iteration succeeded without errors. - * @param outputPath Optional output directory path to log on successful builds. + * @param outputPath Optional POSIX output directory path to log on successful builds. */ function logBuildResult( logger: logging.LoggerApi, diff --git a/packages/angular/build/src/builders/library/options.ts b/packages/angular/build/src/builders/library/options.ts index b7747fb6db27..14bc4514027d 100644 --- a/packages/angular/build/src/builders/library/options.ts +++ b/packages/angular/build/src/builders/library/options.ts @@ -13,6 +13,7 @@ import { normalizeAssetPatterns } from '../../utils'; import { supportColor } from '../../utils/color'; import { assertIsError } from '../../utils/error'; import { normalizeCacheOptions } from '../../utils/normalize-cache'; +import { toPosixPath } from '../../utils/path'; import { generateSearchDirectories, getTailwindConfig, @@ -24,14 +25,25 @@ import { loadPackageJson } from './pipeline/utils'; import type { Schema as LibraryBuilderOptions } from './schema'; import type { NormalizedLibraryOptions, PackageJsonData } from './types'; +/** + * Normalizes raw library builder options into {@link NormalizedLibraryOptions} with all + * file and directory paths normalized to POSIX format. + * + * @param context The Architect builder context. + * @param projectName The name of the library project. + * @param options The raw library builder schema options. + * @returns A promise resolving to the normalized library options. + */ export async function normalizeLibraryOptions( context: BuilderContext, projectName: string, options: LibraryBuilderOptions, ): Promise { - const { workspaceRoot } = context; + const workspaceRoot = toPosixPath(context.workspaceRoot); const projectMetadata = await context.getProjectMetadata(projectName); - const { projectRoot, projectSourceRoot } = getProjectRootPaths(workspaceRoot, projectMetadata); + const projectRootPaths = getProjectRootPaths(workspaceRoot, projectMetadata); + const projectRoot = toPosixPath(projectRootPaths.projectRoot); + const projectSourceRoot = toPosixPath(projectRootPaths.projectSourceRoot); const { tsConfig, @@ -50,8 +62,8 @@ export async function normalizeLibraryOptions( clearScreen, } = options; - const resolvedTsConfigPath = path.resolve(workspaceRoot, tsConfig); - const packageJsonPath = path.join(projectRoot, 'package.json'); + const resolvedTsConfigPath = toPosixPath(path.resolve(workspaceRoot, tsConfig)); + const packageJsonPath = path.posix.join(projectRoot, 'package.json'); let packageJson: PackageJsonData; try { @@ -99,7 +111,7 @@ export async function normalizeLibraryOptions( } defaultAssets.push({ glob: 'README.md', - input: path.dirname(entryPoint.entryFilePath), + input: path.posix.dirname(entryPoint.entryFilePath), output: entryPoint.name, }); } @@ -109,7 +121,11 @@ export async function normalizeLibraryOptions( workspaceRoot, projectRoot, projectSourceRoot, - ); + ).map((asset) => ({ + ...asset, + input: toPosixPath(path.resolve(workspaceRoot, asset.input)), + output: toPosixPath(asset.output), + })); const cacheOptions = normalizeCacheOptions( projectMetadata, @@ -119,7 +135,7 @@ export async function normalizeLibraryOptions( ); const styleIncludePaths = (stylePreprocessorOptions?.includePaths ?? []).map((p: string) => - path.resolve(workspaceRoot, p), + toPosixPath(path.resolve(workspaceRoot, p)), ); const searchDirectories = await generateSearchDirectories([projectRoot, workspaceRoot]); @@ -133,7 +149,9 @@ export async function normalizeLibraryOptions( projectRoot, packageName, packageJson, - outputPath: path.resolve(workspaceRoot, options.outputPath ?? path.join('dist', projectName)), + outputPath: toPosixPath( + path.resolve(workspaceRoot, options.outputPath ?? path.posix.join('dist', projectName)), + ), deleteOutputPath, packageJsonPath, tsConfigPath: resolvedTsConfigPath, diff --git a/packages/angular/build/src/builders/library/pipeline/assets.ts b/packages/angular/build/src/builders/library/pipeline/assets.ts index e1e46f4b9f08..7b8329a7865a 100644 --- a/packages/angular/build/src/builders/library/pipeline/assets.ts +++ b/packages/angular/build/src/builders/library/pipeline/assets.ts @@ -9,7 +9,6 @@ import { statSync } from 'node:fs'; import path from 'node:path'; import picomatch from 'picomatch'; -import { toPosixPath } from '../../../utils/path'; import { DEFAULT_ASSET_IGNORE, resolveAssets } from '../../../utils/resolve-assets'; import type { NormalizedLibraryOptions } from '../types'; import { type DiskOutputFile, createDiskOutputFile } from './utils'; @@ -17,9 +16,9 @@ import { type DiskOutputFile, createDiskOutputFile } from './utils'; /** * Resolves and collects configured library assets to be emitted to disk. * - * @param assets The normalized asset patterns. - * @param workspaceRoot The workspace root directory path. - * @param modifiedFiles Optional set of modified file paths for incremental copying in watch mode. + * @param assets The normalized asset patterns with POSIX paths. + * @param workspaceRoot The normalized POSIX workspace root directory path. + * @param modifiedFiles Optional set of modified POSIX file paths for incremental copying in watch mode. * @returns An array of disk file emission descriptors. */ export async function collectAssetsToEmit( @@ -32,25 +31,22 @@ export async function collectAssetsToEmit( } if (modifiedFiles) { - const matchers = createAssetMatchers(assets, workspaceRoot); + const matchers = createAssetMatchers(assets); const filesToEmit: DiskOutputFile[] = []; for (const file of modifiedFiles) { - const resolvedFile = path.isAbsolute(file) ? file : path.resolve(workspaceRoot, file); - const posixFile = toPosixPath(resolvedFile); - - for (const { asset, posixInputPrefix, isMatch } of matchers) { - if (!posixFile.startsWith(posixInputPrefix)) { + for (const { asset, prefix, isMatch } of matchers) { + if (!file.startsWith(prefix)) { continue; } - const relative = posixFile.slice(posixInputPrefix.length); + const relative = file.slice(prefix.length); if (!isMatch(relative)) { continue; } - if (statSync(resolvedFile, { throwIfNoEntry: false })?.isFile()) { - filesToEmit.push(createDiskOutputFile(resolvedFile, path.join(asset.output, relative))); + if (statSync(file, { throwIfNoEntry: false })?.isFile()) { + filesToEmit.push(createDiskOutputFile(file, path.posix.join(asset.output, relative))); } } } @@ -63,15 +59,14 @@ export async function collectAssetsToEmit( return resolvedAssets.map(({ source, destination }) => createDiskOutputFile(source, destination)); } -function createAssetMatchers(assets: NormalizedLibraryOptions['assets'], workspaceRoot: string) { +function createAssetMatchers(assets: NormalizedLibraryOptions['assets']) { return assets.map((asset) => { - const absInput = path.resolve(workspaceRoot, asset.input); - const posixInput = toPosixPath(absInput).replace(/\/+$/, ''); const isMatch = picomatch(asset.glob, { dot: true, ignore: [...DEFAULT_ASSET_IGNORE, ...(asset.ignore ?? [])], }); + const prefix = asset.input.endsWith('/') ? asset.input : `${asset.input}/`; - return { asset, posixInputPrefix: `${posixInput}/`, isMatch }; + return { asset, prefix, isMatch }; }); } diff --git a/packages/angular/build/src/builders/library/pipeline/build-action.ts b/packages/angular/build/src/builders/library/pipeline/build-action.ts index acdc69c61bff..f121048b1fc7 100644 --- a/packages/angular/build/src/builders/library/pipeline/build-action.ts +++ b/packages/angular/build/src/builders/library/pipeline/build-action.ts @@ -11,7 +11,6 @@ import path from 'node:path'; import type { ComponentStylesheetBundler } from '../../../tools/esbuild/angular/component-stylesheets'; import { emitFilesToDisk } from '../../../utils/disk-files'; import { assertIsError } from '../../../utils/error'; -import { toPosixPath } from '../../../utils/path'; import type { NormalizedLibraryOptions, SingleBuildState } from '../types'; import { collectAssetsToEmit } from './assets'; import { bundleEntryPoints } from './bundler'; @@ -49,7 +48,7 @@ export function createSingleBuildState(): SingleBuildState { * Context required to execute a single library build iteration. */ export interface BuildActionContext { - /** Normalized options for the library build. */ + /** Normalized options for the library build with POSIX paths. */ options: NormalizedLibraryOptions; /** The Architect builder context. */ @@ -62,7 +61,7 @@ export interface BuildActionContext { isWatchMode: boolean; /** - * Set of file paths tracked for compilation and configuration + * Set of POSIX file paths tracked for compilation and configuration * (including `tsconfig.json`, `package.json`, entry points, and referenced source, * template, and stylesheet files). Updated during compilation and used to determine * whether file changes require recompiling entry points, excluding asset files so @@ -73,7 +72,7 @@ export interface BuildActionContext { /** State preserved across incremental builds in watch mode. */ buildState: SingleBuildState; - /** Set of file paths modified since the last build iteration. */ + /** Set of POSIX file paths modified since the last build iteration. */ modifiedFiles?: Set; /** @@ -91,6 +90,7 @@ export interface BuildActionContext { * manifest generation, and asset copying. * * @param actionContext The build action state and configuration. + * @returns A promise resolving to the build action result containing errors, warnings, and logs. */ export async function buildAction(actionContext: BuildActionContext): Promise { const { @@ -106,10 +106,10 @@ export async function buildAction(actionContext: BuildActionContext): Promise 0 || pendingChangedDtsFiles.size > 0 || - hasModifiedWatchedFile(modifiedFiles, watchedCompilationFiles, posixPackageJsonPath); + hasModifiedWatchedFile(modifiedFiles, watchedCompilationFiles, packageJsonPath); try { if (!buildState.hasEmittedManifests) { @@ -172,13 +172,12 @@ export async function buildAction(actionContext: BuildActionContext): Promise> | undefined; let diagnostics: LibraryCompilationDiagnostics; if (hasStylesheetErrors) { diagnostics = await diagnosePromise; } else { + const itemsToBundle = collectEntryPointsToBundle(options, buildState, logs); try { [bundleOutput, diagnostics] = await Promise.all([ bundleEntryPoints(itemsToBundle, esmFiles, dtsFiles, { @@ -243,7 +242,7 @@ export async function buildAction(actionContext: BuildActionContext): Promise path.join(options.outputPath, file.path)); + await emitFilesToDisk(filesToEmit, (file) => path.posix.join(options.outputPath, file.path)); buildState.hasEmittedManifests = true; buildState.hasEmittedTslib = hasTslibImport; @@ -262,16 +261,16 @@ export async function buildAction(actionContext: BuildActionContext): Promise, watchedCompilationFiles: ReadonlySet, - posixPackageJsonPath: string, + packageJsonPath: string, ): boolean { for (const file of modifiedFiles) { - if (file !== posixPackageJsonPath && watchedCompilationFiles.has(file)) { + if (file !== packageJsonPath && watchedCompilationFiles.has(file)) { return true; } } diff --git a/packages/angular/build/src/builders/library/pipeline/bundler.ts b/packages/angular/build/src/builders/library/pipeline/bundler.ts index 5cd89a4b110d..c48942885083 100644 --- a/packages/angular/build/src/builders/library/pipeline/bundler.ts +++ b/packages/angular/build/src/builders/library/pipeline/bundler.ts @@ -60,7 +60,7 @@ interface MultiBundleOutput { /** In-memory files generated by the bundle invocation. */ filesToEmit: MemoryOutputFile[]; - /** Map of bundle entry names to the set of virtual module IDs included in the bundle. */ + /** Map of bundle entry names to the set of virtual POSIX module IDs included in the bundle. */ moduleIdsByBundle: Map>; /** Set of bundle entry names that import 'tslib'. */ @@ -75,9 +75,9 @@ interface MultiBundleOutput { * using at most 2 Rolldown instances total (1 for all .mjs bundles, 1 for all .d.ts bundles). * * @param items The collection of entry point inputs with change statuses. - * @param esmFiles Map of virtual ESM output file paths to their content. - * @param dtsFiles Map of virtual TypeScript declaration file paths to their content. - * @param options The normalized library builder options. + * @param esmFiles Map of virtual POSIX ESM output file paths to their content. + * @param dtsFiles Map of virtual POSIX TypeScript declaration file paths to their content. + * @param options The normalized library builder options with POSIX paths. * @returns A promise resolving to the bundled output files and bundle cache results. */ export async function bundleEntryPoints( @@ -135,7 +135,7 @@ export async function bundleEntryPoints( * * @param entryPoints The entry points to include in the bundle input map. * @param dtsMode Whether the input map is for declaration files (.d.ts) rather than ESM files (.js). - * @returns A record mapping bundle names to virtual entry file paths. + * @returns A record mapping bundle names to virtual POSIX entry file paths. */ function resolveEntryInputMap( entryPoints: readonly NormalizedEntryPoint[], @@ -143,20 +143,18 @@ function resolveEntryInputMap( ): Record { const input: Record = {}; for (const { bundleName, entryFilePath } of entryPoints) { - const posixPath = toPosixPath(entryFilePath); input[bundleName] = dtsMode - ? posixPath.replace(/\.([cm]?ts)$/, '.d.$1') - : posixPath.replace(/\.([cm]?)ts$/, '.$1js'); + ? entryFilePath.replace(/\.([cm]?ts)$/, '.d.$1') + : entryFilePath.replace(/\.([cm]?)ts$/, '.$1js'); } return input; } /** - * Creates a Rolldown plugin that loads modules from an in-memory file map - * and prevents illegal cross-entry-point sibling imports. + * Creates a Rolldown plugin that resolves and loads modules from an in-memory file map. * - * @param files Map of virtual file paths to their content. + * @param files Map of virtual POSIX file paths to their content. * @param extensions Candidate extensions to probe when resolving extensionless module specifiers. * @param includeMap Whether source map files should also be loaded from the memory map. * @returns A Rolldown plugin instance. @@ -183,12 +181,7 @@ function createMemoryFileLoaderPlugin( return { id, external: true }; } - const posixId = toPosixPath(id); - const importerPosix = toPosixPath(importer); - const resolved = - posixId[0] === '.' - ? path.posix.join(path.posix.dirname(importerPosix), posixId) - : posixId; + const resolved = id[0] === '.' ? path.posix.join(path.posix.dirname(importer), id) : id; let resolvedCandidate: string | undefined; if (files.has(resolved)) { @@ -230,7 +223,7 @@ function createMemoryFileLoaderPlugin( * the transitive set of module IDs belonging to each entry point bundle. * * @param output The array of output chunks and assets from Rolldown. - * @param dir The destination output directory prefix. + * @param dir The destination POSIX output directory prefix. * @returns The processed multi-bundle output. */ function processRolldownOutput( @@ -312,10 +305,10 @@ const IGNORED_ROLLDOWN_WARNING_CODES: ReadonlySet = new Set([ /** * Executes a Rolldown bundle build across all provided entry inputs. * - * @param input Map of bundle names to virtual entry file paths. + * @param input Map of bundle names to virtual POSIX entry file paths. * @param plugins Rolldown plugins to use during bundling. * @param extension Output file extension ('mjs' or 'd.ts'). - * @param options The normalized library options. + * @param options The normalized library options with POSIX paths. * @returns A promise resolving to the multi-bundle output. */ async function executeMultiBundle( @@ -367,7 +360,7 @@ async function executeMultiBundle( try { const { output } = await bundle.generate({ format: 'es', - dir: path.join(outputPath, dir), + dir: path.posix.join(outputPath, dir), entryFileNames: `[name].${extension}`, chunkFileNames: `[name]-[hash].${extension}`, sourcemap, @@ -388,8 +381,8 @@ async function executeMultiBundle( * Bundles JavaScript ESM output files for all provided entry points. * * @param entryPoints The entry points to bundle. - * @param esmFiles Map of virtual ESM output file paths to contents. - * @param options The normalized library options. + * @param esmFiles Map of virtual POSIX ESM output file paths to contents. + * @param options The normalized library options with POSIX paths. * @returns A promise resolving to the multi-bundle output. */ async function bundleAllEsm( @@ -418,8 +411,8 @@ async function bundleAllEsm( * Bundles TypeScript declaration (.d.ts) output files for all provided entry points. * * @param entryPoints The entry points to bundle. - * @param dtsFiles Map of virtual declaration output file paths to contents. - * @param options The normalized library options. + * @param dtsFiles Map of virtual POSIX declaration output file paths to contents. + * @param options The normalized library options with POSIX paths. * @returns A promise resolving to the multi-bundle output. */ async function bundleAllDts( diff --git a/packages/angular/build/src/builders/library/pipeline/compilation.ts b/packages/angular/build/src/builders/library/pipeline/compilation.ts index afc5c319854e..5a795b463bae 100644 --- a/packages/angular/build/src/builders/library/pipeline/compilation.ts +++ b/packages/angular/build/src/builders/library/pipeline/compilation.ts @@ -35,19 +35,19 @@ export interface LibraryCompilationDiagnostics { * Output of the unified library compilation step. */ export interface LibraryCompilationOutput { - /** Read-only map of emitted JavaScript files. */ + /** Read-only map of emitted JavaScript files keyed by POSIX path. */ readonly esmFiles: ReadonlyMap; - /** Read-only map of emitted TypeScript declaration files. */ + /** Read-only map of emitted TypeScript declaration files keyed by POSIX path. */ readonly dtsFiles: ReadonlyMap; - /** Set of JavaScript file paths that were modified or newly emitted in this iteration. */ + /** Set of POSIX JavaScript file paths that were modified or newly emitted in this iteration. */ readonly changedEsmFiles: ReadonlySet; - /** Set of declaration file paths that were modified or newly emitted in this iteration. */ + /** Set of POSIX declaration file paths that were modified or newly emitted in this iteration. */ readonly changedDtsFiles: ReadonlySet; - /** Set of all source and dependency file paths referenced during compilation. */ + /** Set of all POSIX source and dependency file paths referenced during compilation. */ readonly referencedFiles: ReadonlySet; /** Cached compilation state for subsequent incremental builds. */ @@ -70,10 +70,10 @@ export interface LibraryCompilationOutput { * Compiles all library entry points in a single TypeScript and Angular compilation pass. * * @param entryPoints The collection of normalized library entry points to compile. - * @param options The normalized library builder options. + * @param options The normalized library builder options with POSIX paths. * @param stylesheetBundler The component stylesheet bundler instance. * @param cached Optional cached compilation state from a previous build iteration. - * @param modifiedFiles Optional set of modified file paths for incremental compilation. + * @param modifiedFiles Optional set of modified POSIX file paths for incremental compilation. * @returns A promise resolving to the compilation output containing emitted files and diagnostics. */ export async function compileLibrary( @@ -179,13 +179,12 @@ export async function compileLibrary( if (effectiveModifiedFiles) { for (const modifiedFile of effectiveModifiedFiles) { - const posixModified = toPosixPath(modifiedFile); - if (allReferencedFiles.has(posixModified)) { + if (allReferencedFiles.has(modifiedFile)) { continue; } - const basePathWithoutExt = posixModified.replace(/(?:\.d\.[cm]?ts|\.[cm]?[jt]sx?)$/i, ''); - if (basePathWithoutExt === posixModified || existsSync(posixModified)) { + const basePathWithoutExt = modifiedFile.replace(/(?:\.d\.[cm]?ts|\.[cm]?[jt]sx?)$/i, ''); + if (basePathWithoutExt === modifiedFile || existsSync(modifiedFile)) { continue; } diff --git a/packages/angular/build/src/builders/library/pipeline/entry-points.ts b/packages/angular/build/src/builders/library/pipeline/entry-points.ts index 7797f069fade..5cff4ca82136 100644 --- a/packages/angular/build/src/builders/library/pipeline/entry-points.ts +++ b/packages/angular/build/src/builders/library/pipeline/entry-points.ts @@ -38,9 +38,9 @@ export function getEntryPointBundleName(packageName: string, entryPointName = '. * @param posixKey Normalized POSIX key without trailing slashes. * @param isPrimary Whether this is the primary entry point. * @param targetPath The relative file path string from exports. - * @param projectRoot The library project root directory. + * @param projectRoot The library project root POSIX directory path. * @param packageName The root package name (e.g. `@my/lib`). - * @returns The normalized entry point descriptor. + * @returns The normalized entry point descriptor with POSIX paths. */ function normalizeEntryPoint( key: string, @@ -65,7 +65,7 @@ function normalizeEntryPoint( const subpath = isPrimary ? '.' : `./${name}`; const displayName = (isPrimary ? packageName : `${packageName}/${name}`).toLowerCase(); const bundleName = getEntryPointBundleName(packageName, name); - const entryFilePath = path.resolve(projectRoot, targetPath); + const entryFilePath = toPosixPath(path.resolve(projectRoot, targetPath)); if (!/(?, @@ -234,6 +238,12 @@ export function haveEntryPointsChanged( /** * Updates watched files, entry points in options, and cached bundle results when package.json entry points change. + * + * @param packageJson The reloaded `package.json` data. + * @param options The normalized library builder options. + * @param buildState The state preserved across incremental builds. + * @param watchedCompilationFiles Set of POSIX file paths tracked for compilation. + * @param packageJsonPath Normalized POSIX path to `package.json`. */ export function updateWatchedEntryPoints( packageJson: PackageJsonData, @@ -251,7 +261,7 @@ export function updateWatchedEntryPoints( if (haveEntryPointsChanged(options.entryPoints, newEntryPoints)) { for (const entryPoint of newEntryPoints.values()) { - watchedCompilationFiles.add(toPosixPath(entryPoint.entryFilePath)); + watchedCompilationFiles.add(entryPoint.entryFilePath); } for (const name of buildState.previousBundleResults.keys()) { @@ -315,8 +325,8 @@ export function collectEntryPointsToBundle( /** * Checks whether any file in `changedFiles` belongs to the given entry point's `moduleIds`. * - * @param moduleIds Set of module IDs referenced by the entry point's previous bundle. - * @param changedFiles Set of file paths that changed during compilation. + * @param moduleIds Set of virtual POSIX module IDs referenced by the entry point's previous bundle. + * @param changedFiles Set of POSIX file paths that changed during compilation. * @returns `true` if at least one changed file is part of `moduleIds`; otherwise `false`. */ function hasEntryPointChanges( diff --git a/packages/angular/build/src/builders/library/pipeline/package-manifests.ts b/packages/angular/build/src/builders/library/pipeline/package-manifests.ts index 90e5d5bbd94a..98ed88a506e6 100644 --- a/packages/angular/build/src/builders/library/pipeline/package-manifests.ts +++ b/packages/angular/build/src/builders/library/pipeline/package-manifests.ts @@ -188,7 +188,7 @@ let cachedTslibRange: string | undefined; /** * Get the tslib range used by the Angular compiler. - * @param workspaceRoot path to the workspace root + * @param workspaceRoot path to the workspace root. * @returns tslib range */ async function getAngularTslibRange(workspaceRoot: string): Promise { diff --git a/packages/angular/build/src/builders/library/pipeline/stylesheet-bundler.ts b/packages/angular/build/src/builders/library/pipeline/stylesheet-bundler.ts index 74c44f3a1491..971741d7a2e2 100644 --- a/packages/angular/build/src/builders/library/pipeline/stylesheet-bundler.ts +++ b/packages/angular/build/src/builders/library/pipeline/stylesheet-bundler.ts @@ -10,6 +10,9 @@ import { ComponentStylesheetBundler } from '../../../tools/esbuild/angular/compo import type { BundleStylesheetOptions } from '../../../tools/esbuild/stylesheets/bundle-options'; import type { NormalizedLibraryOptions } from '../types'; +/** + * Subset of normalized library options required to configure the component stylesheet bundler. + */ export type LibraryStylesheetBundlerOptions = Pick< NormalizedLibraryOptions, | 'workspaceRoot' @@ -25,7 +28,7 @@ export type LibraryStylesheetBundlerOptions = Pick< /** * Creates a stylesheet bundler instance configured for library compilation. * - * @param options The normalized library builder options. + * @param options The normalized library builder options with POSIX paths. * @param incremental Whether incremental watch mode is enabled. * @param target The esbuild target environments derived from browserslist. * @returns A new ComponentStylesheetBundler instance. diff --git a/packages/angular/build/src/builders/library/pipeline/utils.ts b/packages/angular/build/src/builders/library/pipeline/utils.ts index 9092a73005ef..8ef8cf7fe9f3 100644 --- a/packages/angular/build/src/builders/library/pipeline/utils.ts +++ b/packages/angular/build/src/builders/library/pipeline/utils.ts @@ -7,6 +7,7 @@ */ import fs from 'node:fs/promises'; +import { toPosixPath } from '../../../utils/path'; import type { PackageJsonData } from '../types'; const IS_DTS_FILE_REGEXP = /\.d\.[cm]?ts$/i; @@ -28,7 +29,7 @@ export const TYPES_OUTPUT_DIR = 'types'; export interface MemoryOutputFile { origin: 'memory'; - /** The destination path where the file should be written. */ + /** The relative POSIX destination path where the file should be written. */ path: string; /** The contents of the file as either a string or byte array. */ @@ -41,10 +42,10 @@ export interface MemoryOutputFile { export interface DiskOutputFile { origin: 'disk'; - /** The path to the source file on disk. */ + /** The POSIX path to the source file on disk. */ source: string; - /** The destination path where the file should be copied. */ + /** The relative POSIX destination path where the file should be copied. */ path: string; } @@ -54,26 +55,26 @@ export interface DiskOutputFile { export type OutputFile = MemoryOutputFile | DiskOutputFile; /** - * Creates an output file descriptor for an existing file on disk. + * Creates an output file descriptor for an existing file on disk with POSIX paths. * * @param source The path to the source file on disk. - * @param path The destination path where the file should be copied. - * @returns A {@link DiskOutputFile} descriptor. + * @param path The relative destination path where the file should be copied. + * @returns A {@link DiskOutputFile} descriptor with POSIX `source` and `path`. */ export function createDiskOutputFile(source: string, path: string): DiskOutputFile { return { origin: 'disk', - source, - path, + source: toPosixPath(source), + path: toPosixPath(path), }; } /** - * Creates an output file descriptor for an in-memory file. + * Creates an output file descriptor for an in-memory file with a POSIX destination path. * - * @param path The destination path where the file should be written. + * @param path The relative destination path where the file should be written. * @param contents The contents of the file as either a string, byte array, or JSON object. - * @returns A {@link MemoryOutputFile} descriptor. + * @returns A {@link MemoryOutputFile} descriptor with a POSIX `path`. */ export function createMemoryOutputFile( path: string, @@ -81,7 +82,7 @@ export function createMemoryOutputFile( ): MemoryOutputFile { return { origin: 'memory', - path, + path: toPosixPath(path), contents: typeof contents === 'string' || contents instanceof Uint8Array ? contents diff --git a/packages/angular/build/src/builders/library/types.ts b/packages/angular/build/src/builders/library/types.ts index d360cfe2c868..2deeddf589e5 100644 --- a/packages/angular/build/src/builders/library/types.ts +++ b/packages/angular/build/src/builders/library/types.ts @@ -28,7 +28,7 @@ export interface NormalizedEntryPoint { /** Base name of the output bundle (e.g. 'my-lib' or 'my-lib-testing'). */ bundleName: string; - /** Absolute path to entry file. */ + /** Absolute POSIX path to the entry file. */ entryFilePath: string; /** Is this the primary entry point ('.')? */ @@ -59,21 +59,40 @@ export interface PackageJsonData { /** * Normalized options for the library builder. + * All file and directory paths are normalized to POSIX format. */ export interface NormalizedLibraryOptions { + /** Absolute POSIX path to the workspace root directory. */ workspaceRoot: string; + + /** Absolute POSIX path to the library project root directory. */ projectRoot: string; + packageName: string; packageJson: PackageJsonData; + + /** Absolute POSIX path to the build output directory. */ outputPath: string; + deleteOutputPath: boolean; + + /** Absolute POSIX path to the library's `package.json`. */ packageJsonPath: string; + + /** Absolute POSIX path to the TypeScript configuration file. */ tsConfigPath: string; + entryPoints: Map; inlineStyleLanguage: 'css' | 'less' | 'sass' | 'scss'; + + /** Absolute POSIX paths to style preprocessor include directories. */ styleIncludePaths: string[]; + sass?: StylesheetPluginsass; + + /** Normalized asset patterns with POSIX `input` and `output` paths. */ assets: ReturnType; + compilationMode?: 'partial' | 'full'; declarationMap?: boolean; allowedNonPeerDependencies: RegExp[]; @@ -93,10 +112,10 @@ export interface NormalizedLibraryOptions { * Cached module ID sets for a bundled entry point. */ export interface BundleResult { - /** Exact set of virtual ESM module IDs bundled into this entry point. */ + /** Exact set of virtual POSIX ESM module IDs bundled into this entry point. */ esmModuleIds: ReadonlySet; - /** Exact set of virtual DTS module IDs bundled into this entry point. */ + /** Exact set of virtual POSIX DTS module IDs bundled into this entry point. */ dtsModuleIds: ReadonlySet; /** Whether this entry point bundle imports 'tslib'. */ @@ -110,13 +129,13 @@ export interface SingleProgramCache { /** The active Angular compilation instance. */ readonly compilationInstance: AngularCompilation; - /** In-memory map of emitted JavaScript files keyed by relative output path. */ + /** In-memory map of emitted JavaScript files keyed by POSIX path. */ readonly esmFiles: Map; - /** In-memory map of emitted TypeScript declaration files keyed by relative output path. */ + /** In-memory map of emitted TypeScript declaration files keyed by POSIX path. */ readonly dtsFiles: Map; - /** Set of file paths that failed during stylesheet bundling or compilation. */ + /** Set of POSIX file paths that failed during stylesheet bundling or compilation. */ readonly failedFiles?: ReadonlySet; } @@ -133,10 +152,10 @@ export interface SingleBuildState { /** Map of entry point names to their previous bundle results. */ previousBundleResults: Map; - /** Set of changed ESM file paths pending bundling. */ + /** Set of changed POSIX ESM file paths pending bundling. */ pendingChangedEsmFiles: Set; - /** Set of changed TypeScript declaration file paths pending bundling. */ + /** Set of changed POSIX TypeScript declaration file paths pending bundling. */ pendingChangedDtsFiles: Set; /** Whether the previous build iteration encountered a compilation or diagnostic error. */ diff --git a/packages/angular/build/src/utils/delete-output-dir.ts b/packages/angular/build/src/utils/delete-output-dir.ts index 45084760793d..1f676e77b759 100644 --- a/packages/angular/build/src/utils/delete-output-dir.ts +++ b/packages/angular/build/src/utils/delete-output-dir.ts @@ -17,8 +17,9 @@ export async function deleteOutputDir( outputPath: string, emptyOnlyDirectories?: string[], ): Promise { - const resolvedOutputPath = resolve(root, outputPath); - if (resolvedOutputPath === root) { + const resolvedRoot = resolve(root); + const resolvedOutputPath = resolve(resolvedRoot, outputPath); + if (resolvedOutputPath === resolvedRoot) { throw new Error('Output path MUST not be project root directory!'); } diff --git a/packages/angular/build/src/utils/normalize-asset-patterns.ts b/packages/angular/build/src/utils/normalize-asset-patterns.ts index d97b6e605fa4..66365e10df22 100644 --- a/packages/angular/build/src/utils/normalize-asset-patterns.ts +++ b/packages/angular/build/src/utils/normalize-asset-patterns.ts @@ -24,14 +24,15 @@ export function normalizeAssetPatterns( // When sourceRoot is not available, we default to ${projectRoot}/src. const sourceRoot = projectSourceRoot || path.join(projectRoot, 'src'); - const resolvedSourceRoot = path.resolve(workspaceRoot, sourceRoot); - const resolvedProjectRoot = path.resolve(workspaceRoot, projectRoot); + const resolvedWorkspaceRoot = path.resolve(workspaceRoot); + const resolvedSourceRoot = path.resolve(resolvedWorkspaceRoot, sourceRoot); + const resolvedProjectRoot = path.resolve(resolvedWorkspaceRoot, projectRoot); return assetPatterns.map((assetPattern) => { // Normalize string asset patterns to objects. if (typeof assetPattern === 'string') { const assetPath = path.normalize(assetPattern); - const resolvedAssetPath = path.resolve(workspaceRoot, assetPath); + const resolvedAssetPath = path.resolve(resolvedWorkspaceRoot, assetPath); let root: string; // Check if the string asset is within sourceRoot. @@ -39,8 +40,8 @@ export function normalizeAssetPatterns( root = resolvedSourceRoot; } else if (resolvedAssetPath.startsWith(resolvedProjectRoot)) { root = resolvedProjectRoot; - } else if (resolvedAssetPath.startsWith(workspaceRoot)) { - root = workspaceRoot; + } else if (resolvedAssetPath.startsWith(resolvedWorkspaceRoot)) { + root = resolvedWorkspaceRoot; } else { throw new Error(`The ${assetPattern} asset path must be within the workspace root.`); } @@ -67,11 +68,11 @@ export function normalizeAssetPatterns( } // Output directory for both is the relative path from the root to input. - const output = path.relative(root, path.resolve(workspaceRoot, input)); + const output = path.relative(root, path.resolve(resolvedWorkspaceRoot, input)); assetPattern = { glob, input, output }; } else { - if (!isSubDirectory(workspaceRoot, assetPattern.input)) { + if (!isSubDirectory(resolvedWorkspaceRoot, assetPattern.input)) { throw new Error(`The ${assetPattern.input} asset path must be within the workspace root.`); } From 3dd880525c979ff130fbaf24da662a1d6eb368c2 Mon Sep 17 00:00:00 2001 From: Doug Parker Date: Wed, 14 Oct 2026 15:33:16 -0700 Subject: [PATCH 36/52] docs: release notes for the v20.3.40 release --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1922874a08d9..58a5466b6649 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ + + +# 20.3.40 (2026-10-14) + +### @angular/cli + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------- | +| [bfe1908f4](https://github.com/angular/angular-cli/commit/bfe1908f46f5799e839dcf0f162955df59a94cb0) | fix | update zod to 4.6.6 | + + + # 22.3.0-next.1 (2026-10-07) From 3515b05c715919b7ae36225fa21475c7a64738d0 Mon Sep 17 00:00:00 2001 From: Doug Parker Date: Wed, 14 Oct 2026 19:51:23 -0700 Subject: [PATCH 37/52] docs: release notes for the v21.2.27 release --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58a5466b6649..ce91a1e74158 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ + + +# 21.2.27 (2026-10-14) + +### @angular/cli + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------- | +| [2e1742adf](https://github.com/angular/angular-cli/commit/2e1742adf28645635bb6cff3cc08ad9c94c7d085) | fix | update zod to 4.6.6 | + + + # 20.3.40 (2026-10-14) From 2b5a9a620495b4c85bf5cfa3db39b632d88e6ca5 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Mon, 12 Oct 2026 13:15:29 +0000 Subject: [PATCH 38/52] perf(@angular/build): enable TypeScript incremental build cache in library builder Pass the normalized `cacheOptions.path` to `compilationInstance.initialize` when persistent disk caching is enabled so TypeScript writes and reuses `.tsbuildinfo` across builds. --- .../builders/library/pipeline/compilation.ts | 4 +- .../library/tests/behavior/build_spec.ts | 42 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/packages/angular/build/src/builders/library/pipeline/compilation.ts b/packages/angular/build/src/builders/library/pipeline/compilation.ts index 5a795b463bae..367777667fe3 100644 --- a/packages/angular/build/src/builders/library/pipeline/compilation.ts +++ b/packages/angular/build/src/builders/library/pipeline/compilation.ts @@ -83,7 +83,8 @@ export async function compileLibrary( cached?: SingleProgramCache, modifiedFiles?: Set, ): Promise { - const { tsConfigPath, compilationMode, preserveSymlinks, colors, declarationMap } = options; + const { tsConfigPath, compilationMode, preserveSymlinks, colors, declarationMap, cacheOptions } = + options; const entryPathsMap: Record = {}; const rootFiles: string[] = []; @@ -155,6 +156,7 @@ export async function compileLibrary( declarationMap, compilationMode, paths: entryPathsMap, + cachePath: cacheOptions.enabled ? cacheOptions.path : undefined, }, 'library', ); diff --git a/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts b/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts index 4f5c6736c1ff..0b6de2a26c7f 100644 --- a/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts +++ b/packages/angular/build/src/builders/library/tests/behavior/build_spec.ts @@ -236,5 +236,47 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => }), ); }); + + it('should write and reuse .tsbuildinfo in the persistent cache directory when cache is enabled', async () => { + harness.useProject('lib', { + root: 'projects/lib', + sourceRoot: 'projects/lib/src', + cli: { + cache: { + enabled: true, + environment: 'all', + path: '.angular/cache', + }, + }, + }); + + harness.useTarget('build', { + ...BASE_OPTIONS, + }); + + const firstBuild = await harness.executeOnce(); + expect(firstBuild.result?.success).toBeTrue(); + harness + .expectFile('.angular/cache/0.0.0-PLACEHOLDER/lib/angular-build-library/.tsbuildinfo') + .toExist(); + + await harness.writeFile( + 'projects/lib/src/public-api.ts', + ` + export * from './lib/lib.service'; + export * from './lib/lib.component'; + export const CACHED_BUILD = true; + `, + ); + + const secondBuild = await harness.executeOnce(); + expect(secondBuild.result?.success).toBeTrue(); + const fesmContent = harness.readFile('dist/lib/fesm2022/lib.mjs'); + expect(fesmContent).toContain('LibComponent'); + expect(fesmContent).toContain('CACHED_BUILD'); + const dtsContent = harness.readFile('dist/lib/types/lib.d.ts'); + expect(dtsContent).toContain('LibComponent'); + expect(dtsContent).toContain('CACHED_BUILD'); + }); }); }); From b640b32e148ab68f820b390b1d9f03ae9a809266 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Thu, 15 Oct 2026 12:26:33 +0000 Subject: [PATCH 39/52] fix(@angular/build): use module.registerHooks() for in-memory ESM loader Node.js 26 runtime-deprecates `module.register()` (`DEP0205`) in favor of synchronous `module.registerHooks()`. Update the server-rendering in-memory ESM loader hooks to make `load` synchronous using `readFileSync` and register the hooks directly via `registerHooks({ resolve, load })`. Closes #34358 --- .../esm-in-memory-loader/loader-hooks.ts | 6 +- .../esm-in-memory-loader/loader-hooks_spec.ts | 69 +++++++++++++------ .../esm-in-memory-loader/register-hooks.ts | 7 +- 3 files changed, 56 insertions(+), 26 deletions(-) diff --git a/packages/angular/build/src/utils/server-rendering/esm-in-memory-loader/loader-hooks.ts b/packages/angular/build/src/utils/server-rendering/esm-in-memory-loader/loader-hooks.ts index 6f21bfbc739b..6ff4c8f8191c 100644 --- a/packages/angular/build/src/utils/server-rendering/esm-in-memory-loader/loader-hooks.ts +++ b/packages/angular/build/src/utils/server-rendering/esm-in-memory-loader/loader-hooks.ts @@ -8,7 +8,7 @@ import assert from 'node:assert'; import { randomUUID } from 'node:crypto'; -import { readFile } from 'node:fs/promises'; +import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import { fileURLToPath, pathToFileURL } from 'node:url'; @@ -110,7 +110,7 @@ export function resolve( }); } -export async function load(url: string, context: { format?: string | null }, nextLoad: Function) { +export function load(url: string, context: { format?: string | null }, nextLoad: Function) { const { format } = context; // Load the file from memory if the URL is based in the virtual root @@ -137,7 +137,7 @@ export async function load(url: string, context: { format?: string | null }, nex } const filePath = fileURLToPath(url); - const fileBytes = await readFile(filePath); + const fileBytes = readFileSync(filePath); const source = Buffer.concat([NG_SERVER_MODE_INIT_BYTES, fileBytes]); return { diff --git a/packages/angular/build/src/utils/server-rendering/esm-in-memory-loader/loader-hooks_spec.ts b/packages/angular/build/src/utils/server-rendering/esm-in-memory-loader/loader-hooks_spec.ts index 2b7622145378..0b32c2248b10 100644 --- a/packages/angular/build/src/utils/server-rendering/esm-in-memory-loader/loader-hooks_spec.ts +++ b/packages/angular/build/src/utils/server-rendering/esm-in-memory-loader/loader-hooks_spec.ts @@ -6,6 +6,10 @@ * found in the LICENSE file at https://angular.dev/license */ +import assert from 'node:assert'; +import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import { pathToFileURL } from 'node:url'; import { initialize, load, resolve } from './loader-hooks'; import { createSharedServerFiles } from './utils'; @@ -124,12 +128,12 @@ describe('esm-in-memory-loader loader-hooks', () => { }); describe('load', () => { - it('should load in-memory file source from SharedArrayBuffer backed Uint8Array', async () => { + it('should load in-memory file source from SharedArrayBuffer backed Uint8Array', () => { const memoryUrl = new URL('./main.server.mjs', 'memory://').href; const rootResolve = resolve(memoryUrl, { parentURL: undefined }, () => {}); const nextLoad = jasmine.createSpy('nextLoad'); - const result = await load(rootResolve.url, { format: 'module' }, nextLoad); + const result = load(rootResolve.url, { format: 'module' }, nextLoad); expect(nextLoad).not.toHaveBeenCalled(); expect(result.format).toBe('module'); @@ -137,12 +141,12 @@ describe('esm-in-memory-loader loader-hooks', () => { expect(result.source).toBe('export const main = true;'); }); - it('should load in-memory file with multi-byte UTF-8 characters', async () => { + it('should load in-memory file with multi-byte UTF-8 characters', () => { const memoryUrl = new URL('./utf8.mjs', 'memory://').href; const rootResolve = resolve(memoryUrl, { parentURL: undefined }, () => {}); const nextLoad = jasmine.createSpy('nextLoad'); - const result = await load(rootResolve.url, { format: 'module' }, nextLoad); + const result = load(rootResolve.url, { format: 'module' }, nextLoad); expect(nextLoad).not.toHaveBeenCalled(); expect(result.format).toBe('module'); @@ -150,12 +154,12 @@ describe('esm-in-memory-loader loader-hooks', () => { expect(result.source).toBe('export const text = "🔥 UTF-8 🚀";'); }); - it('should load in-memory file with empty content', async () => { + it('should load in-memory file with empty content', () => { const memoryUrl = new URL('./empty.mjs', 'memory://').href; const rootResolve = resolve(memoryUrl, { parentURL: undefined }, () => {}); const nextLoad = jasmine.createSpy('nextLoad'); - const result = await load(rootResolve.url, { format: 'module' }, nextLoad); + const result = load(rootResolve.url, { format: 'module' }, nextLoad); expect(nextLoad).not.toHaveBeenCalled(); expect(result.format).toBe('module'); @@ -163,7 +167,7 @@ describe('esm-in-memory-loader loader-hooks', () => { expect(result.source).toBe(''); }); - it('should load in-memory file source with non-zero byteOffset in Uint8Array', async () => { + it('should load in-memory file source with non-zero byteOffset in Uint8Array', () => { const target = 'export const sliced = 42;'; const fullBuffer = Buffer.from(`__PADDING__${target}__MORE__`); const offset = Buffer.byteLength('__PADDING__', 'utf-8'); @@ -181,7 +185,7 @@ describe('esm-in-memory-loader loader-hooks', () => { const rootResolve = resolve(memoryUrl, { parentURL: undefined }, () => {}); const nextLoad = jasmine.createSpy('nextLoad'); - const result = await load(rootResolve.url, { format: 'module' }, nextLoad); + const result = load(rootResolve.url, { format: 'module' }, nextLoad); expect(nextLoad).not.toHaveBeenCalled(); expect(result.format).toBe('module'); @@ -189,7 +193,7 @@ describe('esm-in-memory-loader loader-hooks', () => { expect(result.source).toBe(target); }); - it('should load in-memory file source when outputFiles contain string values', async () => { + it('should load in-memory file source when outputFiles contain string values', () => { initialize({ workspaceRoot, outputFiles: { @@ -201,7 +205,7 @@ describe('esm-in-memory-loader loader-hooks', () => { const rootResolve = resolve(memoryUrl, { parentURL: undefined }, () => {}); const nextLoad = jasmine.createSpy('nextLoad'); - const result = await load(rootResolve.url, { format: 'module' }, nextLoad); + const result = load(rootResolve.url, { format: 'module' }, nextLoad); expect(nextLoad).not.toHaveBeenCalled(); expect(result.format).toBe('module'); @@ -209,21 +213,46 @@ describe('esm-in-memory-loader loader-hooks', () => { expect(result.source).toBe('export const fromString = 1;'); }); - it('should reject when in-memory file does not exist in outputFiles', async () => { + it('should throw when in-memory file does not exist in outputFiles', () => { const memoryUrl = new URL('./main.server.mjs', 'memory://').href; const rootResolve = resolve(memoryUrl, { parentURL: undefined }, () => {}); const nonExistentVirtualUrl = rootResolve.url.replace('main.server.mjs', 'missing.mjs'); const nextLoad = jasmine.createSpy('nextLoad'); - await expectAsync( - load(nonExistentVirtualUrl, { format: 'module' }, nextLoad), - ).toBeRejectedWithError(/Resolved in-memory ESM file should always exist/); + expect(() => load(nonExistentVirtualUrl, { format: 'module' }, nextLoad)).toThrowError( + /Resolved in-memory ESM file should always exist/, + ); expect(nextLoad).not.toHaveBeenCalled(); }); - it('should delegate to nextLoad for non-angular file URLs', async () => { - const nextLoad = jasmine.createSpy('nextLoad').and.resolveTo({ format: 'module' }); - const result = await load( + it('should prepend ngServerMode initialization for @angular/ file URLs', async () => { + const baseTmpDir = process.env['TEST_TMPDIR']; + assert(baseTmpDir, 'TEST_TMPDIR is not set'); + const tmpDir = await mkdtemp(join(baseTmpDir, 'loader-hooks-test-')); + + try { + const angularDir = join(tmpDir, '@angular/core'); + await mkdir(angularDir, { recursive: true }); + const filePath = join(angularDir, 'index.mjs'); + await writeFile(filePath, 'export const VERSION = "1.0.0";'); + + const nextLoad = jasmine.createSpy('nextLoad'); + const result = load(pathToFileURL(filePath).href, { format: 'module' }, nextLoad); + + expect(nextLoad).not.toHaveBeenCalled(); + expect(result.format).toBe('module'); + expect(result.shortCircuit).toBeTrue(); + expect(new TextDecoder().decode(result.source)).toBe( + 'var ngServerMode=true;export const VERSION = "1.0.0";', + ); + } finally { + await rm(tmpDir, { recursive: true, force: true }); + } + }); + + it('should delegate to nextLoad for non-angular file URLs', () => { + const nextLoad = jasmine.createSpy('nextLoad').and.returnValue({ format: 'module' }); + const result = load( 'file:///workspace/node_modules/rxjs/index.js', { format: 'module' }, nextLoad, @@ -235,9 +264,9 @@ describe('esm-in-memory-loader loader-hooks', () => { expect(result.format).toBe('module'); }); - it('should delegate to nextLoad for non-memory non-file URLs', async () => { - const nextLoad = jasmine.createSpy('nextLoad').and.resolveTo({ format: 'builtin' }); - const result = await load('node:fs', { format: 'builtin' }, nextLoad); + it('should delegate to nextLoad for non-memory non-file URLs', () => { + const nextLoad = jasmine.createSpy('nextLoad').and.returnValue({ format: 'builtin' }); + const result = load('node:fs', { format: 'builtin' }, nextLoad); expect(nextLoad).toHaveBeenCalledWith('node:fs'); expect(result.format).toBe('builtin'); diff --git a/packages/angular/build/src/utils/server-rendering/esm-in-memory-loader/register-hooks.ts b/packages/angular/build/src/utils/server-rendering/esm-in-memory-loader/register-hooks.ts index b23fe297bc19..56747e17bd03 100644 --- a/packages/angular/build/src/utils/server-rendering/esm-in-memory-loader/register-hooks.ts +++ b/packages/angular/build/src/utils/server-rendering/esm-in-memory-loader/register-hooks.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.dev/license */ -import { register } from 'node:module'; -import { pathToFileURL } from 'node:url'; +import { registerHooks } from 'node:module'; import { workerData } from 'node:worker_threads'; +import { initialize, load, resolve } from './loader-hooks'; -register('./loader-hooks.js', { parentURL: pathToFileURL(__filename), data: workerData }); +initialize(workerData); +registerHooks({ resolve, load }); From c042a66fed76f8190f6dc739865af1144f9bf854 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Thu, 15 Oct 2026 10:50:57 +0000 Subject: [PATCH 40/52] refactor(@angular/build): export NormalizedAssetsPattern and avoid mutating input patterns Export the `NormalizedAssetsPattern` interface from `normalize-asset-patterns.ts`, avoid mutating input `AssetPatternClass` objects in place, and simplify directory detection using `statSync(..., { throwIfNoEntry: false })`. Also import `normalizeAssetPatterns` directly in `library/options.ts` and add test coverage for asset `ignore` patterns. --- .../build/src/builders/library/options.ts | 2 +- .../library/tests/options/assets_spec.ts | 3 + .../src/utils/normalize-asset-patterns.ts | 64 ++++++++++--------- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/packages/angular/build/src/builders/library/options.ts b/packages/angular/build/src/builders/library/options.ts index 14bc4514027d..23d18d6f4d8e 100644 --- a/packages/angular/build/src/builders/library/options.ts +++ b/packages/angular/build/src/builders/library/options.ts @@ -9,9 +9,9 @@ import type { BuilderContext } from '@angular-devkit/architect'; import path from 'node:path'; import type { StylesheetPluginsass } from '../../tools/esbuild/stylesheets/stylesheet-plugin-factory'; -import { normalizeAssetPatterns } from '../../utils'; import { supportColor } from '../../utils/color'; import { assertIsError } from '../../utils/error'; +import { normalizeAssetPatterns } from '../../utils/normalize-asset-patterns'; import { normalizeCacheOptions } from '../../utils/normalize-cache'; import { toPosixPath } from '../../utils/path'; import { diff --git a/packages/angular/build/src/builders/library/tests/options/assets_spec.ts b/packages/angular/build/src/builders/library/tests/options/assets_spec.ts index ded7743675ff..a596cbfe4e62 100644 --- a/packages/angular/build/src/builders/library/tests/options/assets_spec.ts +++ b/packages/angular/build/src/builders/library/tests/options/assets_spec.ts @@ -15,6 +15,7 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => await harness.writeFiles({ 'projects/lib/assets-dir/file-a.png': 'PNG_A', 'projects/lib/assets-dir/file-b.png': 'PNG_B', + 'projects/lib/assets-dir/ignored.png': 'PNG_IGNORED', 'projects/lib/assets-dir/file-c.svg': 'SVG_C', }); @@ -25,6 +26,7 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => glob: '**/*.png', input: 'projects/lib/assets-dir', output: 'assets', + ignore: ['ignored.png'], }, ], }); @@ -34,6 +36,7 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => expect(harness.readFile('dist/lib/assets/file-a.png')).toBe('PNG_A'); expect(harness.readFile('dist/lib/assets/file-b.png')).toBe('PNG_B'); + expect(harness.hasFile('dist/lib/assets/ignored.png')).toBeFalse(); expect(harness.hasFile('dist/lib/assets/file-c.svg')).toBeFalse(); }); diff --git a/packages/angular/build/src/utils/normalize-asset-patterns.ts b/packages/angular/build/src/utils/normalize-asset-patterns.ts index 66365e10df22..defa6511172f 100644 --- a/packages/angular/build/src/utils/normalize-asset-patterns.ts +++ b/packages/angular/build/src/utils/normalize-asset-patterns.ts @@ -6,18 +6,35 @@ * found in the LICENSE file at https://angular.dev/license */ -import assert from 'node:assert'; import { statSync } from 'node:fs'; -import * as path from 'node:path'; -import { AssetPattern, AssetPatternClass } from '../builders/application/schema'; +import path from 'node:path'; +import type { AssetPattern, AssetPatternClass } from '../builders/application/schema'; import { isSubDirectory } from './path'; +/** + * Asset pattern configuration normalized into its object form with a resolved `output` directory. + */ +export interface NormalizedAssetsPattern extends AssetPatternClass { + /** Relative output directory within the build output path. */ + output: string; +} + +/** + * Normalizes raw string and object asset patterns into {@link NormalizedAssetsPattern} objects + * and validates that all asset inputs and outputs stay within the workspace and output directories. + * + * @param assetPatterns Raw string or object asset patterns from builder options. + * @param workspaceRoot Workspace root directory path. + * @param projectRoot Project root directory path. + * @param projectSourceRoot Optional project source root directory path. + * @returns An array of normalized asset pattern configurations. + */ export function normalizeAssetPatterns( assetPatterns: AssetPattern[], workspaceRoot: string, projectRoot: string, projectSourceRoot: string | undefined, -): (AssetPatternClass & { output: string })[] { +): NormalizedAssetsPattern[] { if (assetPatterns.length === 0) { return []; } @@ -29,6 +46,8 @@ export function normalizeAssetPatterns( const resolvedProjectRoot = path.resolve(resolvedWorkspaceRoot, projectRoot); return assetPatterns.map((assetPattern) => { + let normalized: NormalizedAssetsPattern; + // Normalize string asset patterns to objects. if (typeof assetPattern === 'string') { const assetPath = path.normalize(assetPattern); @@ -46,45 +65,32 @@ export function normalizeAssetPatterns( throw new Error(`The ${assetPattern} asset path must be within the workspace root.`); } - let glob: string, input: string; - let isDirectory: boolean; - + let isDirectory = true; try { - isDirectory = statSync(resolvedAssetPath).isDirectory(); - } catch { - isDirectory = true; - } - - if (isDirectory) { - // Folders get a recursive star glob. - glob = '**/*'; - // Input directory is their original path. - input = assetPath; - } else { - // Files are their own glob. - glob = path.basename(assetPath); - // Input directory is their original dirname. - input = path.dirname(assetPath); - } + isDirectory = statSync(resolvedAssetPath, { throwIfNoEntry: false })?.isDirectory() ?? true; + } catch {} + const glob = isDirectory ? '**/*' : path.basename(assetPath); + const input = isDirectory ? assetPath : path.dirname(assetPath); // Output directory for both is the relative path from the root to input. const output = path.relative(root, path.resolve(resolvedWorkspaceRoot, input)); - assetPattern = { glob, input, output }; + normalized = { glob, input, output }; } else { if (!isSubDirectory(resolvedWorkspaceRoot, assetPattern.input)) { throw new Error(`The ${assetPattern.input} asset path must be within the workspace root.`); } - assetPattern.output = path.join('.', assetPattern.output ?? ''); + normalized = { + ...assetPattern, + output: path.join('.', assetPattern.output ?? ''), + }; } - assert(assetPattern.output !== undefined); - - if (assetPattern.output.startsWith('..')) { + if (normalized.output.startsWith('..')) { throw new Error('An asset cannot be written to a location outside of the output path.'); } - return assetPattern as AssetPatternClass & { output: string }; + return normalized; }); } From d02d39caa64b610d7ee849d9a98d4a2109e29e70 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Thu, 15 Oct 2026 10:55:57 +0000 Subject: [PATCH 41/52] refactor(@angular/build): encapsulate library build state in BuilderState and ExecutionResult Introduce `BuilderState` and `ExecutionResult` to replace `SingleBuildState`, `BuildActionResult`, `LibraryCompilationDiagnostics`, and manual `watchedCompilationFiles` parameter threading across the library builder pipeline. `BuilderState` manages incremental compilation state, watched compilation files, pending compilation modifications across aborted watch iterations, and `ExecutionResult` diagnostic collection. --- .../src/builders/library/builder-state.ts | 240 +++++++++++++++++ .../builders/library/builder-state_spec.ts | 155 +++++++++++ .../build/src/builders/library/builder.ts | 122 ++++----- .../src/builders/library/execution-result.ts | 75 ++++++ .../build/src/builders/library/index.ts | 2 +- .../builders/library/pipeline/build-action.ts | 244 +++++------------- .../builders/library/pipeline/compilation.ts | 157 ++++------- .../builders/library/pipeline/entry-points.ts | 61 +++-- .../library/pipeline/entry-points_spec.ts | 220 ++++++++++------ .../library/pipeline/package-manifests.ts | 16 +- .../build/src/builders/library/types.ts | 85 ++++-- 11 files changed, 883 insertions(+), 494 deletions(-) create mode 100644 packages/angular/build/src/builders/library/builder-state.ts create mode 100644 packages/angular/build/src/builders/library/builder-state_spec.ts create mode 100644 packages/angular/build/src/builders/library/execution-result.ts diff --git a/packages/angular/build/src/builders/library/builder-state.ts b/packages/angular/build/src/builders/library/builder-state.ts new file mode 100644 index 000000000000..c20ef26ea7c5 --- /dev/null +++ b/packages/angular/build/src/builders/library/builder-state.ts @@ -0,0 +1,240 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { ExecutionResult } from './execution-result'; +import type { + BundleResult, + LibraryCompilationOutput, + NormalizedLibraryOptions, + SingleProgramCache, +} from './types'; + +/** + * Encapsulates incremental compilation state, watched compilation file tracking, + * and execution results across watch-mode rebuilds. + */ +export class BuilderState { + readonly #watchedCompilationFiles = new Set(); + readonly #pendingCompilationFiles = new Set(); + + #executionResult = new ExecutionResult(); + #singleProgramCache?: SingleProgramCache; + #compilationMode?: 'partial' | 'full'; + + /** Map of entry point names to their previous bundle results. */ + readonly previousBundleResults = new Map(); + + /** Set of changed POSIX ESM file paths pending bundling. */ + readonly pendingChangedEsmFiles = new Set(); + + /** Set of changed POSIX TypeScript declaration file paths pending bundling. */ + readonly pendingChangedDtsFiles = new Set(); + + /** Whether the previous build iteration encountered a compilation or diagnostic error. */ + hasCompilationError = false; + + /** Whether package.json and secondary entry point manifests have been emitted. */ + hasEmittedManifests = false; + + /** Whether the last emitted root package.json included a tslib dependency. */ + hasEmittedTslib = false; + + /** Whether static assets have been emitted in a prior iteration. */ + hasEmittedAssets = false; + + /** Whether entry points in package.json changed since the last compilation. */ + hasEntryPointsChanges = false; + + constructor( + options?: Partial< + Pick + >, + ) { + if (options?.tsConfigPath) { + this.#watchedCompilationFiles.add(options.tsConfigPath); + } + if (options?.packageJsonPath) { + this.#watchedCompilationFiles.add(options.packageJsonPath); + } + if (options?.entryPoints) { + for (const entryPoint of options.entryPoints.values()) { + this.#watchedCompilationFiles.add(entryPoint.entryFilePath); + } + } + } + + /** Cached unified TypeScript and Angular compilation state. */ + get singleProgramCache(): SingleProgramCache | undefined { + return this.#singleProgramCache; + } + + /** Effective compilation mode resolved from builder options and tsconfig. */ + get compilationMode(): 'partial' | 'full' | undefined { + return this.#compilationMode; + } + + /** Whether any active entry point bundle imports `tslib`. */ + get hasTslibImport(): boolean { + for (const result of this.previousBundleResults.values()) { + if (result.hasTslibImport) { + return true; + } + } + + return false; + } + + /** + * Set of POSIX file paths tracked for compilation and configuration + * (including `tsconfig.json`, `package.json`, entry points, and referenced source, + * template, and stylesheet files). + */ + get watchedCompilationFiles(): Set { + return this.#watchedCompilationFiles; + } + + /** + * Execution result holding errors, warnings, and logs for the current build iteration. + */ + get executionResult(): ExecutionResult { + return this.#executionResult; + } + + /** + * Resets the execution result for a new build iteration. + * + * @returns The fresh `ExecutionResult` instance for the current build iteration. + */ + resetExecutionResult(): ExecutionResult { + this.#executionResult = new ExecutionResult(); + + return this.#executionResult; + } + + /** + * Determines whether compilation and bundling need to run for the current build iteration. + * Also records incoming modified files so they are retained if the iteration aborts early. + * + * @param packageJsonPath Normalized POSIX path to the library's `package.json`. + * @param modifiedFiles Optional set of modified POSIX file paths in watch mode. + * @returns `true` if entry points should be compiled; otherwise `false`. + */ + shouldCompileEntryPoints(packageJsonPath: string, modifiedFiles?: ReadonlySet): boolean { + if (modifiedFiles) { + for (const file of modifiedFiles) { + if (file !== packageJsonPath) { + this.#pendingCompilationFiles.add(file); + } + } + } + + if ( + !modifiedFiles || + !this.#singleProgramCache || + this.hasCompilationError || + this.hasEntryPointsChanges || + this.pendingChangedEsmFiles.size > 0 || + this.pendingChangedDtsFiles.size > 0 + ) { + return true; + } + + for (const file of this.#pendingCompilationFiles) { + if (this.#watchedCompilationFiles.has(file)) { + return true; + } + } + + this.#pendingCompilationFiles.clear(); + + return false; + } + + /** + * Returns the effective set of modified POSIX file paths for compilation, + * merging any pending compilation files from earlier aborted iterations. + * + * @param modifiedFiles Optional set of modified POSIX file paths from the current iteration. + * @returns Merged set of modified POSIX file paths, or `undefined` for a full compilation. + */ + getCompilationModifiedFiles(modifiedFiles?: ReadonlySet): Set | undefined { + if (!modifiedFiles) { + this.#pendingCompilationFiles.clear(); + + return undefined; + } + + const files = new Set(modifiedFiles); + for (const file of this.#pendingCompilationFiles) { + files.add(file); + } + + return files; + } + + /** + * Records compilation output into the build state, updating the program cache, + * watched compilation files, and pending changed ESM/DTS file sets. + * + * @param output The compilation output produced by `compileLibrary`. + */ + recordCompilationOutput(output: LibraryCompilationOutput): void { + this.#pendingCompilationFiles.clear(); + this.#singleProgramCache = output.cache; + if (this.#compilationMode !== output.compilationMode) { + this.#compilationMode = output.compilationMode; + this.hasEmittedManifests = false; + } + + for (const file of output.referencedFiles) { + this.#watchedCompilationFiles.add(file); + } + for (const file of output.changedEsmFiles) { + this.pendingChangedEsmFiles.add(file); + } + for (const file of output.changedDtsFiles) { + this.pendingChangedDtsFiles.add(file); + } + } + + /** + * Records active bundle results across entry points after compilation and bundling succeed, + * clearing pending compilation/bundle flags. + * + * @param bundleResults Newly bundled results keyed by entry point name. + */ + recordBundleOutput(bundleResults: ReadonlyMap): void { + this.hasCompilationError = false; + this.hasEntryPointsChanges = false; + this.pendingChangedEsmFiles.clear(); + this.pendingChangedDtsFiles.clear(); + + for (const [name, bundleResult] of bundleResults) { + this.previousBundleResults.set(name, bundleResult); + } + } + + /** + * Disposes active compilation resources and clears cached state. + */ + async dispose(): Promise { + await this.#singleProgramCache?.compilationInstance.close?.(); + this.#singleProgramCache = undefined; + this.#compilationMode = undefined; + this.hasEmittedTslib = false; + this.hasEmittedAssets = false; + this.hasCompilationError = false; + this.hasEmittedManifests = false; + this.hasEntryPointsChanges = false; + this.previousBundleResults.clear(); + this.pendingChangedEsmFiles.clear(); + this.pendingChangedDtsFiles.clear(); + this.#pendingCompilationFiles.clear(); + this.#watchedCompilationFiles.clear(); + } +} diff --git a/packages/angular/build/src/builders/library/builder-state_spec.ts b/packages/angular/build/src/builders/library/builder-state_spec.ts new file mode 100644 index 000000000000..9cf744d288bc --- /dev/null +++ b/packages/angular/build/src/builders/library/builder-state_spec.ts @@ -0,0 +1,155 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { BuilderState } from './builder-state'; +import type { LibraryCompilationOutput, SingleProgramCache } from './types'; + +describe('BuilderState', () => { + const packageJsonPath = '/workspace/projects/my-lib/package.json'; + const tsConfigPath = '/workspace/projects/my-lib/tsconfig.lib.json'; + const entryFilePath = '/workspace/projects/my-lib/src/public-api.ts'; + + function createMockCache(closeSpy?: jasmine.Spy): SingleProgramCache { + return { + compilationInstance: { + close: closeSpy, + } as unknown as SingleProgramCache['compilationInstance'], + esmFiles: new Map(), + dtsFiles: new Map(), + failedFiles: new Set(), + }; + } + + function createMockCompilationOutput( + overrides: Partial = {}, + ): LibraryCompilationOutput { + return { + esmFiles: new Map(), + dtsFiles: new Map(), + changedEsmFiles: new Set(), + changedDtsFiles: new Set(), + referencedFiles: new Set(), + cache: createMockCache(), + hasStylesheetErrors: false, + diagnosePromise: Promise.resolve(), + declarationMap: false, + compilationMode: 'partial', + ...overrides, + }; + } + + describe('ExecutionResult', () => { + it('should track logs, warnings, and errors and reset per iteration', () => { + const state = new BuilderState(); + expect(state.executionResult.hasErrors).toBeFalse(); + expect(state.executionResult.output).toEqual({ success: true }); + + state.executionResult.addLog('Bundling my-lib'); + state.executionResult.addWarning('Unused import'); + state.executionResult.addWarnings(['Deprecated API']); + state.executionResult.addError('Type error'); + state.executionResult.addErrors(['Syntax error']); + + expect(state.executionResult.logs).toEqual(['Bundling my-lib']); + expect(state.executionResult.warnings).toEqual(['Unused import', 'Deprecated API']); + expect(state.executionResult.errors).toEqual(['Type error', 'Syntax error']); + expect(state.executionResult.hasErrors).toBeTrue(); + expect(state.executionResult.output).toEqual({ success: false }); + + const freshResult = state.resetExecutionResult(); + expect(freshResult).toBe(state.executionResult); + expect(freshResult.hasErrors).toBeFalse(); + expect(freshResult.logs).toEqual([]); + expect(freshResult.warnings).toEqual([]); + expect(freshResult.errors).toEqual([]); + }); + }); + + describe('shouldCompileEntryPoints & getCompilationModifiedFiles', () => { + it('should preserve pending compilation files across aborted iterations', () => { + const state = new BuilderState({ + packageJsonPath, + tsConfigPath, + entryPoints: new Map([ + [ + '.', + { + subpath: '.', + name: '.', + displayName: 'my-lib', + bundleName: 'my-lib', + entryFilePath, + isPrimary: true, + }, + ], + ]), + }); + + state.recordCompilationOutput( + createMockCompilationOutput({ + referencedFiles: new Set([entryFilePath]), + }), + ); + + // Iteration 1: entryFilePath changes, but build aborts before recordCompilationOutput + expect( + state.shouldCompileEntryPoints(packageJsonPath, new Set([entryFilePath, packageJsonPath])), + ).toBeTrue(); + + // Iteration 2: only package.json changes on recovery + expect( + state.shouldCompileEntryPoints(packageJsonPath, new Set([packageJsonPath])), + ).toBeTrue(); + expect(state.getCompilationModifiedFiles(new Set([packageJsonPath]))).toEqual( + new Set([packageJsonPath, entryFilePath]), + ); + + // Once compilation output is recorded, pending compilation files are cleared + state.recordCompilationOutput(createMockCompilationOutput()); + expect( + state.shouldCompileEntryPoints(packageJsonPath, new Set([packageJsonPath])), + ).toBeFalse(); + }); + + it('should invalidate hasEmittedManifests when compilationMode changes', () => { + const state = new BuilderState(); + state.hasEmittedManifests = true; + state.recordCompilationOutput(createMockCompilationOutput({ compilationMode: 'partial' })); + expect(state.hasEmittedManifests).toBeFalse(); + + state.hasEmittedManifests = true; + state.recordCompilationOutput(createMockCompilationOutput({ compilationMode: 'partial' })); + expect(state.hasEmittedManifests).toBeTrue(); + + state.recordCompilationOutput(createMockCompilationOutput({ compilationMode: 'full' })); + expect(state.hasEmittedManifests).toBeFalse(); + }); + }); + + describe('dispose', () => { + it('should close compilationInstance and clear cached state on dispose', async () => { + const closeSpy = jasmine.createSpy('close').and.resolveTo(); + const state = new BuilderState({ packageJsonPath }); + state.recordCompilationOutput( + createMockCompilationOutput({ + cache: createMockCache(closeSpy), + changedEsmFiles: new Set(['/a.js']), + changedDtsFiles: new Set(['/a.d.ts']), + }), + ); + + await state.dispose(); + + expect(closeSpy).toHaveBeenCalledTimes(1); + expect(state.singleProgramCache).toBeUndefined(); + expect(state.pendingChangedEsmFiles).toHaveSize(0); + expect(state.pendingChangedDtsFiles).toHaveSize(0); + expect(state.watchedCompilationFiles).toHaveSize(0); + }); + }); +}); diff --git a/packages/angular/build/src/builders/library/builder.ts b/packages/angular/build/src/builders/library/builder.ts index c3c2149adf5b..fa8e717c9776 100644 --- a/packages/angular/build/src/builders/library/builder.ts +++ b/packages/angular/build/src/builders/library/builder.ts @@ -8,6 +8,7 @@ import type { BuilderContext, BuilderOutput } from '@angular-devkit/architect'; import type { logging } from '@angular-devkit/core'; +import type { ComponentStylesheetBundler } from '../../tools/esbuild/angular/component-stylesheets'; import { resetSassWorkerPoolCaches, shutdownSassWorkerPool, @@ -23,13 +24,14 @@ import { purgeStaleBuildCache } from '../../utils/purge-cache'; import { getSupportedBrowsers } from '../../utils/supported-browsers'; import { assertCompatibleAngularVersion } from '../../utils/version'; import type { BuildWatcher } from '../../utils/watcher'; +import { BuilderState } from './builder-state'; +import type { ExecutionResult } from './execution-result'; import { normalizeLibraryOptions } from './options'; -import type { BuildActionResult } from './pipeline/build-action'; +import type { BuildActionContext } from './pipeline/build-action'; import { updateWatchedEntryPoints } from './pipeline/entry-points'; -import type { createComponentStylesheetBundlerForLibrary } from './pipeline/stylesheet-bundler'; import { loadPackageJson } from './pipeline/utils'; import type { Schema as LibraryBuilderOptions } from './schema'; -import type { NormalizedLibraryOptions, SingleBuildState } from './types'; +import type { NormalizedLibraryOptions } from './types'; /** * Executes the library builder to compile, bundle, and package an Angular library into the Angular Package Format (APF). @@ -63,8 +65,6 @@ export async function* executeLibraryBuilder( projectRoot, outputPath, deleteOutputPath, - packageJsonPath, - tsConfigPath, watch: isWatchMode, poll, cacheOptions, @@ -89,17 +89,14 @@ export async function* executeLibraryBuilder( } // Dynamically lazy-loaded to prevent importing dependencies at the top level. - const [ - { buildAction, createSingleBuildState, hasModifiedWatchedFile }, - { createComponentStylesheetBundlerForLibrary }, - ] = await Promise.all([ + const [{ buildAction }, { createComponentStylesheetBundlerForLibrary }] = await Promise.all([ import('./pipeline/build-action'), import('./pipeline/stylesheet-bundler'), ]); - let stylesheetBundler: ReturnType | undefined; + let stylesheetBundler: ComponentStylesheetBundler | undefined; let watcher: BuildWatcher | undefined; - const buildState = createSingleBuildState(); + const buildState = new BuilderState(normalizedOptions); try { const browsers = getSupportedBrowsers(projectRoot, logger); @@ -110,13 +107,6 @@ export async function* executeLibraryBuilder( target, ); - // Track all referenced compilation files for watch mode - const watchedCompilationFiles = new Set([tsConfigPath, packageJsonPath]); - - for (const entryPoint of normalizedOptions.entryPoints.values()) { - watchedCompilationFiles.add(entryPoint.entryFilePath); - } - if (isWatchMode) { const { setupWatcher } = await import('../../utils/watcher'); watcher = await setupWatcher({ @@ -127,7 +117,10 @@ export async function* executeLibraryBuilder( poll, preserveSymlinks, signal, - watchFiles: watchedCompilationFiles, + watchFiles: [ + ...buildState.watchedCompilationFiles, + ...normalizedOptions.assets.map((asset) => asset.input), + ], }); context.addTeardown?.(() => void watcher?.close()); @@ -139,11 +132,10 @@ export async function* executeLibraryBuilder( { options: normalizedOptions, stylesheetBundler, - watchedCompilationFiles, isWatchMode, - context, buildState, }, + logger, withProgress, watcher, buildAction, @@ -163,12 +155,10 @@ export async function* executeLibraryBuilder( watcher, normalizedOptions, stylesheetBundler, - watchedCompilationFiles, - context, + logger, withProgress, buildState, buildAction, - hasModifiedWatchedFile, signal, ); } finally { @@ -178,7 +168,7 @@ export async function* executeLibraryBuilder( await Promise.allSettled([ watcher?.close(), stylesheetBundler?.dispose(), - buildState.singleProgramCache?.compilationInstance.close?.(), + buildState.dispose(), ]); } } @@ -189,6 +179,7 @@ export async function* executeLibraryBuilder( * * @param message Progress spinner message to display while building. * @param actionContext The build action context and state. + * @param logger The Architect logger API. * @param withProgress Progress wrapper function (`withSpinner` or `withNoProgress`). * @param watcher Optional file watcher for watch mode. * @param buildAction The library build action function to execute. @@ -196,33 +187,34 @@ export async function* executeLibraryBuilder( */ async function executeBuild( message: string, - actionContext: import('./pipeline/build-action').BuildActionContext, + actionContext: BuildActionContext, + logger: logging.LoggerApi, withProgress: typeof withSpinner, watcher: BuildWatcher | undefined, buildAction: typeof import('./pipeline/build-action').buildAction, ): Promise { const startTime = process.hrtime.bigint(); - const { context, watchedCompilationFiles, isWatchMode, options } = actionContext; + const { buildState, isWatchMode, options } = actionContext; try { const result = await withProgress(message, () => buildAction(actionContext)); - logMessages(context.logger, result); + logMessages(logger, result); - const success = result.errors.length === 0; - logBuildResult(context.logger, startTime, success, options.outputPath); - if (success && isWatchMode) { + const { output } = result; + logBuildResult(logger, startTime, output.success, options.outputPath); + if (output.success && isWatchMode) { logCumulativeDurations(); } - return { success }; + return output; } catch (error) { assertIsError(error); - logBuildResult(context.logger, startTime, false); + logBuildResult(logger, startTime, false); return { success: false, error: error.message }; } finally { if (watcher) { - watcher.add(Array.from(watchedCompilationFiles)); + watcher.add(Array.from(buildState.watchedCompilationFiles)); const { assetsToEmit } = actionContext; if (assetsToEmit?.length) { @@ -238,32 +230,29 @@ async function executeBuild( * @param watcher The file watcher instance. * @param options The normalized library builder options with POSIX paths. * @param stylesheetBundler The component stylesheet bundler instance. - * @param watchedCompilationFiles Set of POSIX file paths tracked for compilation. - * @param context The Architect builder context. + * @param logger The Architect logger API. * @param withProgress Progress wrapper function (`withSpinner` or `withNoProgress`). * @param buildState The state preserved across incremental builds. * @param buildAction The library build action function to execute. - * @param hasModifiedWatchedFile Helper to check whether watched compilation files changed. - * @param signal Optional abort signal to terminate the watch loop. + * @param signal Abort signal to terminate the watch loop. + * @returns An async iterator yielding builder output results. */ async function* runWatchLoop( watcher: BuildWatcher, options: NormalizedLibraryOptions, - stylesheetBundler: ReturnType, - watchedCompilationFiles: Set, - context: BuilderContext, + stylesheetBundler: ComponentStylesheetBundler, + logger: logging.LoggerApi, withProgress: typeof withSpinner, - buildState: SingleBuildState, + buildState: BuilderState, buildAction: typeof import('./pipeline/build-action').buildAction, - hasModifiedWatchedFile: typeof import('./pipeline/build-action').hasModifiedWatchedFile, - signal?: AbortSignal, + signal: AbortSignal, ): AsyncIterableIterator { const { collectAssetsToEmit } = await import('./pipeline/assets'); const { workspaceRoot, packageJsonPath, assets, clearScreen } = options; for await (const changes of watcher) { - if (signal?.aborted) { + if (signal.aborted) { break; } @@ -299,29 +288,17 @@ async function* runWatchLoop( } // Check if package.json was modified - let hasPackageJsonChanges = false; if (changedFiles.has(packageJsonPath)) { + buildState.hasEmittedManifests = false; try { const packageJson = await loadPackageJson(packageJsonPath); - if (!packageJson.name) { - throw new Error(`The package.json at '${packageJsonPath}' must contain a 'name'.`); - } - options.packageJson = packageJson; - options.packageName = packageJson.name; - - updateWatchedEntryPoints( - packageJson, - options, - buildState, - watchedCompilationFiles, - packageJsonPath, - ); - - hasPackageJsonChanges = true; + updateWatchedEntryPoints(packageJson, options, buildState); } catch (error) { assertIsError(error); await buildState.singleProgramCache?.compilationInstance.update?.(changedFiles); - buildState.hasEmittedManifests = false; + if (buildState.shouldCompileEntryPoints(packageJsonPath, changedFiles)) { + buildState.hasCompilationError = true; + } yield { success: false, @@ -331,11 +308,10 @@ async function* runWatchLoop( } } - const hasSourceChanges = - !buildState.singleProgramCache || - buildState.hasCompilationError || - buildState.hasEntryPointsChanges || - hasModifiedWatchedFile(changedFiles, watchedCompilationFiles, packageJsonPath); + const hasSourceChanges = buildState.shouldCompileEntryPoints(packageJsonPath, changedFiles); + if (!hasSourceChanges) { + await buildState.singleProgramCache?.compilationInstance.update?.(changedFiles); + } const assetsToEmit = await collectAssetsToEmit( assets, @@ -343,7 +319,7 @@ async function* runWatchLoop( buildState.hasEmittedAssets ? changedFiles : undefined, ); - if (!hasSourceChanges && !hasPackageJsonChanges && assetsToEmit.length === 0) { + if (!hasSourceChanges && buildState.hasEmittedManifests && assetsToEmit.length === 0) { continue; } @@ -352,13 +328,12 @@ async function* runWatchLoop( { options, stylesheetBundler, - watchedCompilationFiles, isWatchMode: true, - context, buildState, modifiedFiles: changedFiles, assetsToEmit, }, + logger, withProgress, watcher, buildAction, @@ -370,12 +345,9 @@ async function* runWatchLoop( * Logs informational, warning, and error messages produced during a build iteration. * * @param logger The Architect logger API. - * @param result The build action result containing logs, warnings, and errors. + * @param result The build execution result containing logs, warnings, and errors. */ -function logMessages( - logger: logging.LoggerApi, - { logs, warnings, errors }: BuildActionResult, -): void { +function logMessages(logger: logging.LoggerApi, { logs, warnings, errors }: ExecutionResult): void { if (logs.length) { logger.info(logs.join('\n')); } diff --git a/packages/angular/build/src/builders/library/execution-result.ts b/packages/angular/build/src/builders/library/execution-result.ts new file mode 100644 index 000000000000..4f9826360503 --- /dev/null +++ b/packages/angular/build/src/builders/library/execution-result.ts @@ -0,0 +1,75 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import type { BuilderOutput } from '@angular-devkit/architect'; + +/** + * Encapsulates the diagnostic messages (`errors`, `warnings`, and `logs`) and + * builder output status for a single library build iteration. + */ +export class ExecutionResult { + readonly #errors: string[] = []; + readonly #warnings: string[] = []; + readonly #logs: string[] = []; + + /** Formatted error messages produced during the build iteration. */ + get errors(): readonly string[] { + return this.#errors; + } + + /** Formatted warning messages produced during the build iteration. */ + get warnings(): readonly string[] { + return this.#warnings; + } + + /** Informational log messages produced during the build iteration. */ + get logs(): readonly string[] { + return this.#logs; + } + + /** Whether any errors have been recorded in the build iteration. */ + get hasErrors(): boolean { + return this.#errors.length > 0; + } + + /** Architect builder output status for the build iteration. */ + get output(): BuilderOutput { + return { + success: !this.hasErrors, + }; + } + + /** Records an informational log message. */ + addLog(value: string): void { + this.#logs.push(value); + } + + /** Records a formatted error message. */ + addError(error: string): void { + this.#errors.push(error); + } + + /** Records multiple formatted error messages. */ + addErrors(errors: Iterable): void { + for (const error of errors) { + this.#errors.push(error); + } + } + + /** Records a formatted warning message. */ + addWarning(warning: string): void { + this.#warnings.push(warning); + } + + /** Records multiple formatted warning messages. */ + addWarnings(warnings: Iterable): void { + for (const warning of warnings) { + this.#warnings.push(warning); + } + } +} diff --git a/packages/angular/build/src/builders/library/index.ts b/packages/angular/build/src/builders/library/index.ts index 6a6ddf7a1ce7..da1f5d9385a3 100644 --- a/packages/angular/build/src/builders/library/index.ts +++ b/packages/angular/build/src/builders/library/index.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import { Builder, createBuilder } from '@angular-devkit/architect'; +import { type Builder, createBuilder } from '@angular-devkit/architect'; import { executeLibraryBuilder } from './builder'; import type { Schema as LibraryBuilderOptions } from './schema'; diff --git a/packages/angular/build/src/builders/library/pipeline/build-action.ts b/packages/angular/build/src/builders/library/pipeline/build-action.ts index f121048b1fc7..734ea23c544e 100644 --- a/packages/angular/build/src/builders/library/pipeline/build-action.ts +++ b/packages/angular/build/src/builders/library/pipeline/build-action.ts @@ -6,44 +6,20 @@ * found in the LICENSE file at https://angular.dev/license */ -import type { BuilderContext } from '@angular-devkit/architect'; import path from 'node:path'; import type { ComponentStylesheetBundler } from '../../../tools/esbuild/angular/component-stylesheets'; import { emitFilesToDisk } from '../../../utils/disk-files'; import { assertIsError } from '../../../utils/error'; -import type { NormalizedLibraryOptions, SingleBuildState } from '../types'; +import type { BuilderState } from '../builder-state'; +import type { ExecutionResult } from '../execution-result'; +import type { NormalizedLibraryOptions } from '../types'; import { collectAssetsToEmit } from './assets'; -import { bundleEntryPoints } from './bundler'; -import { type LibraryCompilationDiagnostics, compileLibrary } from './compilation'; +import { type BundleEntryPointsOutput, bundleEntryPoints } from './bundler'; +import { compileLibrary } from './compilation'; import { collectEntryPointsToBundle } from './entry-points'; import { generatePackageManifests } from './package-manifests'; import type { DiskOutputFile, OutputFile } from './utils'; -/** - * Result of executing a single library build iteration. - */ -export interface BuildActionResult { - /** Formatted error messages produced during the build. */ - errors: string[]; - - /** Formatted warning messages produced during the build. */ - warnings: string[]; - - /** Informational log messages produced during the build. */ - logs: string[]; -} - -/** - * Creates a fresh {@link SingleBuildState} instance. - */ -export function createSingleBuildState(): SingleBuildState { - return { - previousBundleResults: new Map(), - pendingChangedEsmFiles: new Set(), - pendingChangedDtsFiles: new Set(), - }; -} - /** * Context required to execute a single library build iteration. */ @@ -51,35 +27,23 @@ export interface BuildActionContext { /** Normalized options for the library build with POSIX paths. */ options: NormalizedLibraryOptions; - /** The Architect builder context. */ - context: BuilderContext; - /** Bundler instance used to process component stylesheets. */ stylesheetBundler: ComponentStylesheetBundler; /** Whether the builder is running in watch mode. */ isWatchMode: boolean; - /** - * Set of POSIX file paths tracked for compilation and configuration - * (including `tsconfig.json`, `package.json`, entry points, and referenced source, - * template, and stylesheet files). Updated during compilation and used to determine - * whether file changes require recompiling entry points, excluding asset files so - * asset-only changes do not trigger code compilation. - */ - watchedCompilationFiles: Set; - - /** State preserved across incremental builds in watch mode. */ - buildState: SingleBuildState; + /** Build state tracking compilation caches and emitted outputs. */ + buildState: BuilderState; /** Set of POSIX file paths modified since the last build iteration. */ modifiedFiles?: Set; /** - * Asset files to emit to disk for the current build iteration. + * Asset files to emit for the current build iteration. * Pre-collected in the watch loop to avoid redundant asset matching, or resolved and * populated by `buildAction` when omitted (such as during the initial build) so the - * caller can register their source paths with the file watcher. + * caller can register their POSIX source paths with the file watcher. */ assetsToEmit?: DiskOutputFile[]; } @@ -90,138 +54,84 @@ export interface BuildActionContext { * manifest generation, and asset copying. * * @param actionContext The build action state and configuration. - * @returns A promise resolving to the build action result containing errors, warnings, and logs. + * @returns A promise resolving to the build iteration's `ExecutionResult`. */ -export async function buildAction(actionContext: BuildActionContext): Promise { - const { - options, - stylesheetBundler, - isWatchMode, - watchedCompilationFiles, - buildState, - modifiedFiles, - } = actionContext; - - const errors: string[] = []; - const warnings: string[] = []; - const logs: string[] = []; +export async function buildAction(actionContext: BuildActionContext): Promise { + const { options, stylesheetBundler, isWatchMode, buildState, modifiedFiles } = actionContext; + const result = buildState.resetExecutionResult(); const { packageJsonPath } = options; - const { pendingChangedEsmFiles, pendingChangedDtsFiles } = buildState; - if (!modifiedFiles || modifiedFiles.has(packageJsonPath)) { - buildState.hasEmittedManifests = false; - } - - const shouldCompileEntryPoints = - !modifiedFiles || - !buildState.singleProgramCache || - buildState.hasCompilationError || - buildState.hasEntryPointsChanges || - pendingChangedEsmFiles.size > 0 || - pendingChangedDtsFiles.size > 0 || - hasModifiedWatchedFile(modifiedFiles, watchedCompilationFiles, packageJsonPath); + const shouldCompileEntryPoints = buildState.shouldCompileEntryPoints( + packageJsonPath, + modifiedFiles, + ); try { - if (!buildState.hasEmittedManifests) { - const dependencyErrors = verifyAllowedDependencies(options); - if (dependencyErrors.length > 0) { - errors.push(...dependencyErrors); - - return { errors, warnings, logs }; - } + if (!buildState.hasEmittedManifests && !verifyAllowedDependencies(options, result)) { + return result; } const filesToEmit: OutputFile[] = []; if (shouldCompileEntryPoints) { buildState.hasCompilationError = true; - buildState.hasEntryPointsChanges = false; + + const compilationOutput = await compileLibrary( + options, + stylesheetBundler, + buildState, + buildState.getCompilationModifiedFiles(modifiedFiles), + ); + buildState.recordCompilationOutput(compilationOutput); const { esmFiles, dtsFiles, - changedEsmFiles, - changedDtsFiles, - referencedFiles, - cache, hasStylesheetErrors, diagnosePromise, declarationMap, compilationMode, - } = await compileLibrary( - options.entryPoints.values(), - options, - stylesheetBundler, - buildState.singleProgramCache, - modifiedFiles, - ); - buildState.singleProgramCache = cache; - if (buildState.compilationMode !== compilationMode) { - buildState.compilationMode = compilationMode; - buildState.hasEmittedManifests = false; - } - - for (const file of referencedFiles) { - watchedCompilationFiles.add(file); - } - for (const file of changedEsmFiles) { - pendingChangedEsmFiles.add(file); - } - for (const file of changedDtsFiles) { - pendingChangedDtsFiles.add(file); - } + } = compilationOutput; - let bundleOutput: Awaited> | undefined; - let diagnostics: LibraryCompilationDiagnostics; if (hasStylesheetErrors) { - diagnostics = await diagnosePromise; - } else { - const itemsToBundle = collectEntryPointsToBundle(options, buildState, logs); - try { - [bundleOutput, diagnostics] = await Promise.all([ - bundleEntryPoints(itemsToBundle, esmFiles, dtsFiles, { - ...options, - declarationMap, - compilationMode, - }), - diagnosePromise, - ]); - } catch (error) { - assertIsError(error); - // Prioritize TypeScript/Angular diagnostic errors over secondary bundler failures. - diagnostics = await diagnosePromise; - if (diagnostics.errors.length === 0) { - errors.push(error.message); - } - } - } - - warnings.push(...diagnostics.warnings, ...(bundleOutput?.warnings ?? [])); - if (diagnostics.errors.length > 0 || errors.length > 0 || !bundleOutput) { - errors.push(...diagnostics.errors); + await diagnosePromise; - return { errors, warnings, logs }; + return result; } - buildState.hasCompilationError = false; - pendingChangedEsmFiles.clear(); - pendingChangedDtsFiles.clear(); + const itemsToBundle = collectEntryPointsToBundle(options, buildState); + let bundleOutput: BundleEntryPointsOutput; + try { + [bundleOutput] = await Promise.all([ + bundleEntryPoints(itemsToBundle, esmFiles, dtsFiles, { + ...options, + declarationMap, + compilationMode, + }), + diagnosePromise, + ]); + } catch (error) { + assertIsError(error); + // Prioritize TypeScript/Angular diagnostic errors over secondary bundler failures. + await diagnosePromise; + if (!result.hasErrors) { + result.addError(error.message); + } - filesToEmit.push(...bundleOutput.filesToEmit); - for (const [name, bundleResult] of bundleOutput.bundleResults) { - buildState.previousBundleResults.set(name, bundleResult); + return result; } - } - let hasTslibImport = false; - for (const entryPoint of options.entryPoints.values()) { - if (buildState.previousBundleResults.get(entryPoint.name)?.hasTslibImport) { - hasTslibImport = true; - break; + result.addWarnings(bundleOutput.warnings); + if (result.hasErrors) { + return result; } + + filesToEmit.push(...bundleOutput.filesToEmit); + buildState.recordBundleOutput(bundleOutput.bundleResults); } + const { hasTslibImport } = buildState; if (!buildState.hasEmittedManifests || buildState.hasEmittedTslib !== hasTslibImport) { filesToEmit.push( ...(await generatePackageManifests( @@ -249,33 +159,10 @@ export async function buildAction(actionContext: BuildActionContext): Promise, - watchedCompilationFiles: ReadonlySet, - packageJsonPath: string, -): boolean { - for (const file of modifiedFiles) { - if (file !== packageJsonPath && watchedCompilationFiles.has(file)) { - return true; - } - } - - return false; + return result; } /** @@ -283,24 +170,29 @@ export function hasModifiedWatchedFile( * permitted by `allowedNonPeerDependencies`. * * @param options The normalized library builder options. - * @returns An array of error messages for any disallowed dependencies. + * @param result The execution result to record any disallowed dependency errors into. + * @returns `true` if all dependencies are allowed; otherwise `false`. */ -function verifyAllowedDependencies(options: NormalizedLibraryOptions): string[] { +function verifyAllowedDependencies( + options: NormalizedLibraryOptions, + result: ExecutionResult, +): boolean { const { packageJson, allowedNonPeerDependencies } = options; const dependencies = { ...(packageJson.dependencies ?? {}), ...(packageJson.optionalDependencies ?? {}), }; - const errors: string[] = []; + let isValid = true; for (const dep of Object.keys(dependencies)) { if (!allowedNonPeerDependencies.some((regex) => regex.test(dep))) { - errors.push( + result.addError( `Dependency '${dep}' must be explicitly allowed using the 'allowedNonPeerDependencies' option, ` + `or moved to 'peerDependencies' in 'package.json'.`, ); + isValid = false; } } - return errors; + return isValid; } diff --git a/packages/angular/build/src/builders/library/pipeline/compilation.ts b/packages/angular/build/src/builders/library/pipeline/compilation.ts index 367777667fe3..38b28f442df6 100644 --- a/packages/angular/build/src/builders/library/pipeline/compilation.ts +++ b/packages/angular/build/src/builders/library/pipeline/compilation.ts @@ -15,80 +15,41 @@ import { import type { ComponentStylesheetBundler } from '../../../tools/esbuild/angular/component-stylesheets'; import { useTypeChecking } from '../../../utils/environment-options'; import { toPosixPath } from '../../../utils/path'; -import type { NormalizedEntryPoint, NormalizedLibraryOptions, SingleProgramCache } from '../types'; +import type { BuilderState } from '../builder-state'; +import type { LibraryCompilationOutput, NormalizedLibraryOptions } from '../types'; import { isDeclarationFile, isDeclarationSourceMapFile } from './utils'; const EMITTED_EXTENSIONS = ['.js', '.mjs', '.cjs', '.d.ts', '.d.mts', '.d.cts']; -/** - * Formatted diagnostic messages produced during library compilation. - */ -export interface LibraryCompilationDiagnostics { - /** Formatted compilation error messages. */ - readonly errors: string[]; - - /** Formatted compilation warning messages. */ - readonly warnings: string[]; -} - -/** - * Output of the unified library compilation step. - */ -export interface LibraryCompilationOutput { - /** Read-only map of emitted JavaScript files keyed by POSIX path. */ - readonly esmFiles: ReadonlyMap; - - /** Read-only map of emitted TypeScript declaration files keyed by POSIX path. */ - readonly dtsFiles: ReadonlyMap; - - /** Set of POSIX JavaScript file paths that were modified or newly emitted in this iteration. */ - readonly changedEsmFiles: ReadonlySet; - - /** Set of POSIX declaration file paths that were modified or newly emitted in this iteration. */ - readonly changedDtsFiles: ReadonlySet; - - /** Set of all POSIX source and dependency file paths referenced during compilation. */ - readonly referencedFiles: ReadonlySet; - - /** Cached compilation state for subsequent incremental builds. */ - readonly cache: SingleProgramCache; - - /** Whether any component stylesheet bundling errors occurred. */ - readonly hasStylesheetErrors: boolean; - - /** Promise that resolves to formatted compilation diagnostic errors and warnings. */ - readonly diagnosePromise: Promise; - - /** Effective declarationMap setting resolved from builder options and tsconfig. */ - readonly declarationMap: boolean; - - /** Effective compilationMode setting resolved from builder options and tsconfig. */ - readonly compilationMode: 'partial' | 'full'; -} - /** * Compiles all library entry points in a single TypeScript and Angular compilation pass. * - * @param entryPoints The collection of normalized library entry points to compile. * @param options The normalized library builder options with POSIX paths. * @param stylesheetBundler The component stylesheet bundler instance. - * @param cached Optional cached compilation state from a previous build iteration. + * @param buildState The build state tracking compilation caches and diagnostics. * @param modifiedFiles Optional set of modified POSIX file paths for incremental compilation. - * @returns A promise resolving to the compilation output containing emitted files and diagnostics. + * @returns A promise resolving to the compilation output containing emitted files and cache state. */ export async function compileLibrary( - entryPoints: Iterable, options: NormalizedLibraryOptions, stylesheetBundler: ComponentStylesheetBundler, - cached?: SingleProgramCache, + buildState: BuilderState, modifiedFiles?: Set, ): Promise { - const { tsConfigPath, compilationMode, preserveSymlinks, colors, declarationMap, cacheOptions } = - options; + const { + tsConfigPath, + entryPoints, + compilationMode, + preserveSymlinks, + colors, + declarationMap, + cacheOptions, + } = options; + const cached = buildState.singleProgramCache; const entryPathsMap: Record = {}; const rootFiles: string[] = []; - for (const ep of entryPoints) { + for (const ep of entryPoints.values()) { entryPathsMap[ep.displayName] = [ep.entryFilePath]; rootFiles.push(ep.entryFilePath); } @@ -98,12 +59,13 @@ export async function compileLibrary( try { let effectiveModifiedFiles = modifiedFiles; - if (cached?.failedFiles?.size) { + if (cached && cached.failedFiles.size > 0) { stylesheetBundler.invalidate(cached.failedFiles); - effectiveModifiedFiles = new Set(modifiedFiles); + const merged = new Set(modifiedFiles); for (const file of cached.failedFiles) { - effectiveModifiedFiles.add(file); + merged.add(file); } + effectiveModifiedFiles = merged; } if (effectiveModifiedFiles && effectiveModifiedFiles.size > 0) { @@ -168,6 +130,7 @@ export async function compileLibrary( stylesheetErrors, stylesheetWarnings, colors, + buildState, ); const esmFiles = cached?.esmFiles ?? new Map(); @@ -179,7 +142,7 @@ export async function compileLibrary( allReferencedFiles.add(toPosixPath(ref)); } - if (effectiveModifiedFiles) { + if (cached && effectiveModifiedFiles) { for (const modifiedFile of effectiveModifiedFiles) { if (allReferencedFiles.has(modifiedFile)) { continue; @@ -207,21 +170,15 @@ export async function compileLibrary( for (const { filename, contents } of emittedFiles) { const normalized = toPosixPath(filename); - if (normalized.endsWith('.map')) { - const isDtsMap = isDeclarationSourceMapFile(normalized); - const targetMap = isDtsMap ? dtsFiles : esmFiles; - if (targetMap.get(normalized) !== contents) { - targetMap.set(normalized, contents); - (isDtsMap ? changedDtsFiles : changedEsmFiles).add(normalized.slice(0, -4)); - } - } else if (isDeclarationFile(normalized)) { - if (dtsFiles.get(normalized) !== contents) { - changedDtsFiles.add(normalized); - dtsFiles.set(normalized, contents); - } - } else if (esmFiles.get(normalized) !== contents) { - changedEsmFiles.add(normalized); - esmFiles.set(normalized, contents); + const isMap = normalized.endsWith('.map'); + const isDts = isMap ? isDeclarationSourceMapFile(normalized) : isDeclarationFile(normalized); + const targetFiles = isDts ? dtsFiles : esmFiles; + + if (targetFiles.get(normalized) !== contents) { + targetFiles.set(normalized, contents); + (isDts ? changedDtsFiles : changedEsmFiles).add( + isMap ? normalized.slice(0, -4) : normalized, + ); } } @@ -235,7 +192,7 @@ export async function compileLibrary( compilationInstance, esmFiles, dtsFiles, - failedFiles: failedFiles.size > 0 ? failedFiles : undefined, + failedFiles, }, hasStylesheetErrors, diagnosePromise, @@ -251,49 +208,43 @@ export async function compileLibrary( } /** - * Formats stylesheet bundling diagnostics and TypeScript/Angular diagnostics. + * Formats stylesheet bundling diagnostics and TypeScript/Angular diagnostics + * and records them on the build state's execution result. * * @param compilationInstance The active Angular compilation instance. * @param stylesheetErrors List of stylesheet bundling errors. * @param stylesheetWarnings List of stylesheet bundling warnings. * @param colors Whether diagnostic messages should be formatted with ANSI colors. - * @returns A promise resolving to the formatted diagnostic errors and warnings. + * @param buildState The build state whose execution result receives the formatted diagnostics. */ async function runDiagnosticsAndFormat( compilationInstance: AngularCompilation, stylesheetErrors: PartialMessage[], stylesheetWarnings: PartialMessage[], colors: boolean, -): Promise { - const errorsOut: string[] = []; - const warningsOut: string[] = []; - - if (stylesheetErrors.length > 0) { - const formatted = await formatMessages(stylesheetErrors, { kind: 'error', color: colors }); - errorsOut.push(...formatted); - } else if (useTypeChecking) { - const { errors, warnings } = await compilationInstance.diagnoseFiles(); - if (errors?.length) { - const formatted = await formatMessages(errors, { kind: 'error', color: colors }); - errorsOut.push(...formatted); + buildState: BuilderState, +): Promise { + const { executionResult } = buildState; + const errors = [...stylesheetErrors]; + const warnings: PartialMessage[] = []; + + if (errors.length === 0 && useTypeChecking) { + const diagnostics = await compilationInstance.diagnoseFiles(); + if (diagnostics.errors?.length) { + errors.push(...diagnostics.errors); } - - if (warnings?.length) { - const formatted = await formatMessages(warnings, { kind: 'warning', color: colors }); - warningsOut.push(...formatted); + if (diagnostics.warnings?.length) { + warnings.push(...diagnostics.warnings); } } - if (stylesheetWarnings.length > 0) { - const formattedStyleWarnings = await formatMessages(stylesheetWarnings, { - kind: 'warning', - color: colors, - }); - warningsOut.push(...formattedStyleWarnings); + warnings.push(...stylesheetWarnings); + + if (errors.length > 0) { + executionResult.addErrors(await formatMessages(errors, { kind: 'error', color: colors })); } - return { - errors: errorsOut, - warnings: warningsOut, - }; + if (warnings.length > 0) { + executionResult.addWarnings(await formatMessages(warnings, { kind: 'warning', color: colors })); + } } diff --git a/packages/angular/build/src/builders/library/pipeline/entry-points.ts b/packages/angular/build/src/builders/library/pipeline/entry-points.ts index 5cff4ca82136..f50824c5d9f3 100644 --- a/packages/angular/build/src/builders/library/pipeline/entry-points.ts +++ b/packages/angular/build/src/builders/library/pipeline/entry-points.ts @@ -8,12 +8,8 @@ import path from 'node:path'; import { toPosixPath } from '../../../utils/path'; -import type { - NormalizedEntryPoint, - NormalizedLibraryOptions, - PackageJsonData, - SingleBuildState, -} from '../types'; +import type { BuilderState } from '../builder-state'; +import type { NormalizedEntryPoint, NormalizedLibraryOptions, PackageJsonData } from '../types'; import type { BundleEntryPointInput } from './bundler'; /** @@ -24,7 +20,7 @@ import type { BundleEntryPointInput } from './bundler'; * @returns The sanitized bundle base name. */ export function getEntryPointBundleName(packageName: string, entryPointName = '.'): string { - const isPrimary = !entryPointName || entryPointName === '.'; + const isPrimary = entryPointName === '.'; const pkgName = packageName[0] === '@' ? packageName.slice(1) : packageName; const epName = isPrimary ? pkgName : `${pkgName}-${entryPointName}`; @@ -50,11 +46,7 @@ function normalizeEntryPoint( projectRoot: string, packageName: string, ): NormalizedEntryPoint { - const name = isPrimary - ? '.' - : posixKey[0] === '.' && posixKey[1] === '/' - ? posixKey.slice(2) - : posixKey; + const name = isPrimary ? '.' : posixKey.startsWith('./') ? posixKey.slice(2) : posixKey; if (name !== '.' && (path.posix.isAbsolute(name) || name.includes('..'))) { throw new Error( @@ -139,7 +131,7 @@ export function normalizeEntryPoints( exportsRecord = { '.': rawExports }; } else { // If an object has no keys starting with '.', Node.js treats the entire object as the '.' entry point. - const hasSubpathKeys = Object.keys(rawExports as object).some((k) => k.startsWith('.')); + const hasSubpathKeys = Object.keys(rawExports).some((k) => k.startsWith('.')); exportsRecord = hasSubpathKeys ? (rawExports as Record) : { '.': rawExports }; } @@ -190,10 +182,7 @@ export function normalizeEntryPoints( usedBundleNames.set(entryPoint.bundleName, key); entryPoints.set(entryPoint.name, entryPoint); - - if (entryPoint.isPrimary) { - hasPrimary = true; - } + hasPrimary ||= isPrimary; } if (!hasPrimary) { @@ -206,7 +195,8 @@ export function normalizeEntryPoints( } /** - * Determines whether two sets of normalized entry points differ in keys, POSIX entry paths, or subpaths. + * Determines whether two sets of normalized entry points differ in keys, POSIX entry paths, + * subpaths, bundle names, or display names. * * @param oldEntryPoints The previous map of normalized entry points. * @param newEntryPoints The new map of normalized entry points. @@ -242,29 +232,36 @@ export function haveEntryPointsChanged( * @param packageJson The reloaded `package.json` data. * @param options The normalized library builder options. * @param buildState The state preserved across incremental builds. - * @param watchedCompilationFiles Set of POSIX file paths tracked for compilation. - * @param packageJsonPath Normalized POSIX path to `package.json`. */ export function updateWatchedEntryPoints( packageJson: PackageJsonData, options: NormalizedLibraryOptions, - buildState: SingleBuildState, - watchedCompilationFiles: Set, - packageJsonPath: string, + buildState: BuilderState, ): void { + const { packageJsonPath } = options; + if (!packageJson.name) { + throw new Error(`The package.json at '${packageJsonPath}' must contain a 'name'.`); + } + const newEntryPoints = normalizeEntryPoints( packageJson.exports, options.projectRoot, packageJsonPath, - options.packageName, + packageJson.name, ); + const { watchedCompilationFiles, previousBundleResults } = buildState; + if (haveEntryPointsChanged(options.entryPoints, newEntryPoints)) { + for (const oldEntryPoint of options.entryPoints.values()) { + watchedCompilationFiles.delete(oldEntryPoint.entryFilePath); + } + for (const entryPoint of newEntryPoints.values()) { watchedCompilationFiles.add(entryPoint.entryFilePath); } - for (const name of buildState.previousBundleResults.keys()) { + for (const name of previousBundleResults.keys()) { const oldEp = options.entryPoints.get(name); const newEp = newEntryPoints.get(name); if ( @@ -273,13 +270,16 @@ export function updateWatchedEntryPoints( newEp.entryFilePath !== oldEp.entryFilePath || newEp.bundleName !== oldEp.bundleName ) { - buildState.previousBundleResults.delete(name); + previousBundleResults.delete(name); } } options.entryPoints = newEntryPoints; buildState.hasEntryPointsChanges = true; } + + options.packageJson = packageJson; + options.packageName = packageJson.name; } /** @@ -288,15 +288,14 @@ export function updateWatchedEntryPoints( * * @param options The normalized library builder options. * @param buildState The state preserved across incremental builds. - * @param logs Array of informational log messages to append to when an entry point is queued. * @returns The list of entry points that require bundling in the current build iteration. */ export function collectEntryPointsToBundle( options: NormalizedLibraryOptions, - buildState: SingleBuildState, - logs: string[], + buildState: BuilderState, ): BundleEntryPointInput[] { - const { pendingChangedEsmFiles, pendingChangedDtsFiles, previousBundleResults } = buildState; + const { pendingChangedEsmFiles, pendingChangedDtsFiles, previousBundleResults, executionResult } = + buildState; const itemsToBundle: BundleEntryPointInput[] = []; for (const entryPoint of options.entryPoints.values()) { @@ -309,7 +308,7 @@ export function collectEntryPointsToBundle( hasEntryPointChanges(previousBundleResult.dtsModuleIds, pendingChangedDtsFiles); if (hasEsmChanges || hasDtsChanges) { - logs.push(`Compiling ${entryPoint.displayName}...`); + executionResult.addLog(`Compiling ${entryPoint.displayName}...`); itemsToBundle.push({ entryPoint, hasEsmChanges, diff --git a/packages/angular/build/src/builders/library/pipeline/entry-points_spec.ts b/packages/angular/build/src/builders/library/pipeline/entry-points_spec.ts index 834b7aec6835..e4653ef56e2b 100644 --- a/packages/angular/build/src/builders/library/pipeline/entry-points_spec.ts +++ b/packages/angular/build/src/builders/library/pipeline/entry-points_spec.ts @@ -6,16 +6,16 @@ * found in the LICENSE file at https://angular.dev/license */ -import { join, resolve } from 'node:path'; -import { toPosixPath } from '../../../utils/path'; +import { join } from 'node:path'; +import { BuilderState } from '../builder-state'; import type { BundleResult, NormalizedEntryPoint, NormalizedLibraryOptions, PackageJsonData, - SingleBuildState, } from '../types'; import { + collectEntryPointsToBundle, getEntryPointBundleName, haveEntryPointsChanged, normalizeEntryPoints, @@ -23,10 +23,19 @@ import { } from './entry-points'; describe('entry-points pipeline', () => { - const projectRoot = resolve('/workspace/projects/my-lib'); + const projectRoot = '/workspace/projects/my-lib'; const packageJsonPath = join(projectRoot, 'package.json'); const packageName = '@my-scope/my-lib'; + function createBundleResult(overrides: Partial = {}): BundleResult { + return { + esmModuleIds: new Set(), + dtsModuleIds: new Set(), + hasTslibImport: false, + ...overrides, + }; + } + describe('getEntryPointBundleName', () => { it('should compute bundle name for primary entry point without scope', () => { expect(getEntryPointBundleName('my-lib')).toBe('my-lib'); @@ -505,6 +514,8 @@ describe('entry-points pipeline', () => { }); describe('updateWatchedEntryPoints', () => { + const tsConfigPath = join(projectRoot, 'tsconfig.lib.json'); + it('should update options, watched files, build state, and prune removed bundles when entry points change', () => { const initialEntryPoints = normalizeEntryPoints( { @@ -520,17 +531,14 @@ describe('entry-points pipeline', () => { entryPoints: initialEntryPoints, projectRoot, packageName, + packageJsonPath, + tsConfigPath, + assets: [], } as unknown as NormalizedLibraryOptions; - const buildState = { - previousBundleResults: new Map([ - ['.', { esmModuleIds: new Set(), dtsModuleIds: new Set() }], - ['old-feature', { esmModuleIds: new Set(), dtsModuleIds: new Set() }], - ]), - hasEntryPointsChanges: false, - } as unknown as SingleBuildState; - - const watchedCompilationFiles = new Set(); + const buildState = new BuilderState(options); + buildState.previousBundleResults.set('.', createBundleResult()); + buildState.previousBundleResults.set('old-feature', createBundleResult()); const newPackageJson: PackageJsonData = { name: packageName, @@ -540,13 +548,7 @@ describe('entry-points pipeline', () => { }, }; - updateWatchedEntryPoints( - newPackageJson, - options, - buildState, - watchedCompilationFiles, - packageJsonPath, - ); + updateWatchedEntryPoints(newPackageJson, options, buildState); expect(buildState.hasEntryPointsChanges).toBeTrue(); expect(options.entryPoints.has('new-feature')).toBeTrue(); @@ -554,16 +556,17 @@ describe('entry-points pipeline', () => { expect(buildState.previousBundleResults.has('old-feature')).toBeFalse(); expect(buildState.previousBundleResults.has('.')).toBeTrue(); expect( - watchedCompilationFiles.has(toPosixPath(join(projectRoot, 'src/public-api.ts'))), + buildState.watchedCompilationFiles.has(join(projectRoot, 'src/public-api.ts')), ).toBeTrue(); expect( - watchedCompilationFiles.has( - toPosixPath(join(projectRoot, 'new-feature/src/public-api.ts')), - ), + buildState.watchedCompilationFiles.has(join(projectRoot, 'old-feature/src/public-api.ts')), + ).toBeFalse(); + expect( + buildState.watchedCompilationFiles.has(join(projectRoot, 'new-feature/src/public-api.ts')), ).toBeTrue(); }); - it('should not mutate buildState or options when entry points do not change', () => { + it('should not mutate buildState or options.entryPoints when entry points do not change', () => { const initialEntryPoints = normalizeEntryPoints( { '.': './src/public-api.ts', @@ -578,17 +581,14 @@ describe('entry-points pipeline', () => { entryPoints: initialEntryPoints, projectRoot, packageName, + packageJsonPath, + tsConfigPath, + assets: [], } as unknown as NormalizedLibraryOptions; - const buildState = { - previousBundleResults: new Map([ - ['.', { esmModuleIds: new Set(), dtsModuleIds: new Set() }], - ['feature', { esmModuleIds: new Set(), dtsModuleIds: new Set() }], - ]), - hasEntryPointsChanges: false, - } as unknown as SingleBuildState; - - const watchedCompilationFiles = new Set(); + const buildState = new BuilderState(options); + buildState.previousBundleResults.set('.', createBundleResult()); + buildState.previousBundleResults.set('feature', createBundleResult()); const samePackageJson: PackageJsonData = { name: packageName, @@ -598,17 +598,10 @@ describe('entry-points pipeline', () => { }, }; - updateWatchedEntryPoints( - samePackageJson, - options, - buildState, - watchedCompilationFiles, - packageJsonPath, - ); + updateWatchedEntryPoints(samePackageJson, options, buildState); expect(buildState.hasEntryPointsChanges).toBeFalse(); expect(options.entryPoints).toBe(initialEntryPoints); - expect(watchedCompilationFiles).toHaveSize(0); expect(buildState.previousBundleResults).toHaveSize(2); }); @@ -626,16 +619,13 @@ describe('entry-points pipeline', () => { entryPoints: initialEntryPoints, projectRoot, packageName, + packageJsonPath, + tsConfigPath, + assets: [], } as unknown as NormalizedLibraryOptions; - const buildState = { - previousBundleResults: new Map([ - ['.', { esmModuleIds: new Set(), dtsModuleIds: new Set() }], - ]), - hasEntryPointsChanges: false, - } as unknown as SingleBuildState; - - const watchedCompilationFiles = new Set(); + const buildState = new BuilderState(options); + buildState.previousBundleResults.set('.', createBundleResult()); const updatedPackageJson: PackageJsonData = { name: packageName, @@ -644,13 +634,7 @@ describe('entry-points pipeline', () => { }, }; - updateWatchedEntryPoints( - updatedPackageJson, - options, - buildState, - watchedCompilationFiles, - packageJsonPath, - ); + updateWatchedEntryPoints(updatedPackageJson, options, buildState); expect(buildState.hasEntryPointsChanges).toBeTrue(); expect(buildState.previousBundleResults.has('.')).toBeFalse(); @@ -658,7 +642,7 @@ describe('entry-points pipeline', () => { join(projectRoot, 'src/other-api.ts'), ); expect( - watchedCompilationFiles.has(toPosixPath(join(projectRoot, 'src/other-api.ts'))), + buildState.watchedCompilationFiles.has(join(projectRoot, 'src/other-api.ts')), ).toBeTrue(); }); @@ -676,16 +660,13 @@ describe('entry-points pipeline', () => { entryPoints: initialEntryPoints, projectRoot, packageName, + packageJsonPath, + tsConfigPath, + assets: [], } as unknown as NormalizedLibraryOptions; - const buildState = { - previousBundleResults: new Map([ - ['.', { esmModuleIds: new Set(), dtsModuleIds: new Set() }], - ]), - hasEntryPointsChanges: false, - } as unknown as SingleBuildState; - - const watchedCompilationFiles = new Set(); + const buildState = new BuilderState(options); + buildState.previousBundleResults.set('.', createBundleResult()); const updatedPackageJson: PackageJsonData = { name: '@renamed-scope/my-lib', @@ -694,19 +675,108 @@ describe('entry-points pipeline', () => { }, }; - options.packageName = updatedPackageJson.name; - - updateWatchedEntryPoints( - updatedPackageJson, - options, - buildState, - watchedCompilationFiles, - packageJsonPath, - ); + updateWatchedEntryPoints(updatedPackageJson, options, buildState); expect(buildState.hasEntryPointsChanges).toBeTrue(); expect(buildState.previousBundleResults.has('.')).toBeFalse(); + expect(options.packageName).toBe('@renamed-scope/my-lib'); expect(options.entryPoints.get('.')?.bundleName).toBe('renamed-scope-my-lib'); }); + + it('should throw when updated packageJson is missing a name field', () => { + const options = { + entryPoints: new Map(), + projectRoot, + packageName, + packageJsonPath, + assets: [], + } as unknown as NormalizedLibraryOptions; + const buildState = new BuilderState(options); + + expect(() => + updateWatchedEntryPoints({} as PackageJsonData, options, buildState), + ).toThrowError(/must contain a 'name'/); + }); + }); + + describe('collectEntryPointsToBundle', () => { + it('should return all entry points with ESM and DTS changes on initial build', () => { + const entryPoints = normalizeEntryPoints( + { + '.': './src/public-api.ts', + './testing': './testing/src/public-api.ts', + }, + projectRoot, + packageJsonPath, + packageName, + ); + const options = { entryPoints } as unknown as NormalizedLibraryOptions; + const buildState = new BuilderState(options); + + const items = collectEntryPointsToBundle(options, buildState); + + expect(items).toHaveSize(2); + expect(items[0]).toEqual({ + entryPoint: jasmine.objectContaining({ name: '.' }), + previousBundleResult: undefined, + hasEsmChanges: true, + hasDtsChanges: true, + }); + expect(items[1]).toEqual({ + entryPoint: jasmine.objectContaining({ name: 'testing' }), + previousBundleResult: undefined, + hasEsmChanges: true, + hasDtsChanges: true, + }); + expect(buildState.executionResult.logs).toEqual([ + 'Compiling @my-scope/my-lib...', + 'Compiling @my-scope/my-lib/testing...', + ]); + }); + + it('should only return entry points whose ESM or DTS module IDs intersect pending changes', () => { + const entryPoints = normalizeEntryPoints( + { + '.': './src/public-api.ts', + './testing': './testing/src/public-api.ts', + }, + projectRoot, + packageJsonPath, + packageName, + ); + const options = { entryPoints } as unknown as NormalizedLibraryOptions; + const buildState = new BuilderState(options); + + const primaryEntryJs = join(projectRoot, 'src/public-api.js'); + const primaryEntryDts = join(projectRoot, 'src/public-api.d.ts'); + const testingEntryJs = join(projectRoot, 'testing/src/public-api.js'); + const testingEntryDts = join(projectRoot, 'testing/src/public-api.d.ts'); + + buildState.previousBundleResults.set( + '.', + createBundleResult({ + esmModuleIds: new Set([primaryEntryJs]), + dtsModuleIds: new Set([primaryEntryDts]), + }), + ); + buildState.previousBundleResults.set( + 'testing', + createBundleResult({ + esmModuleIds: new Set([testingEntryJs]), + dtsModuleIds: new Set([testingEntryDts]), + }), + ); + + buildState.pendingChangedEsmFiles.add(testingEntryJs); + + const items = collectEntryPointsToBundle(options, buildState); + + expect(items).toHaveSize(1); + expect(items[0]?.entryPoint.name).toBe('testing'); + expect(items[0]?.hasEsmChanges).toBeTrue(); + expect(items[0]?.hasDtsChanges).toBeFalse(); + expect(items[0]?.previousBundleResult).toBe(buildState.previousBundleResults.get('testing')); + expect(buildState.executionResult.logs).toEqual(['Compiling @my-scope/my-lib/testing...']); + }); }); }); diff --git a/packages/angular/build/src/builders/library/pipeline/package-manifests.ts b/packages/angular/build/src/builders/library/pipeline/package-manifests.ts index 98ed88a506e6..5238ccca76c2 100644 --- a/packages/angular/build/src/builders/library/pipeline/package-manifests.ts +++ b/packages/angular/build/src/builders/library/pipeline/package-manifests.ts @@ -78,13 +78,10 @@ export async function generatePackageManifests( }; if (hasTslibImport && !rawPackageJson.dependencies?.['tslib']) { - const tslibVersion = await getAngularTslibRange(options.workspaceRoot); - if (tslibVersion) { - distPackageJson.dependencies = { - ...rawPackageJson.dependencies, - tslib: tslibVersion, - }; - } + distPackageJson.dependencies = { + ...rawPackageJson.dependencies, + tslib: await getAngularTslibRange(options.workspaceRoot), + }; } // Retain scripts if keepLifecycleScripts is set @@ -159,6 +156,11 @@ export async function generatePackageManifests( /** * Creates or updates export conditions for an entry point, preserving custom user-defined conditions. + * + * @param existingConditions Existing export conditions from the user's `package.json`. + * @param dtsPath Relative POSIX path to the bundled `.d.ts` file. + * @param fesmPath Relative POSIX path to the bundled FESM `.mjs` file. + * @returns The merged export conditions object. */ function createExportConditions( existingConditions: unknown, diff --git a/packages/angular/build/src/builders/library/types.ts b/packages/angular/build/src/builders/library/types.ts index 2deeddf589e5..2d2d9f61891d 100644 --- a/packages/angular/build/src/builders/library/types.ts +++ b/packages/angular/build/src/builders/library/types.ts @@ -9,7 +9,7 @@ import type { AngularCompilation } from '../../tools/angular/compilation'; import type { StylesheetPluginsass } from '../../tools/esbuild/stylesheets/stylesheet-plugin-factory'; import type { normalizeAssetPatterns } from '../../utils'; -import type { normalizeCacheOptions } from '../../utils/normalize-cache'; +import type { NormalizedCachedOptions } from '../../utils/normalize-cache'; import type { PostcssConfiguration } from '../../utils/postcss-configuration'; /** @@ -68,12 +68,16 @@ export interface NormalizedLibraryOptions { /** Absolute POSIX path to the library project root directory. */ projectRoot: string; + /** Name of the npm package from the library's `package.json`. */ packageName: string; + + /** Parsed contents of the library's `package.json`. */ packageJson: PackageJsonData; /** Absolute POSIX path to the build output directory. */ outputPath: string; + /** Whether to delete the output directory before building. */ deleteOutputPath: boolean; /** Absolute POSIX path to the library's `package.json`. */ @@ -82,29 +86,58 @@ export interface NormalizedLibraryOptions { /** Absolute POSIX path to the TypeScript configuration file. */ tsConfigPath: string; + /** Map of normalized entry points keyed by entry point name. */ entryPoints: Map; + + /** Default stylesheet language for inline component styles. */ inlineStyleLanguage: 'css' | 'less' | 'sass' | 'scss'; /** Absolute POSIX paths to style preprocessor include directories. */ styleIncludePaths: string[]; + /** Optional Sass preprocessor configuration. */ sass?: StylesheetPluginsass; /** Normalized asset patterns with POSIX `input` and `output` paths. */ assets: ReturnType; + /** Angular compilation mode (`'partial'` or `'full'`). */ compilationMode?: 'partial' | 'full'; + + /** Whether to generate source maps for TypeScript declaration files. */ declarationMap?: boolean; + + /** Regular expressions matching allowed non-peer dependencies. */ allowedNonPeerDependencies: RegExp[]; + + /** Whether to preserve lifecycle scripts in the emitted `package.json`. */ keepLifecycleScripts: boolean; + + /** Whether to run the build in watch mode. */ watch: boolean; + + /** Optional file watching polling interval in milliseconds. */ poll?: number; + + /** Whether to preserve symbolic links during resolution and bundling. */ preserveSymlinks: boolean; + + /** Whether to display build progress in the terminal. */ progress: boolean; + + /** Whether to clear the terminal screen before watch rebuilds. */ clearScreen?: boolean; - cacheOptions: ReturnType; + + /** Normalized build cache configuration. */ + cacheOptions: NormalizedCachedOptions; + + /** Resolved PostCSS configuration, if present in the workspace. */ postcssConfiguration?: { config: PostcssConfiguration; configPath: string }; + + /** Resolved Tailwind CSS configuration, if applicable. */ tailwindConfiguration?: { file: string; package: string }; + + /** Whether terminal color output is enabled. */ colors: boolean; } @@ -135,41 +168,41 @@ export interface SingleProgramCache { /** In-memory map of emitted TypeScript declaration files keyed by POSIX path. */ readonly dtsFiles: Map; - /** Set of POSIX file paths that failed during stylesheet bundling or compilation. */ - readonly failedFiles?: ReadonlySet; + /** Set of POSIX file paths that failed during stylesheet bundling. */ + readonly failedFiles: ReadonlySet; } /** - * State preserved across incremental builds in watch mode. + * Output of the unified library compilation step. */ -export interface SingleBuildState { - /** Cached unified TypeScript and Angular compilation state. */ - singleProgramCache?: SingleProgramCache; +export interface LibraryCompilationOutput { + /** Read-only map of emitted JavaScript files keyed by POSIX path. */ + readonly esmFiles: ReadonlyMap; - /** Effective compilation mode resolved from builder options and tsconfig. */ - compilationMode?: 'partial' | 'full'; + /** Read-only map of emitted TypeScript declaration files keyed by POSIX path. */ + readonly dtsFiles: ReadonlyMap; - /** Map of entry point names to their previous bundle results. */ - previousBundleResults: Map; + /** Set of POSIX JavaScript file paths that were added, modified, or deleted in this iteration. */ + readonly changedEsmFiles: ReadonlySet; - /** Set of changed POSIX ESM file paths pending bundling. */ - pendingChangedEsmFiles: Set; + /** Set of POSIX declaration file paths that were added, modified, or deleted in this iteration. */ + readonly changedDtsFiles: ReadonlySet; - /** Set of changed POSIX TypeScript declaration file paths pending bundling. */ - pendingChangedDtsFiles: Set; + /** Set of all POSIX source and dependency file paths referenced during compilation. */ + readonly referencedFiles: ReadonlySet; - /** Whether the previous build iteration encountered a compilation or diagnostic error. */ - hasCompilationError?: boolean; + /** Cached compilation state for subsequent incremental builds. */ + readonly cache: SingleProgramCache; - /** Whether package.json and secondary entry point manifests have been emitted. */ - hasEmittedManifests?: boolean; + /** Whether any component stylesheet bundling errors occurred. */ + readonly hasStylesheetErrors: boolean; - /** Whether the last emitted root package.json included a tslib dependency. */ - hasEmittedTslib?: boolean; + /** Promise that resolves when compilation diagnostics have been formatted and recorded. */ + readonly diagnosePromise: Promise; - /** Whether static assets have been emitted in a prior iteration. */ - hasEmittedAssets?: boolean; + /** Effective declarationMap setting resolved from builder options and tsconfig. */ + readonly declarationMap: boolean; - /** Whether entry points in package.json changed since the last compilation. */ - hasEntryPointsChanges?: boolean; + /** Effective compilationMode setting resolved from builder options and tsconfig. */ + readonly compilationMode: 'partial' | 'full'; } From d2233e225aa5fd507e3ce7bfd35ae2268c036aa4 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Wed, 14 Oct 2026 16:54:52 -0400 Subject: [PATCH 42/52] fix(@angular/build): coalesce external watcher directories to avoid macOS FSEvents limit Previously, `ParcelExternalManager` immediately created a separate `@parcel/watcher` subscription for the parent directory of every watched file outside the workspace root. In monorepo setups where an application imports from hundreds of external library directories and hoisted `node_modules` packages, this exceeded macOS's ~512 per-process `FSEvents` stream limit, causing subsequent subscriptions to silently fail and miss file changes. To prevent exhausting native watcher streams, `ParcelExternalManager` now normalizes external `node_modules` file paths to their package root directory and batches synchronous file additions and removals within a microtask so nested child directories are subsumed before subscribing. When the number of external target directories exceeds the subscription budget of 256, a prefix tree is used to iteratively collapse the deepest branching subdirectories into common ancestors while preferring directories that do not contain `workspaceRoot`. Additionally, if `parcelWatcher.subscribe()` rejects for an existing directory on disk, the manager dynamically lowers its subscription budget and re-reconciles into higher-level ancestor directories. Closes #34246 --- packages/angular/build/BUILD.bazel | 1 + packages/angular/build/src/utils/watcher.ts | 582 +++++++++++++++--- .../angular/build/src/utils/watcher_spec.ts | 361 +++++++++++ 3 files changed, 866 insertions(+), 78 deletions(-) diff --git a/packages/angular/build/BUILD.bazel b/packages/angular/build/BUILD.bazel index bf6c034292df..d0ab55750e98 100644 --- a/packages/angular/build/BUILD.bazel +++ b/packages/angular/build/BUILD.bazel @@ -153,6 +153,7 @@ ts_project( ":build", ":node_modules/@angular-devkit/core", ":node_modules/@babel/core", + ":node_modules/@parcel/watcher", ":node_modules/oxc-parser", "//:node_modules/@angular/compiler-cli", "//:node_modules/@angular/router", diff --git a/packages/angular/build/src/utils/watcher.ts b/packages/angular/build/src/utils/watcher.ts index 610051c5dcc7..ca0e86f987ff 100644 --- a/packages/angular/build/src/utils/watcher.ts +++ b/packages/angular/build/src/utils/watcher.ts @@ -419,89 +419,364 @@ export function extractNodeModulesPackageDir(posixPath: string): string | undefi return `${nodeModulesPath}/${segments[0]}`; } -class ParcelExternalManager { - private readonly extraSubscriptions = new Map(); - private readonly pendingSubscriptions = new Map< - string, - Promise - >(); - private readonly externalDirFiles = new Map }>(); +/** + * Maximum number of concurrent external directory subscriptions before coalescing + * sibling/cousin directories into common ancestor directories. + * Kept well below macOS's ~512 per-process FSEvents stream limit. + */ +const DEFAULT_MAX_EXTERNAL_SUBSCRIPTIONS = 256; + +/** + * Node in a directory prefix tree used to subsume nested directories + * and coalesce sibling/cousin directories into common ancestors. + */ +interface DirTrieNode { + /** Case-normalized POSIX path key for set/map lookups. */ + dirKey: string; + + /** Original-case POSIX directory path passed to `@parcel/watcher`. */ + dirPath: string; + + /** Depth of this directory node from the filesystem root (0 at root). */ + depth: number; + + /** Parent directory node, or `undefined` if this node is a filesystem root. */ + parent: DirTrieNode | undefined; + + /** Child directory nodes keyed by their `dirKey`. */ + children: Map; + + /** Whether this directory is selected as an active subscription target. */ + isTarget: boolean; + + /** Number of active target leaf directories within this node's subtree. */ + leafCount: number; +} + +/** + * Checks whether any strict ancestor of the given trie node is already marked as a target. + */ +function hasTargetAncestor(node: DirTrieNode): boolean { + let current = node.parent; + while (current) { + if (current.isTarget) { + return true; + } + current = current.parent; + } + + return false; +} + +/** + * Manages `@parcel/watcher` directory subscriptions for watched files located outside the + * primary `workspaceRoot`. + * + * Because `@parcel/watcher` watches directories recursively and macOS limits each process to + * ~512 concurrent `FSEvents` streams, this manager: + * - Normalizes external `node_modules` file paths to their package root directory. + * - Batches synchronous `watchFile` and `removeFile` calls within a microtask before subscribing. + * - Uses a directory prefix tree to subsume nested child directories and iteratively coalesce + * deepest branching subdirectories into common ancestors when the subscription budget is exceeded. + * - Dynamically lowers its subscription budget and coalesces further if `subscribe()` fails on + * an existing directory due to OS stream limits. + */ +export class ParcelExternalManager { + /** Active `@parcel/watcher` subscriptions keyed by subscribed directory lookup key. */ + readonly #extraSubscriptions = new Map(); + + /** Reference-counted watched files grouped by their target external directory lookup key. */ + readonly #externalDirFiles = new Map }>(); + + /** Reverse lookup mapping each watched file lookup key to its target directory lookup key. */ + readonly #fileToDirKey = new Map(); + + /** The `@parcel/watcher` module instance. */ + readonly #parcelWatcher: typeof ParcelWatcher; + + /** Watcher configuration options including ignore patterns. */ + readonly #options: WatcherOptions | undefined; + + /** Normalized POSIX path of the primary watched workspace root. */ + readonly #rootDirPosix: string; + + /** Case-normalized lookup key of the primary watched workspace root. */ + readonly #rootDirLookupKey: string; + + /** Whether the underlying filesystem is case-sensitive. */ + readonly #isCaseSensitive: boolean; + + /** Callback invoked when `@parcel/watcher` emits filesystem events. */ + readonly #handleEvents: (events: ParcelWatcher.Event[]) => void; + + /** Current maximum number of concurrent external directory subscriptions allowed before coalescing. */ + #maxSubscriptions: number; + + /** Whether external directory state has changed and requires a reconciliation pass. */ + #needsReconcile = false; + + /** Whether obsolete subscriptions should be unsubscribed before creating new ones (used after stream limit errors). */ + #shrinkBeforeSubscribe = false; + /** In-flight promise for the currently scheduled or running reconciliation loop. */ + #reconcilePromise: Promise | undefined; + + /** Whether this manager has been closed. */ + #isClosed = false; + + /** + * Creates a new external directory subscription manager for `@parcel/watcher`. + * + * @param parcelWatcher The `@parcel/watcher` module. + * @param options Watcher configuration options. + * @param rootDirPosix Normalized POSIX path of the primary workspace root. + * @param rootDirLookupKey Case-normalized lookup key of the primary workspace root. + * @param isCaseSensitive Whether the filesystem at the workspace root is case-sensitive. + * @param handleEvents Callback to process incoming `@parcel/watcher` events. + * @param maxSubscriptions Maximum number of concurrent external directory subscriptions before coalescing. + */ constructor( - private readonly parcelWatcher: typeof ParcelWatcher, - private readonly options: WatcherOptions | undefined, - private readonly rootDirLookupKey: string, - private readonly handleEvents: (events: ParcelWatcher.Event[]) => void, - ) {} + parcelWatcher: typeof ParcelWatcher, + options: WatcherOptions | undefined, + rootDirPosix: string, + rootDirLookupKey: string, + isCaseSensitive: boolean, + handleEvents: (events: ParcelWatcher.Event[]) => void, + maxSubscriptions = DEFAULT_MAX_EXTERNAL_SUBSCRIPTIONS, + ) { + this.#parcelWatcher = parcelWatcher; + this.#options = options; + this.#rootDirPosix = rootDirPosix; + this.#rootDirLookupKey = rootDirLookupKey; + this.#isCaseSensitive = isCaseSensitive; + this.#handleEvents = handleEvents; + this.#maxSubscriptions = Math.max(1, maxSubscriptions); + } - async ensureWatched(posixPath: string, lookupKey: string): Promise { - if (isPathInside(lookupKey, this.rootDirLookupKey) || lookupKey === this.rootDirLookupKey) { + /** + * Registers a file path to be watched if it resides outside the primary workspace root, + * and schedules an asynchronous subscription reconciliation pass if needed. + * + * @param posixPath Normalized POSIX file path preserving original casing. + * @param lookupKey Case-normalized lookup key for the file path. + */ + watchFile(posixPath: string, lookupKey: string): void { + if ( + this.#isClosed || + isPathInside(lookupKey, this.#rootDirLookupKey) || + lookupKey === this.#rootDirLookupKey + ) { return; } - const dirPath = getDirectoryPath(posixPath); - const dirKey = getDirectoryPath(lookupKey); - let dirEntry = this.externalDirFiles.get(dirKey); + const pkgDir = extractNodeModulesPackageDir(posixPath); + const dirPath = pkgDir ?? getDirectoryPath(posixPath); + const dirKey = pkgDir + ? toLookupKey(pkgDir, this.#isCaseSensitive) + : getDirectoryPath(lookupKey); + + this.#fileToDirKey.set(lookupKey, dirKey); + + let dirEntry = this.#externalDirFiles.get(dirKey); + const isNewDir = !dirEntry; if (!dirEntry) { dirEntry = { dirPath, files: new Set() }; - this.externalDirFiles.set(dirKey, dirEntry); + this.#externalDirFiles.set(dirKey, dirEntry); } dirEntry.files.add(lookupKey); - await this.ensureDirWatched(dirPath, dirKey); + if (isNewDir || !this.#isCoveredByActiveSubscription(dirKey)) { + this.#scheduleReconcile(); + } } + /** + * Unregisters a previously watched external file and schedules a reconciliation pass + * if it was the last watched file in its target directory. + * + * @param lookupKey Case-normalized lookup key for the file path to remove. + */ removeFile(lookupKey: string): void { - if (isPathInside(lookupKey, this.rootDirLookupKey) || lookupKey === this.rootDirLookupKey) { + const dirKey = this.#fileToDirKey.get(lookupKey); + if (!dirKey) { return; } - const dirKey = getDirectoryPath(lookupKey); - const dirEntry = this.externalDirFiles.get(dirKey); + this.#fileToDirKey.delete(lookupKey); + const dirEntry = this.#externalDirFiles.get(dirKey); if (dirEntry) { dirEntry.files.delete(lookupKey); if (dirEntry.files.size === 0) { - this.externalDirFiles.delete(dirKey); - const sub = this.extraSubscriptions.get(dirKey); - if (sub) { - this.extraSubscriptions.delete(dirKey); - sub.unsubscribe().catch(() => {}); - - for (const [remainingDirKey, remainingDirEntry] of this.externalDirFiles.entries()) { - if (!this.isCoveredByExistingExternal(remainingDirKey)) { - this.ensureDirWatched(remainingDirEntry.dirPath, remainingDirKey).catch(() => {}); - } - } - } + this.#externalDirFiles.delete(dirKey); + this.#scheduleReconcile(); } } } + /** + * Waits for any scheduled or in-progress subscription reconciliation pass to complete. + */ + async flush(): Promise { + if (this.#reconcilePromise) { + await this.#reconcilePromise; + } + } + + /** + * Closes the manager, awaiting any pending reconciliation and unsubscribing all active + * external directory subscriptions. + */ async close(): Promise { + this.#isClosed = true; + this.#needsReconcile = false; try { - if (this.pendingSubscriptions.size > 0) { - await Promise.allSettled(Array.from(this.pendingSubscriptions.values())); + if (this.#reconcilePromise) { + await this.#reconcilePromise.catch(() => {}); } - if (this.extraSubscriptions.size > 0) { + if (this.#extraSubscriptions.size > 0) { await Promise.allSettled( - Array.from(this.extraSubscriptions.values()).map((sub) => sub.unsubscribe()), + Array.from(this.#extraSubscriptions.values(), (sub) => sub.unsubscribe()), ); } } finally { - this.extraSubscriptions.clear(); - this.pendingSubscriptions.clear(); - this.externalDirFiles.clear(); + this.#extraSubscriptions.clear(); + this.#externalDirFiles.clear(); + this.#fileToDirKey.clear(); } } - private isCoveredByExistingExternal(dirLookupKey: string): boolean { - for (const existingDir of this.extraSubscriptions.keys()) { - if (dirLookupKey === existingDir || isPathInside(dirLookupKey, existingDir)) { - return true; + /** + * Schedules a microtask to reconcile active `@parcel/watcher` subscriptions with the + * current set of external directories. + */ + #scheduleReconcile(): void { + if (this.#isClosed) { + return; + } + + this.#needsReconcile = true; + this.#reconcilePromise ??= Promise.resolve() + .then(() => this.#runReconcileLoop()) + .finally(() => { + this.#reconcilePromise = undefined; + }); + } + + /** + * Continuously executes reconciliation passes until no further changes are pending. + */ + async #runReconcileLoop(): Promise { + while (this.#needsReconcile && !this.#isClosed) { + this.#needsReconcile = false; + await this.#reconcileOnce(); + } + } + + /** + * Performs a single reconciliation pass: computes the desired coalesced directory set, + * subscribes to newly required directories, unsubscribes obsolete directories, and + * triggers fallback coalescing if OS stream limits are encountered. + */ + async #reconcileOnce(): Promise { + const desiredDirs = this.#computeDesiredDirectories(); + + if (this.#shrinkBeforeSubscribe) { + this.#shrinkBeforeSubscribe = false; + const toUnsubscribe: Promise[] = []; + for (const [existingKey, sub] of this.#extraSubscriptions.entries()) { + if (!desiredDirs.has(existingKey)) { + this.#extraSubscriptions.delete(existingKey); + toUnsubscribe.push(sub.unsubscribe().catch(() => {})); + } + } + if (toUnsubscribe.length > 0) { + await Promise.allSettled(toUnsubscribe); } } - for (const pendingDir of this.pendingSubscriptions.keys()) { - if (dirLookupKey === pendingDir || isPathInside(dirLookupKey, pendingDir)) { + + if (this.#isClosed) { + return; + } + + const toSubscribe: [string, string][] = []; + for (const [dirKey, dirPath] of desiredDirs.entries()) { + if (!this.#extraSubscriptions.has(dirKey)) { + toSubscribe.push([dirKey, dirPath]); + } + } + + let hadExistingDirFailure = false; + if (toSubscribe.length > 0) { + await Promise.allSettled( + toSubscribe.map(async ([dirKey, dirPath]) => { + const ignore = isPathInside(this.#rootDirLookupKey, dirKey) + ? [...(this.#options?.ignored ?? []), this.#rootDirPosix, `${this.#rootDirPosix}/**`] + : this.#options?.ignored; + + try { + const sub = await this.#parcelWatcher.subscribe( + dirPath, + (err, events) => { + if (!err) { + this.#handleEvents(events); + } + }, + { ignore }, + ); + + if (this.#isClosed) { + await sub.unsubscribe().catch(() => {}); + + return; + } + + this.#extraSubscriptions.set(dirKey, sub); + } catch { + // Ignore errors for missing directories; if the directory exists on disk, + // mark failure so the manager can coalesce further if over OS stream limits. + if (!this.#isClosed && fs.existsSync(dirPath)) { + hadExistingDirFailure = true; + } + } + }), + ); + } + + if (this.#isClosed) { + return; + } + + // Unsubscribe any previous subscriptions that are no longer desired and whose + // remaining watched files (if any) are now covered by another active subscription. + for (const [existingKey, sub] of this.#extraSubscriptions.entries()) { + if (!desiredDirs.has(existingKey) && this.#canRemoveSubscription(existingKey)) { + this.#extraSubscriptions.delete(existingKey); + sub.unsubscribe().catch(() => {}); + } + } + + // If subscribing to an existing directory failed (e.g. macOS FSEvents per-process limit), + // dynamically lower the subscription budget and re-reconcile to coalesce into ancestors. + if (hadExistingDirFailure && desiredDirs.size > 1 && this.#maxSubscriptions > 1) { + const nextMax = + this.#extraSubscriptions.size > 0 + ? Math.max(1, Math.floor(this.#extraSubscriptions.size / 2)) + : Math.max(1, Math.floor(Math.min(this.#maxSubscriptions, desiredDirs.size) / 2)); + + if (nextMax < desiredDirs.size && nextMax < this.#maxSubscriptions) { + this.#maxSubscriptions = nextMax; + this.#shrinkBeforeSubscribe = true; + this.#needsReconcile = true; + } + } + } + + /** + * Checks whether a directory lookup key is already covered by an active subscription. + */ + #isCoveredByActiveSubscription(dirLookupKey: string): boolean { + for (const existingDir of this.#extraSubscriptions.keys()) { + if (dirLookupKey === existingDir || isPathInside(dirLookupKey, existingDir)) { return true; } } @@ -509,47 +784,196 @@ class ParcelExternalManager { return false; } - private async ensureDirWatched(dirPath: string, dirKey: string): Promise { - if (this.isCoveredByExistingExternal(dirKey)) { - return; + /** + * Determines whether an existing subscription can be safely removed without leaving + * any remaining watched target directories uncovered. + */ + #canRemoveSubscription(subKey: string): boolean { + for (const targetDirKey of this.#externalDirFiles.keys()) { + if (targetDirKey === subKey || isPathInside(targetDirKey, subKey)) { + let coveredByOther = false; + for (const otherSubKey of this.#extraSubscriptions.keys()) { + if ( + otherSubKey !== subKey && + (targetDirKey === otherSubKey || isPathInside(targetDirKey, otherSubKey)) + ) { + coveredByOther = true; + break; + } + } + if (!coveredByOther) { + return false; + } + } + } + + return true; + } + + /** + * Computes the minimal set of external directories to subscribe to (mapped from `dirKey` to `dirPath`), + * subsuming nested directories and coalescing branching ancestors to stay within `#maxSubscriptions`. + */ + #computeDesiredDirectories(): Map { + if (this.#externalDirFiles.size === 0) { + return new Map(); } - const subPromise = this.parcelWatcher.subscribe( - dirPath, - (err, events) => { - if (!err) { - this.handleEvents(events); + const nodesByKey = new Map(); + const roots: DirTrieNode[] = []; + + for (const [dirKey, { dirPath }] of this.#externalDirFiles.entries()) { + const chain: { dirKey: string; dirPath: string }[] = []; + let currentKey = dirKey; + let currentPath = dirPath; + while (true) { + chain.push({ dirKey: currentKey, dirPath: currentPath }); + const parentKey = getDirectoryPath(currentKey); + if (parentKey === currentKey) { + break; } - }, - { - ignore: this.options?.ignored, - }, - ); + currentKey = parentKey; + currentPath = getDirectoryPath(currentPath); + } - this.pendingSubscriptions.set(dirKey, subPromise); + let parentNode: DirTrieNode | undefined; + for (let i = chain.length - 1; i >= 0; i--) { + const { dirKey: nodeKey, dirPath: nodePath } = chain[i]; + const depth = chain.length - 1 - i; + let node = nodesByKey.get(nodeKey); + if (!node) { + node = { + dirKey: nodeKey, + dirPath: nodePath, + depth, + parent: parentNode, + children: new Map(), + isTarget: false, + leafCount: 0, + }; + nodesByKey.set(nodeKey, node); + if (parentNode) { + parentNode.children.set(nodeKey, node); + } else { + roots.push(node); + } + } + parentNode = node; + } - try { - const sub = await subPromise; - this.pendingSubscriptions.delete(dirKey); + if (parentNode) { + parentNode.isTarget = true; + } + } - if (this.externalDirFiles.has(dirKey) && !this.isCoveredByExistingExternal(dirKey)) { - this.extraSubscriptions.set(dirKey, sub); + const initSubtree = (node: DirTrieNode): number => { + if (node.isTarget) { + node.children.clear(); + node.leafCount = 1; - // Subsume any nested child subscriptions that are now covered by this parent subscription - for (const [childDir, childSub] of this.extraSubscriptions.entries()) { - if (childDir !== dirKey && isPathInside(childDir, dirKey)) { - this.extraSubscriptions.delete(childDir); - childSub.unsubscribe().catch(() => {}); + return 1; + } + + let count = 0; + for (const child of node.children.values()) { + count += initSubtree(child); + } + node.leafCount = count; + + return count; + }; + + let totalLeaves = 0; + for (const root of roots) { + totalLeaves += initSubtree(root); + } + + if (totalLeaves > this.#maxSubscriptions) { + // Tier 1: non-ancestors of workspaceRoot (e.g., /libs, /node_modules) + // Tier 2: ancestors of workspaceRoot (e.g., when sibling apps/libs are directly under it) + const tier1ByDepth = new Map(); + const tier2ByDepth = new Map(); + + const collectInternalNodes = (node: DirTrieNode) => { + if (node.isTarget) { + return; + } + if (node.parent !== undefined && node.leafCount > 1) { + const isWorkspaceAncestor = isPathInside(this.#rootDirLookupKey, node.dirKey); + const bucketMap = isWorkspaceAncestor ? tier2ByDepth : tier1ByDepth; + let bucket = bucketMap.get(node.depth); + if (!bucket) { + bucket = []; + bucketMap.set(node.depth, bucket); } + bucket.push(node); } - } else { - sub.unsubscribe().catch(() => {}); + for (const child of node.children.values()) { + collectInternalNodes(child); + } + }; + + for (const root of roots) { + collectInternalNodes(root); + } + + const collapseTier = (byDepth: Map) => { + const sortedLevels = Array.from(byDepth.entries()).sort(([a], [b]) => b - a); + for (const [, nodes] of sortedLevels) { + if (totalLeaves <= this.#maxSubscriptions) { + return; + } + + const candidates = nodes + .filter((n) => n.leafCount > 1 && !hasTargetAncestor(n)) + .sort((a, b) => b.leafCount - a.leafCount || a.dirKey.localeCompare(b.dirKey)); + + for (const candidate of candidates) { + if (totalLeaves <= this.#maxSubscriptions) { + return; + } + if (candidate.leafCount <= 1 || hasTargetAncestor(candidate)) { + continue; + } + + const reduction = candidate.leafCount - 1; + candidate.isTarget = true; + candidate.children.clear(); + candidate.leafCount = 1; + totalLeaves -= reduction; + + let ancestor = candidate.parent; + while (ancestor) { + ancestor.leafCount -= reduction; + ancestor = ancestor.parent; + } + } + } + }; + + collapseTier(tier1ByDepth); + if (totalLeaves > this.#maxSubscriptions) { + collapseTier(tier2ByDepth); } - } catch { - // Ignore subscription errors for missing or restricted external directories - } finally { - this.pendingSubscriptions.delete(dirKey); } + + const desired = new Map(); + const collectTargets = (node: DirTrieNode) => { + if (node.isTarget) { + desired.set(node.dirKey, node.dirPath); + + return; + } + for (const child of node.children.values()) { + collectTargets(child); + } + }; + + for (const root of roots) { + collectTargets(root); + } + + return desired; } } @@ -609,7 +1033,9 @@ async function createParcelWatcher( const externalManager = new ParcelExternalManager( parcelWatcher, options, + rootDirPosix, rootDirLookupKey, + isCaseSensitive, handleEvents, ); @@ -629,7 +1055,7 @@ async function createParcelWatcher( const lookupKey = toLookupKey(posixPath, isCaseSensitive); if (!watchedFiles.has(lookupKey)) { watchedFiles.add(lookupKey); - void externalManager.ensureWatched(posixPath, lookupKey); + externalManager.watchFile(posixPath, lookupKey); } } }, diff --git a/packages/angular/build/src/utils/watcher_spec.ts b/packages/angular/build/src/utils/watcher_spec.ts index 547ad2695f90..3703eb9f4ce1 100644 --- a/packages/angular/build/src/utils/watcher_spec.ts +++ b/packages/angular/build/src/utils/watcher_spec.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ +import type * as ParcelWatcher from '@parcel/watcher'; import assert from 'node:assert'; import * as fs from 'node:fs'; import * as path from 'node:path'; @@ -13,6 +14,7 @@ import { setTimeout } from 'node:timers/promises'; import { type BuildWatcher, ChangedFiles, + ParcelExternalManager, createWatcher, extractNodeModulesPackageDir, getDirectoryPath, @@ -829,5 +831,364 @@ describe('Watcher', () => { fs.rmSync(externalDir, { recursive: true, force: true }); } }, 10000); + + it('should detect changes across multiple external directories when using @parcel/watcher', async () => { + const externalRoot = fs.mkdtempSync(path.join(TMP_DIR, 'parcel-external-spec-')); + let watcher: BuildWatcher | undefined; + + try { + const lib1Dir = path.join(externalRoot, 'libs', 'lib-1', 'src'); + const lib2Dir = path.join(externalRoot, 'libs', 'lib-2', 'src'); + fs.mkdirSync(lib1Dir, { recursive: true }); + fs.mkdirSync(lib2Dir, { recursive: true }); + + const file1 = path.join(lib1Dir, 'index.ts'); + const file2 = path.join(lib2Dir, 'index.ts'); + fs.writeFileSync(file1, 'export const a = 1;'); + fs.writeFileSync(file2, 'export const b = 1;'); + + // Backdate initial file timestamps to earlier than `initTime - 1000` so that any + // delayed initial FSEvents replay from file creation is ignored by the watcher. + const pastTime = new Date(Date.now() - 5000); + fs.utimesSync(file1, pastTime, pastTime); + fs.utimesSync(file2, pastTime, pastTime); + + watcher = await createWatcher({ cwd: tempDir }); + watcher.add([file1, file2]); + + await setTimeout(150); + + const iterator = watcher[Symbol.asyncIterator](); + + let nextPromise = iterator.next(); + fs.writeFileSync(file1, 'export const a = 2;'); + let result = await nextPromise; + expect(result.done).toBeFalsy(); + expect(result.value?.all.some((f: string) => f.includes('lib-1'))).toBeTrue(); + + nextPromise = iterator.next(); + fs.writeFileSync(file2, 'export const b = 2;'); + result = await nextPromise; + expect(result.done).toBeFalsy(); + expect(result.value?.all.some((f: string) => f.includes('lib-2'))).toBeTrue(); + } finally { + await watcher?.close(); + fs.rmSync(externalRoot, { recursive: true, force: true }); + } + }, 10000); + }); + + describe('ParcelExternalManager', () => { + function createMockParcelWatcher(options?: { + failAfter?: number; + onSubscribe?: (dir: string, opts?: ParcelWatcher.Options) => void; + }) { + const activeDirs = new Set(); + const subscribeHistory: { dir: string; options?: ParcelWatcher.Options }[] = []; + let totalCalls = 0; + + const mockWatcher = { + subscribe: jasmine + .createSpy('subscribe') + .and.callFake( + async ( + dir: string, + _cb: ParcelWatcher.SubscribeCallback, + opts?: ParcelWatcher.Options, + ): Promise => { + totalCalls++; + options?.onSubscribe?.(dir, opts); + if (options?.failAfter !== undefined && activeDirs.size >= options.failAfter) { + throw new Error('Error starting FSEvents stream'); + } + activeDirs.add(dir); + subscribeHistory.push({ dir, options: opts }); + + return { + unsubscribe: async () => { + activeDirs.delete(dir); + }, + }; + }, + ), + } as unknown as typeof ParcelWatcher; + + return { + mockWatcher, + activeDirs, + subscribeHistory, + getTotalCalls: () => totalCalls, + }; + } + + it('should batch synchronous watchFile calls and subsume child directories added before parent', async () => { + const { mockWatcher, activeDirs, getTotalCalls } = createMockParcelWatcher(); + const manager = new ParcelExternalManager( + mockWatcher, + undefined, + '/monorepo/apps/app', + '/monorepo/apps/app', + true, + () => {}, + ); + + // Add deeper child directories first, then their parent directory in the same synchronous turn + manager.watchFile( + '/monorepo/libs/lib-1/src/components/button/button.ts', + '/monorepo/libs/lib-1/src/components/button/button.ts', + ); + manager.watchFile( + '/monorepo/libs/lib-1/src/components/card/card.ts', + '/monorepo/libs/lib-1/src/components/card/card.ts', + ); + manager.watchFile('/monorepo/libs/lib-1/src/index.ts', '/monorepo/libs/lib-1/src/index.ts'); + + await manager.flush(); + + // Should only ever have subscribed once to the parent '/monorepo/libs/lib-1/src' + expect(getTotalCalls()).toBe(1); + expect(Array.from(activeDirs)).toEqual(['/monorepo/libs/lib-1/src']); + + await manager.close(); + }); + + it('should normalize external node_modules paths to their package root directory', async () => { + const { mockWatcher, activeDirs, getTotalCalls } = createMockParcelWatcher(); + const manager = new ParcelExternalManager( + mockWatcher, + undefined, + '/monorepo/apps/app', + '/monorepo/apps/app', + true, + () => {}, + ); + + manager.watchFile( + '/monorepo/node_modules/my-pkg/fesm2022/my-pkg.mjs', + '/monorepo/node_modules/my-pkg/fesm2022/my-pkg.mjs', + ); + manager.watchFile( + '/monorepo/node_modules/my-pkg/esm2022/sub/helper.mjs', + '/monorepo/node_modules/my-pkg/esm2022/sub/helper.mjs', + ); + manager.watchFile( + '/monorepo/node_modules/@scope/scoped-pkg/fesm2022/index.mjs', + '/monorepo/node_modules/@scope/scoped-pkg/fesm2022/index.mjs', + ); + manager.watchFile( + '/monorepo/node_modules/@scope/scoped-pkg/package.json', + '/monorepo/node_modules/@scope/scoped-pkg/package.json', + ); + + await manager.flush(); + + expect(getTotalCalls()).toBe(2); + expect(Array.from(activeDirs).sort()).toEqual([ + '/monorepo/node_modules/@scope/scoped-pkg', + '/monorepo/node_modules/my-pkg', + ]); + + // Removing one file from my-pkg should keep the package subscription active + manager.removeFile('/monorepo/node_modules/my-pkg/fesm2022/my-pkg.mjs'); + await manager.flush(); + expect(activeDirs.has('/monorepo/node_modules/my-pkg')).toBeTrue(); + + // Removing the last file from my-pkg should unsubscribe the package directory + manager.removeFile('/monorepo/node_modules/my-pkg/esm2022/sub/helper.mjs'); + await manager.flush(); + expect(activeDirs.has('/monorepo/node_modules/my-pkg')).toBeFalse(); + expect(Array.from(activeDirs)).toEqual(['/monorepo/node_modules/@scope/scoped-pkg']); + + await manager.close(); + }); + + it('should coalesce large numbers of external library and node_modules directories into common ancestors within budget', async () => { + const { mockWatcher, activeDirs, getTotalCalls } = createMockParcelWatcher(); + const manager = new ParcelExternalManager( + mockWatcher, + undefined, + '/monorepo/apps/app', + '/monorepo/apps/app', + true, + () => {}, + 64, + ); + + // Simulate 600 sibling libraries and 200 hoisted node_modules packages (800 external dirs) + for (let i = 0; i < 600; i++) { + const file = `/monorepo/libs/lib-${i}/src/index.ts`; + manager.watchFile(file, file); + } + for (let i = 0; i < 200; i++) { + const file = `/monorepo/node_modules/pkg-${i}/dist/index.mjs`; + manager.watchFile(file, file); + } + + await manager.flush(); + + // All 600 libs coalesce into '/monorepo/libs' and all 200 packages coalesce into '/monorepo/node_modules' + expect(getTotalCalls()).toBe(2); + expect(Array.from(activeDirs).sort()).toEqual(['/monorepo/libs', '/monorepo/node_modules']); + + await manager.close(); + }); + + it('should prioritize collapsing deeper branching subdirectories before broader ancestor directories', async () => { + const { mockWatcher, activeDirs } = createMockParcelWatcher(); + const manager = new ParcelExternalManager( + mockWatcher, + undefined, + '/monorepo/apps/app', + '/monorepo/apps/app', + true, + () => {}, + 3, // Budget of 3 subscriptions + ); + + // lib-1 has 4 component subdirectories, lib-2 and lib-3 have 1 each (total = 6 leaf dirs) + for (let c = 1; c <= 4; c++) { + const file = `/monorepo/libs/lib-1/src/comp-${c}/comp.ts`; + manager.watchFile(file, file); + } + manager.watchFile('/monorepo/libs/lib-2/src/index.ts', '/monorepo/libs/lib-2/src/index.ts'); + manager.watchFile('/monorepo/libs/lib-3/src/index.ts', '/monorepo/libs/lib-3/src/index.ts'); + + await manager.flush(); + + // Collapsing lib-1/src reduces total leaves from 6 to 3, meeting the budget of 3 + // without needing to collapse all of '/monorepo/libs' + expect(Array.from(activeDirs).sort()).toEqual([ + '/monorepo/libs/lib-1/src', + '/monorepo/libs/lib-2/src', + '/monorepo/libs/lib-3/src', + ]); + + await manager.close(); + }); + + it('should ignore workspaceRoot when coalescing into an ancestor of workspaceRoot (Tier 2)', async () => { + const { mockWatcher, activeDirs, subscribeHistory } = createMockParcelWatcher(); + const manager = new ParcelExternalManager( + mockWatcher, + { ignored: ['/monorepo/apps/app/dist'] }, + '/monorepo/apps/app', + '/monorepo/apps/app', + true, + () => {}, + 2, // Budget of 2 subscriptions + ); + + // Sibling apps/packages directly under /monorepo/apps (which is an ancestor of /monorepo/apps/app) + manager.watchFile( + '/monorepo/apps/shared-1/src/index.ts', + '/monorepo/apps/shared-1/src/index.ts', + ); + manager.watchFile( + '/monorepo/apps/shared-2/src/index.ts', + '/monorepo/apps/shared-2/src/index.ts', + ); + manager.watchFile( + '/monorepo/apps/shared-3/src/index.ts', + '/monorepo/apps/shared-3/src/index.ts', + ); + + await manager.flush(); + + expect(Array.from(activeDirs)).toEqual(['/monorepo/apps']); + expect(subscribeHistory.length).toBe(1); + expect(subscribeHistory[0].options?.ignore).toEqual([ + '/monorepo/apps/app/dist', + '/monorepo/apps/app', + '/monorepo/apps/app/**', + ]); + + await manager.close(); + }); + + it('should dynamically lower budget and coalesce into ancestor when subscribe fails with FSEvents stream limit error', async () => { + const externalRoot = fs.mkdtempSync(path.join(TMP_DIR, 'parcel-fallback-spec-')); + + try { + const rootPosix = toPosixPathNormalized(path.join(externalRoot, 'apps', 'app')); + const libFiles: string[] = []; + for (let i = 0; i < 6; i++) { + const libDir = path.join(externalRoot, 'libs', `lib-${i}`, 'src'); + fs.mkdirSync(libDir, { recursive: true }); + const file = toPosixPathNormalized(path.join(libDir, 'index.ts')); + fs.writeFileSync(file, 'export const x = 1;'); + libFiles.push(file); + } + + // Allow at most 2 active FSEvents streams even though manager budget starts at 64 + const { mockWatcher, activeDirs } = createMockParcelWatcher({ failAfter: 2 }); + const manager = new ParcelExternalManager( + mockWatcher, + undefined, + rootPosix, + rootPosix, + true, + () => {}, + 64, + ); + + for (const file of libFiles) { + manager.watchFile(file, file); + } + + await manager.flush(); + + // Should have shrunk and coalesced the 6 libraries into the single '/libs' ancestor directory + const expectedLibsDir = toPosixPathNormalized(path.join(externalRoot, 'libs')); + expect(Array.from(activeDirs)).toEqual([expectedLibsDir]); + + await manager.close(); + } finally { + fs.rmSync(externalRoot, { recursive: true, force: true }); + } + }); + + it('should uncoalesce and subscribe to remaining leaf directories when removals bring count back within budget', async () => { + const { mockWatcher, activeDirs } = createMockParcelWatcher(); + const manager = new ParcelExternalManager( + mockWatcher, + undefined, + '/monorepo/apps/app', + '/monorepo/apps/app', + true, + () => {}, + 2, // Budget of 2 subscriptions + ); + + const file1 = '/monorepo/libs/lib-1/src/index.ts'; + const file2 = '/monorepo/libs/lib-2/src/index.ts'; + const file3 = '/monorepo/libs/lib-3/src/index.ts'; + + manager.watchFile(file1, file1); + manager.watchFile(file2, file2); + manager.watchFile(file3, file3); + + await manager.flush(); + + // 3 directories exceed budget of 2, so they coalesce into '/monorepo/libs' + expect(Array.from(activeDirs)).toEqual(['/monorepo/libs']); + + // Removing file3 brings remaining directories to 2, which fits within budget + manager.removeFile(file3); + await manager.flush(); + + expect(Array.from(activeDirs).sort()).toEqual([ + '/monorepo/libs/lib-1/src', + '/monorepo/libs/lib-2/src', + ]); + + // Removing the remaining files unsubscribes everything + manager.removeFile(file1); + manager.removeFile(file2); + await manager.flush(); + + expect(activeDirs.size).toBe(0); + + await manager.close(); + }); }); }); From 14cded63307cf76ad4278d2520ff351131622d01 Mon Sep 17 00:00:00 2001 From: Angular Robot Date: Thu, 15 Oct 2026 13:02:11 +0000 Subject: [PATCH 43/52] build: update cross-repo angular dependencies See associated pull request for more information. --- .../assistant-to-the-branch-manager.yml | 2 +- .github/workflows/ci.yml | 52 +- .github/workflows/dev-infra.yml | 6 +- .github/workflows/perf.yml | 6 +- .github/workflows/pr.yml | 44 +- MODULE.bazel | 6 +- MODULE.bazel.lock | 50 +- package.json | 24 +- packages/angular/ssr/package.json | 12 +- packages/ngtools/webpack/package.json | 4 +- pnpm-lock.yaml | 456 ++++++++---------- tests/e2e/ng-snapshot/package.json | 32 +- 12 files changed, 330 insertions(+), 364 deletions(-) diff --git a/.github/workflows/assistant-to-the-branch-manager.yml b/.github/workflows/assistant-to-the-branch-manager.yml index 8c6035d666dc..f50263aad6ab 100644 --- a/.github/workflows/assistant-to-the-branch-manager.yml +++ b/.github/workflows/assistant-to-the-branch-manager.yml @@ -18,6 +18,6 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - - uses: angular/dev-infra/github-actions/branch-manager@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + - uses: angular/dev-infra/github-actions/branch-manager@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56dde16b608c..6397ee443590 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,9 +21,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/setup@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Generate JSON schema types @@ -44,11 +44,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/setup@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -61,11 +61,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/setup@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -84,13 +84,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/setup@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -100,11 +100,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/setup@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -137,7 +137,7 @@ jobs: runs-on: windows-2025 steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Download built Windows E2E tests @@ -164,13 +164,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/setup@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -188,13 +188,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/setup@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -208,13 +208,13 @@ jobs: SAUCE_TUNNEL_IDENTIFIER: angular-cli-${{ github.workflow }}-${{ github.run_number }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/setup@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Start Sauce Connect @@ -245,11 +245,11 @@ jobs: CIRCLE_BRANCH: ${{ github.ref_name }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/setup@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - run: pnpm admin snapshots --verbose env: SNAPSHOT_BUILDS_GITHUB_TOKEN: ${{ secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN }} diff --git a/.github/workflows/dev-infra.yml b/.github/workflows/dev-infra.yml index f508452e9456..b85b240f82dc 100644 --- a/.github/workflows/dev-infra.yml +++ b/.github/workflows/dev-infra.yml @@ -16,21 +16,21 @@ jobs: if: github.event_name == 'pull_request_target' runs-on: ubuntu-latest steps: - - uses: angular/dev-infra/github-actions/labeling/pull-request@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + - uses: angular/dev-infra/github-actions/labeling/pull-request@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} post_approval_changes: if: github.event_name == 'pull_request_target' runs-on: ubuntu-latest steps: - - uses: angular/dev-infra/github-actions/post-approval-changes@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + - uses: angular/dev-infra/github-actions/post-approval-changes@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} issue_labels: if: github.event_name == 'issues' runs-on: ubuntu-latest steps: - - uses: angular/dev-infra/github-actions/labeling/issue@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + - uses: angular/dev-infra/github-actions/labeling/issue@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} google-generative-ai-key: ${{ secrets.GOOGLE_GENERATIVE_AI_KEY }} diff --git a/.github/workflows/perf.yml b/.github/workflows/perf.yml index 1c275f2d1a0d..21a061c26de5 100644 --- a/.github/workflows/perf.yml +++ b/.github/workflows/perf.yml @@ -22,7 +22,7 @@ jobs: workflows: ${{ steps.workflows.outputs.workflows }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Install node modules run: pnpm install --frozen-lockfile - id: workflows @@ -40,9 +40,9 @@ jobs: workflow: ${{ fromJSON(needs.list.outputs.workflows) }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/setup@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Install node modules run: pnpm install --frozen-lockfile # We utilize the google-github-actions/auth action to allow us to get an active credential using workflow diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index d9195bdf9f8c..f0eb6e091f47 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -34,9 +34,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/setup@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup ESLint Caching uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: @@ -66,17 +66,17 @@ jobs: # it has been merged. run: pnpm ng-dev format changed --check ${{ github.event.pull_request.base.sha }} - name: Check Package Licenses - uses: angular/dev-infra/github-actions/linting/licenses@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/linting/licenses@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main build: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/setup@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Build release targets @@ -93,11 +93,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/setup@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Run module and package tests @@ -114,13 +114,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/setup@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Run CLI E2E tests run: pnpm bazel test --test_env=E2E_SHARD_TOTAL=6 --test_env=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests:e2e.${{ matrix.subset }}_node${{ matrix.node }} @@ -128,11 +128,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/setup@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Build E2E tests for Windows on Linux @@ -156,7 +156,7 @@ jobs: runs-on: windows-2025 steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Download built Windows E2E tests @@ -183,13 +183,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/setup@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Run CLI E2E tests run: pnpm bazel test --test_env=E2E_SHARD_TOTAL=3 --test_env=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests:e2e.${{ matrix.subset }}_node${{ matrix.node }} @@ -205,12 +205,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/setup@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@28ae58d2ad683fb3991006c23a9829c08b65aaec # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@c09a8058c7eee99ed9cec6213ff967bad6d6b73c # main - name: Run CLI E2E tests run: pnpm bazel test --test_env=E2E_SHARD_TOTAL=6 --test_env=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests:e2e.snapshots.${{ matrix.subset }}_node${{ matrix.node }} diff --git a/MODULE.bazel b/MODULE.bazel index a4caf9a9bc97..f81a41dd6522 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -19,21 +19,21 @@ bazel_dep(name = "aspect_rules_jasmine", version = "2.0.4") bazel_dep(name = "rules_angular") git_override( module_name = "rules_angular", - commit = "b5869cff3db5d2217b8896d483e75af8a1d26712", + commit = "bfe6e98434982bad38c393f1bd472ec33f16cd32", remote = "https://github.com/angular/rules_angular.git", ) bazel_dep(name = "devinfra") git_override( module_name = "devinfra", - commit = "28ae58d2ad683fb3991006c23a9829c08b65aaec", + commit = "c09a8058c7eee99ed9cec6213ff967bad6d6b73c", remote = "https://github.com/angular/dev-infra.git", ) bazel_dep(name = "rules_browsers") git_override( module_name = "rules_browsers", - commit = "4b53d68eed02bbb0901b21fb02b8cf99f4f59a52", + commit = "48a956da3908e5c923f21e6ffd1c72c5605d61fe", remote = "https://github.com/angular/rules_browsers.git", ) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 5f2282f7683b..4cb3f4cc542f 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -445,16 +445,16 @@ }, "@@rules_browsers+//browsers:extensions.bzl%browsers": { "general": { - "bzlTransitiveDigest": "/FonktAou7w4aKjGZUZDFFOlASeGnKNw0QALxUIdtuE=", + "bzlTransitiveDigest": "OZ8V6/fUTaz9GXcrxaCB7fqf29DyphGiugzTRl7yPR8=", "usagesDigest": "FmXYJVoVJlnfUU8x8gObSvu4qWcco/9Faw61aC/wBF0=", "recordedInputs": [], "generatedRepoSpecs": { "rules_browsers_chrome_linux": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "9541eafbc02f85e3ec0c24b05f8bbffe88094389949860681bf6055aef668d7b", + "sha256": "e3f19706550899e76efdadb1ad172c3af2bb89c137a1350fe7f72333d2a4d0a4", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/157.0.8099.0/linux64/chrome-headless-shell-linux64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/158.0.8106.0/linux64/chrome-headless-shell-linux64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-linux64/chrome-headless-shell" @@ -470,9 +470,9 @@ "rules_browsers_chrome_mac": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "358f032d48a0b825b0601b89b970da5a7c245344ed7a557a3ef8613c342521b0", + "sha256": "1f98187b068d2c631d4465a437ce7c4d83f7bde9b6a0e19faae1c9de04eb4a4d", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/157.0.8099.0/mac-x64/chrome-headless-shell-mac-x64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/158.0.8106.0/mac-x64/chrome-headless-shell-mac-x64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-mac-x64/chrome-headless-shell" @@ -488,9 +488,9 @@ "rules_browsers_chrome_mac_arm": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "c3de600edda5e11aa40918f123781040cd6e9c2509a2acfc466b773bf7c9b326", + "sha256": "a564d6b8c498a1c8624e9e14f83ece2d9903db1ec2b491e9fa8fdc7805187dce", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/157.0.8099.0/mac-arm64/chrome-headless-shell-mac-arm64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/158.0.8106.0/mac-arm64/chrome-headless-shell-mac-arm64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-mac-arm64/chrome-headless-shell" @@ -506,9 +506,9 @@ "rules_browsers_chrome_win64": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "b2e81e06ac46d3355bc6428b3abe97308d34e810d4404427bbd14665111e67a1", + "sha256": "3a874f0d0d36a84a89c4fedf7e0dfdcad7e4818bbaf22842ac06762305256b87", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/157.0.8099.0/win64/chrome-headless-shell-win64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/158.0.8106.0/win64/chrome-headless-shell-win64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-win64/chrome-headless-shell.exe" @@ -524,9 +524,9 @@ "rules_browsers_chromedriver_linux": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "cf16fed1899de0f0b8999389779cefbb6696c5fd44ad9718ce2195a3ff5ca029", + "sha256": "51b3afc67a5765403601420074ad7091e083133ca8f82e878a49b783614256df", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/157.0.8099.0/linux64/chromedriver-linux64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/158.0.8106.0/linux64/chromedriver-linux64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-linux64/chromedriver" @@ -540,9 +540,9 @@ "rules_browsers_chromedriver_mac": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "ba472bdd32ee62a98f04fcca364015a0df241fdf85ee7d834a048b5fdfd90fd3", + "sha256": "944924ff8ba2ca15407e788f1d36918e4979f9f5329d0bdf8689c9a96c1818fc", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/157.0.8099.0/mac-x64/chromedriver-mac-x64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/158.0.8106.0/mac-x64/chromedriver-mac-x64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-mac-x64/chromedriver" @@ -556,9 +556,9 @@ "rules_browsers_chromedriver_mac_arm": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "8fe44ebac5303278a5d533c114ad0dbed0df9c218bce5b80d606078472ea95bd", + "sha256": "2b46fd5f3838e6a2ea73e29e67537c97f43a23eeddbf5522ac15cd27f05a4987", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/157.0.8099.0/mac-arm64/chromedriver-mac-arm64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/158.0.8106.0/mac-arm64/chromedriver-mac-arm64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-mac-arm64/chromedriver" @@ -572,9 +572,9 @@ "rules_browsers_chromedriver_win64": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "1fadd71af32db4e3497ce4faac3f07503f4c4cdad8747e71ff62c5c9c3dd05e1", + "sha256": "5c38e2e1d06b51e34885fb0474bf74a5bb36e4a6a517327df8d74f49d7cf9dd8", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/157.0.8099.0/win64/chromedriver-win64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/158.0.8106.0/win64/chromedriver-win64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-win64/chromedriver.exe" @@ -588,9 +588,9 @@ "rules_browsers_firefox_linux": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "42f2c62a562316982ef5a796738c57602bf84a984f5c616e80bcff4627f78fff", + "sha256": "9549b054ec4cf85f50f6a19d8c6fb79580312e71ebc4ec2cb217ec9af09dc12a", "urls": [ - "https://archive.mozilla.org/pub/firefox/releases/157.0/linux-x86_64/en-US/firefox-157.0.tar.xz" + "https://archive.mozilla.org/pub/firefox/releases/158.0/linux-x86_64/en-US/firefox-158.0.tar.xz" ], "named_files": { "FIREFOX": "firefox/firefox" @@ -604,9 +604,9 @@ "rules_browsers_firefox_mac": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "df6d8c79b6126bcf24cb70ebab9371916a662028e2d706e462d432e78fdf396c", + "sha256": "dfe8508ee8880cec1578253eb02b9154b5971a55e832d97396f463cd07b5ef67", "urls": [ - "https://archive.mozilla.org/pub/firefox/releases/157.0/mac/en-US/Firefox%20157.0.dmg" + "https://archive.mozilla.org/pub/firefox/releases/158.0/mac/en-US/Firefox%20158.0.dmg" ], "named_files": { "FIREFOX": "Firefox.app/Contents/MacOS/firefox" @@ -620,9 +620,9 @@ "rules_browsers_firefox_mac_arm": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "df6d8c79b6126bcf24cb70ebab9371916a662028e2d706e462d432e78fdf396c", + "sha256": "dfe8508ee8880cec1578253eb02b9154b5971a55e832d97396f463cd07b5ef67", "urls": [ - "https://archive.mozilla.org/pub/firefox/releases/157.0/mac/en-US/Firefox%20157.0.dmg" + "https://archive.mozilla.org/pub/firefox/releases/158.0/mac/en-US/Firefox%20158.0.dmg" ], "named_files": { "FIREFOX": "Firefox.app/Contents/MacOS/firefox" @@ -636,9 +636,9 @@ "rules_browsers_firefox_win64": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "58c90afab6e4b9a6b34d2958fe06d1a143dd9226ea8834377e5cd45e815936d7", + "sha256": "450ab1c772e02f0c9ef02f489b153d86c45bd9311b202d10dc233f3c0206f8d1", "urls": [ - "https://archive.mozilla.org/pub/firefox/releases/157.0/win64/en-US/Firefox%20Setup%20157.0.exe" + "https://archive.mozilla.org/pub/firefox/releases/158.0/win64/en-US/Firefox%20Setup%20158.0.exe" ], "named_files": { "FIREFOX": "core/firefox.exe" diff --git a/package.json b/package.json index 6a7407853c21..6e4cab8c46dc 100644 --- a/package.json +++ b/package.json @@ -43,23 +43,23 @@ }, "homepage": "https://github.com/angular/angular-cli", "dependencies": { - "@angular/compiler-cli": "22.3.0-next.1", + "@angular/compiler-cli": "22.3.0-next.2", "typescript": "6.0.3" }, "devDependencies": { - "@angular/animations": "22.3.0-next.1", + "@angular/animations": "22.3.0-next.2", "@angular/cdk": "22.3.0-next.2", - "@angular/common": "22.3.0-next.1", - "@angular/compiler": "22.3.0-next.1", - "@angular/core": "22.3.0-next.1", - "@angular/forms": "22.3.0-next.1", - "@angular/localize": "22.3.0-next.1", + "@angular/common": "22.3.0-next.2", + "@angular/compiler": "22.3.0-next.2", + "@angular/core": "22.3.0-next.2", + "@angular/forms": "22.3.0-next.2", + "@angular/localize": "22.3.0-next.2", "@angular/material": "22.3.0-next.2", - "@angular/ng-dev": "https://github.com/angular/dev-infra-private-ng-dev-builds.git#fa4308affb4a0dde34ebc95196b58550752485a2", - "@angular/platform-browser": "22.3.0-next.1", - "@angular/platform-server": "22.3.0-next.1", - "@angular/router": "22.3.0-next.1", - "@angular/service-worker": "22.3.0-next.1", + "@angular/ng-dev": "https://github.com/angular/dev-infra-private-ng-dev-builds.git#940c0beef0de4cb128e90962d47ff80e352a1cd8", + "@angular/platform-browser": "22.3.0-next.2", + "@angular/platform-server": "22.3.0-next.2", + "@angular/router": "22.3.0-next.2", + "@angular/service-worker": "22.3.0-next.2", "@babel/core": "8.0.7", "@bazel/bazelisk": "1.28.1", "@bazel/buildifier": "8.2.1", diff --git a/packages/angular/ssr/package.json b/packages/angular/ssr/package.json index 9d86125f4aad..a3049daf662d 100644 --- a/packages/angular/ssr/package.json +++ b/packages/angular/ssr/package.json @@ -38,12 +38,12 @@ }, "devDependencies": { "@angular-devkit/schematics": "workspace:*", - "@angular/common": "22.3.0-next.1", - "@angular/compiler": "22.3.0-next.1", - "@angular/core": "22.3.0-next.1", - "@angular/platform-browser": "22.3.0-next.1", - "@angular/platform-server": "22.3.0-next.1", - "@angular/router": "22.3.0-next.1", + "@angular/common": "22.3.0-next.2", + "@angular/compiler": "22.3.0-next.2", + "@angular/core": "22.3.0-next.2", + "@angular/platform-browser": "22.3.0-next.2", + "@angular/platform-server": "22.3.0-next.2", + "@angular/router": "22.3.0-next.2", "@schematics/angular": "workspace:*" }, "sideEffects": false, diff --git a/packages/ngtools/webpack/package.json b/packages/ngtools/webpack/package.json index a7488b0d9316..13cea96fc202 100644 --- a/packages/ngtools/webpack/package.json +++ b/packages/ngtools/webpack/package.json @@ -17,8 +17,8 @@ }, "devDependencies": { "@angular-devkit/core": "workspace:0.0.0-PLACEHOLDER", - "@angular/compiler": "22.3.0-next.1", - "@angular/compiler-cli": "22.3.0-next.1", + "@angular/compiler": "22.3.0-next.2", + "@angular/compiler-cli": "22.3.0-next.2", "typescript": "6.0.3", "webpack": "5.111.1" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e38b036ee3d9..ff51f38b4f6c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -172,8 +172,8 @@ importers: .: dependencies: '@angular/compiler-cli': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(typescript@6.0.3) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(@angular/compiler@22.3.0-next.2)(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 @@ -184,44 +184,44 @@ importers: built: true devDependencies: '@angular/animations': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)) '@angular/cdk': specifier: 22.3.0-next.2 - version: 22.3.0-next.2(1e228ab395252fe57958c1335d3a301f) + version: 22.3.0-next.2(e02572097466d520d7eb144e95d6bbd2) '@angular/common': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) '@angular/compiler': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1 + specifier: 22.3.0-next.2 + version: 22.3.0-next.2 '@angular/core': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3) '@angular/forms': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2) '@angular/localize': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(@angular/compiler-cli@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(typescript@6.0.3))(@angular/compiler@22.3.0-next.1) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(@angular/compiler-cli@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(typescript@6.0.3))(@angular/compiler@22.3.0-next.2) '@angular/material': specifier: 22.3.0-next.2 - version: 22.3.0-next.2(1acbd77e3019024ea0df0dc9f59ed8c0) + version: 22.3.0-next.2(4016851894464b4783f4f873310c276b) '@angular/ng-dev': - specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#fa4308affb4a0dde34ebc95196b58550752485a2 - version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/fa4308affb4a0dde34ebc95196b58550752485a2 + specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#940c0beef0de4cb128e90962d47ff80e352a1cd8 + version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/940c0beef0de4cb128e90962d47ff80e352a1cd8 '@angular/platform-browser': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)) '@angular/platform-server': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/compiler@22.3.0-next.1)(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/compiler@22.3.0-next.2)(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2) '@angular/router': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2) '@angular/service-worker': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) '@babel/core': specifier: 8.0.7 version: 8.0.7 @@ -464,7 +464,7 @@ importers: version: 30.1.2(@noble/hashes@1.8.0) ng-packagr: specifier: 22.3.0-next.2 - version: 22.3.0-next.2(@angular/compiler-cli@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(typescript@6.0.3))(supports-color@11.0.0)(tslib@2.8.1)(typescript@6.0.3) + version: 22.3.0-next.2(@angular/compiler-cli@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(typescript@6.0.3))(supports-color@11.0.0)(tslib@2.8.1)(typescript@6.0.3) rxjs: specifier: 7.8.2 version: 7.8.2 @@ -582,7 +582,7 @@ importers: version: 4.9.1(supports-color@11.0.0) ng-packagr: specifier: 22.3.0-next.2 - version: 22.3.0-next.2(@angular/compiler-cli@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(typescript@6.0.3))(supports-color@11.0.0)(tslib@2.8.1)(typescript@6.0.3) + version: 22.3.0-next.2(@angular/compiler-cli@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(typescript@6.0.3))(supports-color@11.0.0)(tslib@2.8.1)(typescript@6.0.3) postcss: specifier: 8.5.29 version: 8.5.29 @@ -670,23 +670,23 @@ importers: specifier: workspace:* version: link:../../angular_devkit/schematics '@angular/common': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) '@angular/compiler': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1 + specifier: 22.3.0-next.2 + version: 22.3.0-next.2 '@angular/core': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3) '@angular/platform-browser': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)) '@angular/platform-server': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/compiler@22.3.0-next.1)(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/compiler@22.3.0-next.2)(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2) '@angular/router': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2) '@schematics/angular': specifier: workspace:* version: link:../../schematics/angular @@ -870,7 +870,7 @@ importers: version: 3.0.4(bufferutil@4.1.0)(debug@4.4.3(supports-color@11.0.0))(supports-color@11.0.0)(utf-8-validate@6.0.6) ng-packagr: specifier: 22.3.0-next.2 - version: 22.3.0-next.2(@angular/compiler-cli@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(typescript@6.0.3))(supports-color@11.0.0)(tslib@2.8.1)(typescript@6.0.3) + version: 22.3.0-next.2(@angular/compiler-cli@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(typescript@6.0.3))(supports-color@11.0.0)(tslib@2.8.1)(typescript@6.0.3) sass: specifier: 1.105.1 version: 1.105.1 @@ -965,11 +965,11 @@ importers: specifier: workspace:0.0.0-PLACEHOLDER version: link:../../angular_devkit/core '@angular/compiler': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1 + specifier: 22.3.0-next.2 + version: 22.3.0-next.2 '@angular/compiler-cli': - specifier: 22.3.0-next.1 - version: 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(typescript@6.0.3) + specifier: 22.3.0-next.2 + version: 22.3.0-next.2(@angular/compiler@22.3.0-next.2)(typescript@6.0.3) typescript: specifier: 6.0.3 version: 6.0.3 @@ -1029,11 +1029,12 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@angular/animations@22.3.0-next.1': - resolution: {integrity: sha512-YdJE9xE7EO9xJtXNcWFXCatofYRXmkZm5oPOaKBCTHvX12Iw3SQsybxXr23Lq1gHscAZnqffEfhQ78TdnSl5wA==} + '@angular/animations@22.3.0-next.2': + resolution: {integrity: sha512-YJCMY2lUtiIQNfqTXnwbKjePHAEq4sION4i+66eH7Fhog55eust9BQ7zVCp8CtfPUF2kNwhiMyU6DbZQCxmN1w==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0} + deprecated: '@angular/animations is deprecated. Use `animate.enter` and `animate.leave` instead. For more information see: https://v22.angular.dev/guide/animations.' peerDependencies: - '@angular/core': 22.3.0-next.1 + '@angular/core': 22.3.0-next.2 '@angular/cdk@22.3.0-next.2': resolution: {integrity: sha512-UlleZDkYVds93nKOJ32g393Ca7XyrG+c8r5XoQG3aQHKe5L+lc5HjmPGAJ1Y80iotUQG3NFsgwLnweCGV12yWw==} @@ -1044,33 +1045,33 @@ packages: '@angular/platform-browser': ^22.0.0-0 || ^22.1.0-0 || ^22.2.0-0 || ^22.3.0-0 || ^23.0.0-0 rxjs: ^6.5.3 || ^7.4.0 - '@angular/common@22.3.0-next.1': - resolution: {integrity: sha512-vJ4X+f43MIfOMKJc53ttkwxKSP6pfOFgfZ1m+W6fAIF5Ydy49/GnXIUbM2rtcbhsSYgh+95YMs3lhUrgyMXEUw==} + '@angular/common@22.3.0-next.2': + resolution: {integrity: sha512-w4oG/QGNTC5oY+vBf4WnODDr56vvPt8Y0TgLpDy6mW6ephWaIx8dAgvFdlpohU5R1cOYAABeLboQHtS6pdP8Fg==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0} peerDependencies: - '@angular/core': 22.3.0-next.1 + '@angular/core': 22.3.0-next.2 rxjs: ^6.5.3 || ^7.4.0 - '@angular/compiler-cli@22.3.0-next.1': - resolution: {integrity: sha512-yfJ4jfjdTjTJYhWT3A8aEWZsk4xwTTB/S0oVi9VWm7HAb2trn5c3F5B/nWUJSSX5CXQ8TAnzN27mca2ZhyUPLw==} + '@angular/compiler-cli@22.3.0-next.2': + resolution: {integrity: sha512-r0Cq0n88GBn/iOFAL/oLGC3uBAGMINAYtZDA0gvIG+WZPuyo0CPeUEmAndAFDzuiAPegfXVi8yPlfzLS6uP5mw==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0} hasBin: true peerDependencies: - '@angular/compiler': 22.3.0-next.1 + '@angular/compiler': 22.3.0-next.2 typescript: '>=6.0 <6.1' peerDependenciesMeta: typescript: optional: true - '@angular/compiler@22.3.0-next.1': - resolution: {integrity: sha512-58W3f6lwfMwAlmoKfK4qigYuRQkRF0ZGZiSjAEXFhU1sV48pgQaADiz/2cfNGD3pEcb99sW9853XzDA9zzcbqA==} + '@angular/compiler@22.3.0-next.2': + resolution: {integrity: sha512-ayaEJt1ZDS9qKmAvQHq47m3FSMt2Au95KL+ucElgBHGV0TIuXjLdc25smiRj6Jr47U9D1zbEnFoVgWhKBuCl7g==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0} - '@angular/core@22.3.0-next.1': - resolution: {integrity: sha512-6Y4bgGkZmje+7Ct8L3PARXfpm5ZrUYuWYKNz4Xtlr08Fsx1Fp2oroUQ8BsPgZGgfzmHaWyTBE/fvK7ZbybKcjw==} + '@angular/core@22.3.0-next.2': + resolution: {integrity: sha512-9onGgNA0v0q9UI31uVAk3K5Q2r/ye82qwKsQv5FesyZ1hnEyrMMc0kdTzHkgDDRS2xpwVHchZH8BTgJA6A+SGQ==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0} peerDependencies: - '@angular/compiler': 22.3.0-next.1 + '@angular/compiler': 22.3.0-next.2 rxjs: ^6.5.3 || ^7.4.0 zone.js: ~0.15.0 || ~0.16.0 peerDependenciesMeta: @@ -1079,22 +1080,22 @@ packages: zone.js: optional: true - '@angular/forms@22.3.0-next.1': - resolution: {integrity: sha512-dssi5/s/DekmNKDA8zFDgfDVLrK2akZxg0lFO+e/pDeSYBKoalbljtAssPFEdGCiDdfmz6pFasvRw50TYI1ErQ==} + '@angular/forms@22.3.0-next.2': + resolution: {integrity: sha512-1NF2giTkXbULCVTNV8fPooKa8HKYEozWdgzZdCHvtrgIF6C2aW+PN/4ZJTddQjFBjH/4XnQ2xfM7nFCm/SQJuw==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0} peerDependencies: - '@angular/common': 22.3.0-next.1 - '@angular/core': 22.3.0-next.1 - '@angular/platform-browser': 22.3.0-next.1 + '@angular/common': 22.3.0-next.2 + '@angular/core': 22.3.0-next.2 + '@angular/platform-browser': 22.3.0-next.2 rxjs: ^6.5.3 || ^7.4.0 - '@angular/localize@22.3.0-next.1': - resolution: {integrity: sha512-KPZuMWghal8+ZQn3N8s6shDZTyKTFSyw55ooxxhJNt+bOQ++mmjPJ7JCen39qAAILYpgI3IriLnswsbhGnGDNQ==} + '@angular/localize@22.3.0-next.2': + resolution: {integrity: sha512-Q0+i9GURr6A6jUIi5N4b/2ev8ZKDKfcZ1e1B9u6jT+wb1/mryB+8sJnFD3sT7a+E/2wRkNk5GCQuT+HjYzi+HQ==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0} hasBin: true peerDependencies: - '@angular/compiler': 22.3.0-next.1 - '@angular/compiler-cli': 22.3.0-next.1 + '@angular/compiler': 22.3.0-next.2 + '@angular/compiler-cli': 22.3.0-next.2 '@angular/material@22.3.0-next.2': resolution: {integrity: sha512-4l6+DzUtwIH+SYrZdT54Lg7sNvFu6+MmLxlQQB8TtC5V5EijqOv1rjLmp+mFFgpVFmwlZwdGS8vJfRvkzKLY2w==} @@ -1106,47 +1107,47 @@ packages: '@angular/platform-browser': ^22.0.0-0 || ^22.1.0-0 || ^22.2.0-0 || ^22.3.0-0 || ^23.0.0-0 rxjs: ^6.5.3 || ^7.4.0 - '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/fa4308affb4a0dde34ebc95196b58550752485a2': - resolution: {gitHosted: true, integrity: sha512-zq1Lg7edQb2cf9QrSiQEU/+LwY4e/af9tN9W3hO5jDdYK+gp+sYZbBbuzounSWkmK+j+oG0K5CA9/kmyHAimZg==, tarball: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/fa4308affb4a0dde34ebc95196b58550752485a2} - version: 0.0.0-f28485704b2d1f81ae380a8296a4f14d9852c248 + '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/940c0beef0de4cb128e90962d47ff80e352a1cd8': + resolution: {gitHosted: true, integrity: sha512-6d8sBwbru5J4TsfMlHneqn1PD+K2p5l5HGKOba3Y/Ygl+bUEtxIJyM8aRgX88WWgVwjcaKSByQ6gClVxjqNznw==, tarball: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/940c0beef0de4cb128e90962d47ff80e352a1cd8} + version: 0.0.0-f8062d1d0f50e59fcb36a9375a596f416204ee28 hasBin: true - '@angular/platform-browser@22.3.0-next.1': - resolution: {integrity: sha512-2mhIqbG0U75M3m2zICdF1qInDsuwiS+asx/xHWXPNAC1Igsiiq2DrCo9lGfKAuYpORvRWJfppXSD88atBeiDJw==} + '@angular/platform-browser@22.3.0-next.2': + resolution: {integrity: sha512-/KrZjns+lbZx9pMpWLI1E7C5y8B5veA8D/5dWJnNuiUmbAWevaEGpsMl1xGnopuE8JrJvUEOI2aSU4oT729FIQ==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0} peerDependencies: - '@angular/animations': 22.3.0-next.1 - '@angular/common': 22.3.0-next.1 - '@angular/core': 22.3.0-next.1 + '@angular/animations': 22.3.0-next.2 + '@angular/common': 22.3.0-next.2 + '@angular/core': 22.3.0-next.2 peerDependenciesMeta: '@angular/animations': optional: true - '@angular/platform-server@22.3.0-next.1': - resolution: {integrity: sha512-sGX0TGZMoN2c5j3kC6egIoTaD8lNurzIlRbbOAlFhkv6I8NJuyStk74pXn9yTsi2co+i/b8eAQe7Jw0mRXa6gA==} + '@angular/platform-server@22.3.0-next.2': + resolution: {integrity: sha512-AyegJGA+qdjqUJGPX8IysYKqt5XUoLYnjmVzzBV3bYrN0kt0g9SRirm4QCExQB30v/g+AKiVI9Fib50VyU/O9Q==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0} peerDependencies: - '@angular/common': 22.3.0-next.1 - '@angular/compiler': 22.3.0-next.1 - '@angular/core': 22.3.0-next.1 - '@angular/platform-browser': 22.3.0-next.1 + '@angular/common': 22.3.0-next.2 + '@angular/compiler': 22.3.0-next.2 + '@angular/core': 22.3.0-next.2 + '@angular/platform-browser': 22.3.0-next.2 rxjs: ^6.5.3 || ^7.4.0 - '@angular/router@22.3.0-next.1': - resolution: {integrity: sha512-Syu0u+mWinMzwLYidzi1yy2wbXmljRucsLE1jwaaf97rZ6Lqqc8cgnfWBSwxVdZ1r8qhR5zlauvAN/+cbiMF3g==} + '@angular/router@22.3.0-next.2': + resolution: {integrity: sha512-b5Sn7sokZxL5rdN0M8Hf0FYexYo+l5vA7gcxpoJld00QPtv6Uq75mqjhp6MFIk8pWhANY3RoKEjHMdUoNgO4kA==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0} peerDependencies: - '@angular/common': 22.3.0-next.1 - '@angular/core': 22.3.0-next.1 - '@angular/platform-browser': 22.3.0-next.1 + '@angular/common': 22.3.0-next.2 + '@angular/core': 22.3.0-next.2 + '@angular/platform-browser': 22.3.0-next.2 rxjs: ^6.5.3 || ^7.4.0 - '@angular/service-worker@22.3.0-next.1': - resolution: {integrity: sha512-KStwvrt0vE8UAfXEE1GtIJm1b/oKu5XNSzCMqF/xE+VjSTrhnwNaKfyqXbK+7dVwr42AcUifTkOKJLq8zlz8fQ==} + '@angular/service-worker@22.3.0-next.2': + resolution: {integrity: sha512-L4a2at4NHToTNHwD03ir3w1ZXSrM/aARE2j4y7tcYBQXPQlSqwC7Bg4QHQecZ8Ua+eh8ssdVdpb8kPL4A+85pQ==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0} hasBin: true peerDependencies: - '@angular/core': 22.3.0-next.1 + '@angular/core': 22.3.0-next.2 rxjs: ^6.5.3 || ^7.4.0 '@asamuzakjp/css-color@7.1.5': @@ -1177,10 +1178,6 @@ packages: resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} engines: {node: '>=6.9.0'} - '@babel/core@8.0.6': - resolution: {integrity: sha512-5zwYt1V4ji3mXKKRIAkohSJ29WepxNwxQi+7y7P5AcVPh1dcxnZBU2cfxHnPwS+u9+lZnXPsv30TQaF2xg+Tfg==} - engines: {node: ^22.18.0 || >=24.11.0} - '@babel/core@8.0.7': resolution: {integrity: sha512-ZIsZWBG6Y1oa+8fkQVp0xeCdjCHBkXFCCIWrmg9SvejVvfcVQgKKRmGrBDWfM7rilhvnRoEuaqa5dkK7KB3pHA==} engines: {node: ^22.18.0 || >=24.11.0} @@ -2282,8 +2279,8 @@ packages: resolution: {integrity: sha512-IJn+8A3QZJfe7FUtWqHVNo3xJs7KFpurCWGWCiCz3oEh+BkRymKZ1QxfAbU2yGMDzTytLGQ2IV6T2r3cuo75/w==} engines: {node: '>=18'} - '@google/genai@2.28.0': - resolution: {integrity: sha512-hyNAJj+ywu3L46qlZod6KO/JvcT3QONz6VCiPevC/FWOjAD+LQb7DMLUoV8vzoLpt61Q0ruQX99iqbxEjPJWmw==} + '@google/genai@2.29.1': + resolution: {integrity: sha512-keU+JsY11fT4ykdFA6Q8iQHBgOAAVssFLxPtXRjCIEr5Zt2GzE75c22bBmq87XbhgtpuKaObnSgsrG60rj0ZMA==} engines: {node: '>=20.0.0'} peerDependencies: '@modelcontextprotocol/sdk': ^1.25.2 @@ -3804,8 +3801,8 @@ packages: '@types/node@22.20.5': resolution: {integrity: sha512-U2+DNr+wSjpsTS/wZGYHq7GcwfuSmKiKvoPvK22zwTlRhU91yOniN4qRR5KhIjvif7ysw/dz/hKmfDH0Ris4aA==} - '@types/node@24.19.1': - resolution: {integrity: sha512-aS3/DG0oM05K0RIXXP+hKjinGG5IgSSVGzswZxW3O0sS3pH4/fycXundUC9XsszgKCk4gHXylTEK6hyFxVxnoQ==} + '@types/node@24.19.2': + resolution: {integrity: sha512-93d49wCWJkCyN87MxLpNN6KXPCwFw7bVUg79mGUV1OS40JGWwVCr8n61DXCSqz7CV6/VfPkb7xec7uP2M+QHWQ==} '@types/npm-package-arg@6.1.4': resolution: {integrity: sha512-vDgdbMy2QXHnAruzlv68pUtXCjmqUk3WrBAsRboRovsOmxbfn/WiYCjmecyKjGztnMps5dWp4Uq2prp+Ilo17Q==} @@ -7020,10 +7017,6 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} - obug@2.2.1: - resolution: {integrity: sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==} - engines: {node: '>=12.20.0'} - obug@3.0.0: resolution: {integrity: sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==} engines: {node: '>=12.20.0'} @@ -8454,10 +8447,6 @@ packages: engines: {node: '>=22'} hasBin: true - verkit@0.3.2: - resolution: {integrity: sha512-zj/ob3UsvJGN0whEAKFp53REA5X66hvffVqoCtVQAakJKnKlH+/PcOfMoFwIG/o4rElqLv/ycAFlx8ZlXUorCg==} - engines: {node: '>=18.12.0'} - verkit@0.5.0: resolution: {integrity: sha512-u4J1hr6Y+C/hit34GwL3eIcUf3wngT8TlYUjK7tk0jxydKLAq3sYvifjdTDA6U3KCKRcQCQDGf/srjxfZF3l7g==} engines: {node: '>=18.12.0'} @@ -8865,31 +8854,31 @@ snapshots: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 - '@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))': + '@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))': dependencies: - '@angular/core': 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3) + '@angular/core': 22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3) tslib: 2.8.1 - '@angular/cdk@22.3.0-next.2(1e228ab395252fe57958c1335d3a301f)': + '@angular/cdk@22.3.0-next.2(e02572097466d520d7eb144e95d6bbd2)': dependencies: - '@angular/common': 22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) - '@angular/core': 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3) - '@angular/forms': 22.3.0-next.1(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2) - '@angular/platform-browser': 22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)) + '@angular/common': 22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) + '@angular/core': 22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3) + '@angular/forms': 22.3.0-next.2(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2) + '@angular/platform-browser': 22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)) parse5: 8.0.1 rxjs: 7.8.2 tslib: 2.8.1 - '@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2)': + '@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2)': dependencies: - '@angular/core': 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3) + '@angular/core': 22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3) rxjs: 7.8.2 tslib: 2.8.1 - '@angular/compiler-cli@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(typescript@6.0.3)': + '@angular/compiler-cli@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(typescript@6.0.3)': dependencies: - '@angular/compiler': 22.3.0-next.1 - '@babel/core': 8.0.6 + '@angular/compiler': 22.3.0-next.2 + '@babel/core': 8.0.7 '@jridgewell/sourcemap-codec': 1.6.0 chokidar: 5.0.0 convert-source-map: 1.9.0 @@ -8900,54 +8889,54 @@ snapshots: optionalDependencies: typescript: 6.0.3 - '@angular/compiler@22.3.0-next.1': + '@angular/compiler@22.3.0-next.2': dependencies: tslib: 2.8.1 - '@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)': + '@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)': dependencies: rxjs: 7.8.2 tslib: 2.8.1 optionalDependencies: - '@angular/compiler': 22.3.0-next.1 + '@angular/compiler': 22.3.0-next.2 zone.js: 0.16.3 - '@angular/forms@22.3.0-next.1(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2)': + '@angular/forms@22.3.0-next.2(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2)': dependencies: - '@angular/common': 22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) - '@angular/core': 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3) - '@angular/platform-browser': 22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)) + '@angular/common': 22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) + '@angular/core': 22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3) + '@angular/platform-browser': 22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)) '@standard-schema/spec': 1.1.0 rxjs: 7.8.2 tslib: 2.8.1 - zod: 4.6.5 + zod: 4.6.7 - '@angular/localize@22.3.0-next.1(@angular/compiler-cli@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(typescript@6.0.3))(@angular/compiler@22.3.0-next.1)': + '@angular/localize@22.3.0-next.2(@angular/compiler-cli@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(typescript@6.0.3))(@angular/compiler@22.3.0-next.2)': dependencies: - '@angular/compiler': 22.3.0-next.1 - '@angular/compiler-cli': 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(typescript@6.0.3) - '@babel/core': 8.0.6 + '@angular/compiler': 22.3.0-next.2 + '@angular/compiler-cli': 22.3.0-next.2(@angular/compiler@22.3.0-next.2)(typescript@6.0.3) + '@babel/core': 8.0.7 tinyglobby: 0.2.17 yargs: 18.2.0 - '@angular/material@22.3.0-next.2(1acbd77e3019024ea0df0dc9f59ed8c0)': + '@angular/material@22.3.0-next.2(4016851894464b4783f4f873310c276b)': dependencies: - '@angular/cdk': 22.3.0-next.2(1e228ab395252fe57958c1335d3a301f) - '@angular/common': 22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) - '@angular/core': 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3) - '@angular/forms': 22.3.0-next.1(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2) - '@angular/platform-browser': 22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)) + '@angular/cdk': 22.3.0-next.2(e02572097466d520d7eb144e95d6bbd2) + '@angular/common': 22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) + '@angular/core': 22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3) + '@angular/forms': 22.3.0-next.2(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2) + '@angular/platform-browser': 22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)) rxjs: 7.8.2 tslib: 2.8.1 - '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/fa4308affb4a0dde34ebc95196b58550752485a2': + '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/940c0beef0de4cb128e90962d47ff80e352a1cd8': dependencies: '@actions/core': 3.0.1 '@conventional-changelog/git-client': 3.2.0(conventional-commits-filter@6.0.1)(conventional-commits-parser@7.1.3) '@google-cloud/spanner': 8.0.0(supports-color@11.0.0) - '@google/genai': 2.28.0(bufferutil@4.1.0)(supports-color@11.0.0)(utf-8-validate@6.0.6) - '@inquirer/prompts': 8.7.3(@types/node@24.19.1) - '@inquirer/type': 4.2.0(@types/node@24.19.1) + '@google/genai': 2.29.1(bufferutil@4.1.0)(supports-color@11.0.0)(utf-8-validate@6.0.6) + '@inquirer/prompts': 8.7.3(@types/node@24.19.2) + '@inquirer/type': 4.2.0(@types/node@24.19.2) '@octokit/auth-app': 8.3.1 '@octokit/core': 7.0.8 '@octokit/graphql': 9.0.5 @@ -8961,7 +8950,7 @@ snapshots: '@types/events': 3.0.3 '@types/folder-hash': 4.0.4 '@types/jasmine': 6.0.0 - '@types/node': 24.19.1 + '@types/node': 24.19.2 '@types/semver': 7.8.0 '@types/which': 3.0.4 '@types/yargs': 17.0.35 @@ -8992,40 +8981,40 @@ snapshots: which: 7.0.0 yaml: 2.9.1 yargs: 18.2.0 - zod: 4.6.5 + zod: 4.6.7 transitivePeerDependencies: - '@modelcontextprotocol/sdk' - '@react-native-async-storage/async-storage' - '@angular/platform-browser@22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))': + '@angular/platform-browser@22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))': dependencies: - '@angular/common': 22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) - '@angular/core': 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3) + '@angular/common': 22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) + '@angular/core': 22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3) tslib: 2.8.1 optionalDependencies: - '@angular/animations': 22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)) + '@angular/animations': 22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)) - '@angular/platform-server@22.3.0-next.1(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/compiler@22.3.0-next.1)(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2)': + '@angular/platform-server@22.3.0-next.2(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/compiler@22.3.0-next.2)(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2)': dependencies: - '@angular/common': 22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) - '@angular/compiler': 22.3.0-next.1 - '@angular/core': 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3) - '@angular/platform-browser': 22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)) + '@angular/common': 22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) + '@angular/compiler': 22.3.0-next.2 + '@angular/core': 22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3) + '@angular/platform-browser': 22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)) rxjs: 7.8.2 tslib: 2.8.1 xhr2: 0.2.1 - '@angular/router@22.3.0-next.1(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2)': + '@angular/router@22.3.0-next.2(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(@angular/platform-browser@22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(rxjs@7.8.2)': dependencies: - '@angular/common': 22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) - '@angular/core': 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3) - '@angular/platform-browser': 22.3.0-next.1(@angular/animations@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3)) + '@angular/common': 22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2) + '@angular/core': 22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3) + '@angular/platform-browser': 22.3.0-next.2(@angular/animations@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)))(@angular/common@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2))(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3)) rxjs: 7.8.2 tslib: 2.8.1 - '@angular/service-worker@22.3.0-next.1(@angular/core@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2)': + '@angular/service-worker@22.3.0-next.2(@angular/core@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3))(rxjs@7.8.2)': dependencies: - '@angular/core': 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(rxjs@7.8.2)(zone.js@0.16.3) + '@angular/core': 22.3.0-next.2(@angular/compiler@22.3.0-next.2)(rxjs@7.8.2)(zone.js@0.16.3) rxjs: 7.8.2 tslib: 2.8.1 @@ -9079,25 +9068,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/core@8.0.6': - dependencies: - '@babel/code-frame': 8.0.6 - '@babel/generator': 8.0.6 - '@babel/helper-compilation-targets': 8.0.7 - '@babel/helpers': 8.0.7 - '@babel/parser': 8.0.7 - '@babel/template': 8.0.0 - '@babel/traverse': 8.0.7 - '@babel/types': 8.0.6 - '@types/gensync': 1.0.5 - convert-source-map: 2.0.0 - empathic: 2.1.0 - gensync: 1.0.0-beta.2 - import-meta-resolve: 4.2.0 - json5: 2.2.3 - obug: 2.2.1 - verkit: 0.3.2 - '@babel/core@8.0.7': dependencies: '@babel/code-frame': 8.0.6 @@ -10334,7 +10304,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@google/genai@2.28.0(bufferutil@4.1.0)(supports-color@11.0.0)(utf-8-validate@6.0.6)': + '@google/genai@2.29.1(bufferutil@4.1.0)(supports-color@11.0.0)(utf-8-validate@6.0.6)': dependencies: google-auth-library: 10.9.1(supports-color@11.0.0) p-retry: 4.6.2 @@ -10399,14 +10369,14 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/checkbox@5.2.6(@types/node@24.19.1)': + '@inquirer/checkbox@5.2.6(@types/node@24.19.2)': dependencies: '@inquirer/ansi': 2.0.9 - '@inquirer/core': 12.0.4(@types/node@24.19.1) + '@inquirer/core': 12.0.4(@types/node@24.19.2) '@inquirer/figures': 2.0.9 - '@inquirer/type': 4.2.0(@types/node@24.19.1) + '@inquirer/type': 4.2.0(@types/node@24.19.2) optionalDependencies: - '@types/node': 24.19.1 + '@types/node': 24.19.2 '@inquirer/confirm@6.3.3(@types/node@22.20.5)': dependencies: @@ -10415,12 +10385,12 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/confirm@6.3.3(@types/node@24.19.1)': + '@inquirer/confirm@6.3.3(@types/node@24.19.2)': dependencies: - '@inquirer/core': 12.0.4(@types/node@24.19.1) - '@inquirer/type': 4.2.0(@types/node@24.19.1) + '@inquirer/core': 12.0.4(@types/node@24.19.2) + '@inquirer/type': 4.2.0(@types/node@24.19.2) optionalDependencies: - '@types/node': 24.19.1 + '@types/node': 24.19.2 '@inquirer/core@12.0.4(@types/node@22.20.5)': dependencies: @@ -10434,17 +10404,17 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/core@12.0.4(@types/node@24.19.1)': + '@inquirer/core@12.0.4(@types/node@24.19.2)': dependencies: '@inquirer/ansi': 2.0.9 '@inquirer/figures': 2.0.9 - '@inquirer/type': 4.2.0(@types/node@24.19.1) + '@inquirer/type': 4.2.0(@types/node@24.19.2) cli-width: 4.1.0 fast-wrap-ansi: 0.2.2 mute-stream: 3.0.0 signal-exit: 4.1.0 optionalDependencies: - '@types/node': 24.19.1 + '@types/node': 24.19.2 '@inquirer/editor@5.3.4(@types/node@22.20.5)': dependencies: @@ -10454,13 +10424,13 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/editor@5.3.4(@types/node@24.19.1)': + '@inquirer/editor@5.3.4(@types/node@24.19.2)': dependencies: - '@inquirer/core': 12.0.4(@types/node@24.19.1) - '@inquirer/external-editor': 3.0.6(@types/node@24.19.1) - '@inquirer/type': 4.2.0(@types/node@24.19.1) + '@inquirer/core': 12.0.4(@types/node@24.19.2) + '@inquirer/external-editor': 3.0.6(@types/node@24.19.2) + '@inquirer/type': 4.2.0(@types/node@24.19.2) optionalDependencies: - '@types/node': 24.19.1 + '@types/node': 24.19.2 '@inquirer/expand@5.1.6(@types/node@22.20.5)': dependencies: @@ -10469,12 +10439,12 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/expand@5.1.6(@types/node@24.19.1)': + '@inquirer/expand@5.1.6(@types/node@24.19.2)': dependencies: - '@inquirer/core': 12.0.4(@types/node@24.19.1) - '@inquirer/type': 4.2.0(@types/node@24.19.1) + '@inquirer/core': 12.0.4(@types/node@24.19.2) + '@inquirer/type': 4.2.0(@types/node@24.19.2) optionalDependencies: - '@types/node': 24.19.1 + '@types/node': 24.19.2 '@inquirer/external-editor@3.0.6(@types/node@22.20.5)': dependencies: @@ -10483,12 +10453,12 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/external-editor@3.0.6(@types/node@24.19.1)': + '@inquirer/external-editor@3.0.6(@types/node@24.19.2)': dependencies: chardet: 2.2.0 iconv-lite: 0.7.3 optionalDependencies: - '@types/node': 24.19.1 + '@types/node': 24.19.2 '@inquirer/figures@2.0.9': {} @@ -10499,12 +10469,12 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/input@5.1.7(@types/node@24.19.1)': + '@inquirer/input@5.1.7(@types/node@24.19.2)': dependencies: - '@inquirer/core': 12.0.4(@types/node@24.19.1) - '@inquirer/type': 4.2.0(@types/node@24.19.1) + '@inquirer/core': 12.0.4(@types/node@24.19.2) + '@inquirer/type': 4.2.0(@types/node@24.19.2) optionalDependencies: - '@types/node': 24.19.1 + '@types/node': 24.19.2 '@inquirer/number@4.2.4(@types/node@22.20.5)': dependencies: @@ -10513,12 +10483,12 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/number@4.2.4(@types/node@24.19.1)': + '@inquirer/number@4.2.4(@types/node@24.19.2)': dependencies: - '@inquirer/core': 12.0.4(@types/node@24.19.1) - '@inquirer/type': 4.2.0(@types/node@24.19.1) + '@inquirer/core': 12.0.4(@types/node@24.19.2) + '@inquirer/type': 4.2.0(@types/node@24.19.2) optionalDependencies: - '@types/node': 24.19.1 + '@types/node': 24.19.2 '@inquirer/password@5.2.3(@types/node@22.20.5)': dependencies: @@ -10528,13 +10498,13 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/password@5.2.3(@types/node@24.19.1)': + '@inquirer/password@5.2.3(@types/node@24.19.2)': dependencies: '@inquirer/ansi': 2.0.9 - '@inquirer/core': 12.0.4(@types/node@24.19.1) - '@inquirer/type': 4.2.0(@types/node@24.19.1) + '@inquirer/core': 12.0.4(@types/node@24.19.2) + '@inquirer/type': 4.2.0(@types/node@24.19.2) optionalDependencies: - '@types/node': 24.19.1 + '@types/node': 24.19.2 '@inquirer/prompts@8.7.3(@types/node@22.20.5)': dependencies: @@ -10551,20 +10521,20 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/prompts@8.7.3(@types/node@24.19.1)': - dependencies: - '@inquirer/checkbox': 5.2.6(@types/node@24.19.1) - '@inquirer/confirm': 6.3.3(@types/node@24.19.1) - '@inquirer/editor': 5.3.4(@types/node@24.19.1) - '@inquirer/expand': 5.1.6(@types/node@24.19.1) - '@inquirer/input': 5.1.7(@types/node@24.19.1) - '@inquirer/number': 4.2.4(@types/node@24.19.1) - '@inquirer/password': 5.2.3(@types/node@24.19.1) - '@inquirer/rawlist': 5.3.6(@types/node@24.19.1) - '@inquirer/search': 4.3.4(@types/node@24.19.1) - '@inquirer/select': 5.2.6(@types/node@24.19.1) + '@inquirer/prompts@8.7.3(@types/node@24.19.2)': + dependencies: + '@inquirer/checkbox': 5.2.6(@types/node@24.19.2) + '@inquirer/confirm': 6.3.3(@types/node@24.19.2) + '@inquirer/editor': 5.3.4(@types/node@24.19.2) + '@inquirer/expand': 5.1.6(@types/node@24.19.2) + '@inquirer/input': 5.1.7(@types/node@24.19.2) + '@inquirer/number': 4.2.4(@types/node@24.19.2) + '@inquirer/password': 5.2.3(@types/node@24.19.2) + '@inquirer/rawlist': 5.3.6(@types/node@24.19.2) + '@inquirer/search': 4.3.4(@types/node@24.19.2) + '@inquirer/select': 5.2.6(@types/node@24.19.2) optionalDependencies: - '@types/node': 24.19.1 + '@types/node': 24.19.2 '@inquirer/rawlist@5.3.6(@types/node@22.20.5)': dependencies: @@ -10573,12 +10543,12 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/rawlist@5.3.6(@types/node@24.19.1)': + '@inquirer/rawlist@5.3.6(@types/node@24.19.2)': dependencies: - '@inquirer/core': 12.0.4(@types/node@24.19.1) - '@inquirer/type': 4.2.0(@types/node@24.19.1) + '@inquirer/core': 12.0.4(@types/node@24.19.2) + '@inquirer/type': 4.2.0(@types/node@24.19.2) optionalDependencies: - '@types/node': 24.19.1 + '@types/node': 24.19.2 '@inquirer/search@4.3.4(@types/node@22.20.5)': dependencies: @@ -10588,13 +10558,13 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/search@4.3.4(@types/node@24.19.1)': + '@inquirer/search@4.3.4(@types/node@24.19.2)': dependencies: - '@inquirer/core': 12.0.4(@types/node@24.19.1) + '@inquirer/core': 12.0.4(@types/node@24.19.2) '@inquirer/figures': 2.0.9 - '@inquirer/type': 4.2.0(@types/node@24.19.1) + '@inquirer/type': 4.2.0(@types/node@24.19.2) optionalDependencies: - '@types/node': 24.19.1 + '@types/node': 24.19.2 '@inquirer/select@5.2.6(@types/node@22.20.5)': dependencies: @@ -10605,22 +10575,22 @@ snapshots: optionalDependencies: '@types/node': 22.20.5 - '@inquirer/select@5.2.6(@types/node@24.19.1)': + '@inquirer/select@5.2.6(@types/node@24.19.2)': dependencies: '@inquirer/ansi': 2.0.9 - '@inquirer/core': 12.0.4(@types/node@24.19.1) + '@inquirer/core': 12.0.4(@types/node@24.19.2) '@inquirer/figures': 2.0.9 - '@inquirer/type': 4.2.0(@types/node@24.19.1) + '@inquirer/type': 4.2.0(@types/node@24.19.2) optionalDependencies: - '@types/node': 24.19.1 + '@types/node': 24.19.2 '@inquirer/type@4.2.0(@types/node@22.20.5)': optionalDependencies: '@types/node': 22.20.5 - '@inquirer/type@4.2.0(@types/node@24.19.1)': + '@inquirer/type@4.2.0(@types/node@24.19.2)': optionalDependencies: - '@types/node': 24.19.1 + '@types/node': 24.19.2 '@isaacs/cliui@8.0.2': dependencies: @@ -11744,7 +11714,7 @@ snapshots: dependencies: undici-types: 6.21.0 - '@types/node@24.19.1': + '@types/node@24.19.2': dependencies: undici-types: 7.24.6 @@ -15227,10 +15197,10 @@ snapshots: neo-async@2.6.2: {} - ng-packagr@22.3.0-next.2(@angular/compiler-cli@22.3.0-next.1(@angular/compiler@22.3.0-next.1)(typescript@6.0.3))(supports-color@11.0.0)(tslib@2.8.1)(typescript@6.0.3): + ng-packagr@22.3.0-next.2(@angular/compiler-cli@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(typescript@6.0.3))(supports-color@11.0.0)(tslib@2.8.1)(typescript@6.0.3): dependencies: '@ampproject/remapping': 2.3.0 - '@angular/compiler-cli': 22.3.0-next.1(@angular/compiler@22.3.0-next.1)(typescript@6.0.3) + '@angular/compiler-cli': 22.3.0-next.2(@angular/compiler@22.3.0-next.2)(typescript@6.0.3) ajv: 8.20.0 browserslist: 4.29.3 chokidar: 5.0.0 @@ -15359,8 +15329,6 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.2 - obug@2.2.1: {} - obug@3.0.0: {} on-exit-leak-free@2.1.2: {} @@ -17022,8 +16990,6 @@ snapshots: - react-native-b4a - supports-color - verkit@0.3.2: {} - verkit@0.5.0: {} verror@1.10.0: diff --git a/tests/e2e/ng-snapshot/package.json b/tests/e2e/ng-snapshot/package.json index 8550a3c4bb4c..e02c1dcd10e4 100644 --- a/tests/e2e/ng-snapshot/package.json +++ b/tests/e2e/ng-snapshot/package.json @@ -2,21 +2,21 @@ "description": "snapshot versions of Angular for e2e testing", "private": true, "dependencies": { - "@angular/animations": "github:angular/animations-builds#f2f4920079874bc3ff7233cae1bfc044f540aaea", - "@angular/cdk": "github:angular/cdk-builds#47633891913bba784f30c7e96a832ce5aee6b5ca", - "@angular/common": "github:angular/common-builds#50cb684a62ab0a76b5cac1f43e419dcef95695c5", - "@angular/compiler": "github:angular/compiler-builds#121ce74dc256084d4df6189faec0897906c81e7f", - "@angular/compiler-cli": "github:angular/compiler-cli-builds#13f5a3741ae88163e4830805d5fdb3be10975600", - "@angular/core": "github:angular/core-builds#803e8bc85644b8ae2f7626a2128b2597bad464f5", - "@angular/forms": "github:angular/forms-builds#dfc8f809fc98e7350bfb3c0cc4ed76c2f898e8a2", - "@angular/language-service": "github:angular/language-service-builds#26e3a3900301c3d6a9ab6a25567c1038e7a8556d", - "@angular/localize": "github:angular/localize-builds#152ad1e6420c1f2f6592f920c81e39dbcb5f5493", - "@angular/material": "github:angular/material-builds#e39e747aad22eb1ee2981f8f7b39a3b8ec788381", - "@angular/material-moment-adapter": "github:angular/material-moment-adapter-builds#f0e6679098e0bfdb8f98b2c7a2c271ec2d128994", - "@angular/platform-browser": "github:angular/platform-browser-builds#c87936c6c5381b369a60bcd311836c711b68d498", - "@angular/platform-browser-dynamic": "github:angular/platform-browser-dynamic-builds#abdac4b65aa34f8a1c9580631d22ae478579e111", - "@angular/platform-server": "github:angular/platform-server-builds#11bfbc1463ebaff83489b1b560ff49e9fb281fb1", - "@angular/router": "github:angular/router-builds#5457840c68f0afb075100b2d923de1219b450838", - "@angular/service-worker": "github:angular/service-worker-builds#94c8e94f4903c4271b9da3eedea9402e3af87043" + "@angular/animations": "github:angular/animations-builds#43efef5cbf38f5261191e5c11d7f49c276428137", + "@angular/cdk": "github:angular/cdk-builds#43c02174c1dc0f4b74a85342bbd9f43d040bf1ae", + "@angular/common": "github:angular/common-builds#89d9b5d43c81051c59a33d24ccccd75b51f6dc48", + "@angular/compiler": "github:angular/compiler-builds#e91181d83e7086debe8f32f21bfa434c4bd94afd", + "@angular/compiler-cli": "github:angular/compiler-cli-builds#bfd2191e1955c38a1ce52aa467508702d132e7ba", + "@angular/core": "github:angular/core-builds#31cf6f74f000a8499b3ce204ad9b339e830dcc39", + "@angular/forms": "github:angular/forms-builds#1dbb38cca305af00e3362cb59c5293b44a7ae7f1", + "@angular/language-service": "github:angular/language-service-builds#54ce2dee3572da8657674dc965d010fd37b6d15b", + "@angular/localize": "github:angular/localize-builds#bcdfcaf668fd983db3496cdb696ca8b3aa2f68aa", + "@angular/material": "github:angular/material-builds#2c82c94514f7cb2bc3dafd3b5db2160aa9c01517", + "@angular/material-moment-adapter": "github:angular/material-moment-adapter-builds#728a7be6d90391791e0967357a07959d2a4fa3d3", + "@angular/platform-browser": "github:angular/platform-browser-builds#a1b99915c2e91ab779ee0443904bd0194b8e2fb0", + "@angular/platform-browser-dynamic": "github:angular/platform-browser-dynamic-builds#cdfb691b31a234662977f12f0982b880035bb72e", + "@angular/platform-server": "github:angular/platform-server-builds#9e3f315c175ed493a83d91b2d1743582e4934ab3", + "@angular/router": "github:angular/router-builds#972a0d117fd048a478e2cb035ef5b442e8cc5ceb", + "@angular/service-worker": "github:angular/service-worker-builds#f3e0f7d39cadb10a0257cf826cc0519e7809e8e2" } } From d542827facd6e785ae6f7553624a22be5b577026 Mon Sep 17 00:00:00 2001 From: Angular Robot Date: Thu, 15 Oct 2026 16:34:00 +0000 Subject: [PATCH 44/52] build: update all non-major dependencies See associated pull request for more information. --- package.json | 8 +- packages/angular/build/package.json | 10 +- .../angular_devkit/build_angular/package.json | 4 +- packages/schematics/angular/package.json | 4 +- pnpm-lock.yaml | 870 ++++++++++-------- 5 files changed, 503 insertions(+), 393 deletions(-) diff --git a/package.json b/package.json index 6e4cab8c46dc..9bc88e433859 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "@rollup/plugin-commonjs": "^29.0.0", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "16.0.3", - "@rollup/wasm-node": "4.64.5", + "@rollup/wasm-node": "4.64.6", "@stylistic/eslint-plugin": "^5.0.0", "@tony.ganchev/eslint-plugin-header": "~3.4.0", "@types/babel__core": "7.20.5", @@ -119,15 +119,15 @@ "lodash": "^4.17.21", "magic-string": "1.4.3", "prettier": "^3.0.0", - "puppeteer": "25.13.0", + "puppeteer": "25.14.0", "quicktype-core": "26.0.0", - "rollup": "4.64.5", + "rollup": "4.64.6", "rollup-plugin-dts": "6.5.1", "rollup-plugin-sourcemaps2": "0.5.9", "semver": "7.8.5", "source-map-support": "0.5.21", "tslib": "2.8.1", - "undici": "8.11.2", + "undici": "8.12.1", "verdaccio": "6.10.5", "verdaccio-auth-memory": "^13.0.0", "zone.js": "^0.16.0" diff --git a/packages/angular/build/package.json b/packages/angular/build/package.json index a5227c45c526..711ab5893f75 100644 --- a/packages/angular/build/package.json +++ b/packages/angular/build/package.json @@ -33,11 +33,11 @@ "listr2": "11.2.0", "magic-string": "1.4.3", "mrmime": "2.0.1", - "oxc-parser": "0.153.0", + "oxc-parser": "0.154.0", "parse5-html-rewriting-stream": "8.0.1", "picomatch": "4.0.7", "piscina": "5.3.2", - "rolldown": "1.2.13", + "rolldown": "1.2.14", "rolldown-plugin-dts": "0.28.8", "sass": "1.105.1", "sass-embedded": "1.105.1", @@ -53,14 +53,14 @@ "devDependencies": { "@angular-devkit/core": "workspace:*", "@angular/ssr": "workspace:*", - "@oxc-project/types": "0.153.0", + "@oxc-project/types": "0.154.0", "@vitest/coverage-v8": "5.0.4", "istanbul-lib-instrument": "6.0.3", "jsdom": "30.1.2", "less": "4.9.1", "ng-packagr": "22.3.0-next.2", - "postcss": "8.5.29", - "rollup": "4.64.5", + "postcss": "8.5.30", + "rollup": "4.64.6", "rxjs": "7.8.2", "vitest": "5.0.4" }, diff --git a/packages/angular_devkit/build_angular/package.json b/packages/angular_devkit/build_angular/package.json index 502d27aa5975..54a44f134b16 100644 --- a/packages/angular_devkit/build_angular/package.json +++ b/packages/angular_devkit/build_angular/package.json @@ -43,7 +43,7 @@ "ora": "9.4.1", "picomatch": "4.0.7", "piscina": "5.3.2", - "postcss": "8.5.29", + "postcss": "8.5.30", "postcss-loader": "8.2.1", "resolve-url-loader": "5.0.0", "rxjs": "7.8.2", @@ -68,7 +68,7 @@ "browser-sync": "3.0.4", "ng-packagr": "22.3.0-next.2", "sass": "1.105.1", - "undici": "8.11.2" + "undici": "8.12.1" }, "peerDependencies": { "@angular/compiler-cli": "0.0.0-ANGULAR-FW-PEER-DEP", diff --git a/packages/schematics/angular/package.json b/packages/schematics/angular/package.json index 5d0cc7efef53..6025fad3bd99 100644 --- a/packages/schematics/angular/package.json +++ b/packages/schematics/angular/package.json @@ -20,10 +20,10 @@ "@angular-devkit/core": "workspace:0.0.0-PLACEHOLDER", "@angular-devkit/schematics": "workspace:0.0.0-PLACEHOLDER", "jsonc-parser": "3.3.1", - "oxc-parser": "0.153.0", + "oxc-parser": "0.154.0", "typescript": "6.0.3" }, "devDependencies": { - "@oxc-project/types": "0.153.0" + "@oxc-project/types": "0.154.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ff51f38b4f6c..81cbdf51aeb5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -245,16 +245,16 @@ importers: version: 10.0.1(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0)) '@rollup/plugin-commonjs': specifier: ^29.0.0 - version: 29.0.3(rollup@4.64.5) + version: 29.0.3(rollup@4.64.6) '@rollup/plugin-json': specifier: ^6.1.0 - version: 6.1.0(rollup@4.64.5) + version: 6.1.0(rollup@4.64.6) '@rollup/plugin-node-resolve': specifier: 16.0.3 - version: 16.0.3(rollup@4.64.5) + version: 16.0.3(rollup@4.64.6) '@rollup/wasm-node': - specifier: 4.64.5 - version: 4.64.5 + specifier: 4.64.6 + version: 4.64.6 '@stylistic/eslint-plugin': specifier: ^5.0.0 version: 5.10.0(eslint@10.12.0(jiti@2.7.0)(supports-color@11.0.0)) @@ -400,20 +400,20 @@ importers: specifier: ^3.0.0 version: 3.9.10 puppeteer: - specifier: 25.13.0 - version: 25.13.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + specifier: 25.14.0 + version: 25.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) quicktype-core: specifier: 26.0.0 version: 26.0.0 rollup: - specifier: 4.64.5 - version: 4.64.5 + specifier: 4.64.6 + version: 4.64.6 rollup-plugin-dts: specifier: 6.5.1 - version: 6.5.1(rollup@4.64.5)(typescript@6.0.3) + version: 6.5.1(rollup@4.64.6)(typescript@6.0.3) rollup-plugin-sourcemaps2: specifier: 0.5.9 - version: 0.5.9(@types/node@22.20.5)(rollup@4.64.5) + version: 0.5.9(@types/node@22.20.5)(rollup@4.64.6) semver: specifier: 7.8.5 version: 7.8.5 @@ -424,8 +424,8 @@ importers: specifier: 2.8.1 version: 2.8.1 undici: - specifier: 8.11.2 - version: 8.11.2 + specifier: 8.12.1 + version: 8.12.1 verdaccio: specifier: 6.10.5 version: 6.10.5(encoding@0.1.13)(supports-color@11.0.0) @@ -520,8 +520,8 @@ importers: specifier: 2.0.1 version: 2.0.1 oxc-parser: - specifier: 0.153.0 - version: 0.153.0 + specifier: 0.154.0 + version: 0.154.0 parse5-html-rewriting-stream: specifier: 8.0.1 version: 8.0.1 @@ -532,11 +532,11 @@ importers: specifier: 5.3.2 version: 5.3.2 rolldown: - specifier: 1.2.13 - version: 1.2.13 + specifier: 1.2.14 + version: 1.2.14 rolldown-plugin-dts: specifier: 0.28.8 - version: 0.28.8(rolldown@1.2.13)(typescript@6.0.3) + version: 0.28.8(rolldown@1.2.14)(typescript@6.0.3) sass: specifier: 1.105.1 version: 1.105.1 @@ -566,8 +566,8 @@ importers: specifier: workspace:* version: link:../ssr '@oxc-project/types': - specifier: 0.153.0 - version: 0.153.0 + specifier: 0.154.0 + version: 0.154.0 '@vitest/coverage-v8': specifier: 5.0.4 version: 5.0.4(vitest@5.0.4) @@ -584,11 +584,11 @@ importers: specifier: 22.3.0-next.2 version: 22.3.0-next.2(@angular/compiler-cli@22.3.0-next.2(@angular/compiler@22.3.0-next.2)(typescript@6.0.3))(supports-color@11.0.0)(tslib@2.8.1)(typescript@6.0.3) postcss: - specifier: 8.5.29 - version: 8.5.29 + specifier: 8.5.30 + version: 8.5.30 rollup: - specifier: 4.64.5 - version: 4.64.5 + specifier: 4.64.6 + version: 4.64.6 rxjs: specifier: 7.8.2 version: 7.8.2 @@ -755,10 +755,10 @@ importers: version: 4.1.3 autoprefixer: specifier: 10.6.1 - version: 10.6.1(postcss@8.5.29) + version: 10.6.1(postcss@8.5.30) babel-loader: specifier: 10.1.1 - version: 10.1.1(@babel/core@8.0.7)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)) + version: 10.1.1(@babel/core@8.0.7)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)) beasties: specifier: 0.5.5 version: 0.5.5 @@ -767,10 +767,10 @@ importers: version: 4.29.3 copy-webpack-plugin: specifier: 14.0.0 - version: 14.0.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)) + version: 14.0.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)) css-loader: specifier: 7.1.5 - version: 7.1.5(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)) + version: 7.1.5(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)) esbuild-wasm: specifier: 0.28.2 version: 0.28.2 @@ -791,16 +791,16 @@ importers: version: 4.9.1(supports-color@11.0.0) less-loader: specifier: 13.0.0 - version: 13.0.0(less@4.9.1(supports-color@11.0.0))(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)) + version: 13.0.0(less@4.9.1(supports-color@11.0.0))(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)) license-webpack-plugin: specifier: 4.0.2 - version: 4.0.2(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)) + version: 4.0.2(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)) loader-utils: specifier: 3.3.1 version: 3.3.1 mini-css-extract-plugin: specifier: 2.10.2 - version: 2.10.2(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)) + version: 2.10.2(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)) open: specifier: 11.0.4 version: 11.0.4 @@ -814,11 +814,11 @@ importers: specifier: 5.3.2 version: 5.3.2 postcss: - specifier: 8.5.29 - version: 8.5.29 + specifier: 8.5.30 + version: 8.5.30 postcss-loader: specifier: 8.2.1 - version: 8.2.1(postcss@8.5.29)(typescript@6.0.3)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)) + version: 8.2.1(postcss@8.5.30)(typescript@6.0.3)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)) resolve-url-loader: specifier: 5.0.0 version: 5.0.0 @@ -827,13 +827,13 @@ importers: version: 7.8.2 sass-loader: specifier: 17.0.1 - version: 17.0.1(sass-embedded@1.105.1)(sass@1.105.1)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)) + version: 17.0.1(sass-embedded@1.105.1)(sass@1.105.1)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)) semver: specifier: 7.8.5 version: 7.8.5 source-map-loader: specifier: 5.0.0 - version: 5.0.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)) + version: 5.0.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)) source-map-support: specifier: 0.5.21 version: 0.5.21 @@ -848,19 +848,19 @@ importers: version: 2.8.1 webpack: specifier: 5.111.1 - version: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3) + version: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3) webpack-dev-middleware: specifier: 8.3.0 - version: 8.3.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)) + version: 8.3.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)) webpack-dev-server: specifier: 6.0.0 - version: 6.0.0(bufferutil@4.1.0)(supports-color@11.0.0)(utf-8-validate@6.0.6)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)) + version: 6.0.0(bufferutil@4.1.0)(supports-color@11.0.0)(utf-8-validate@6.0.6)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)) webpack-merge: specifier: 6.0.1 version: 6.0.1 webpack-subresource-integrity: specifier: 5.1.0 - version: 5.1.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)) + version: 5.1.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)) devDependencies: '@angular/ssr': specifier: workspace:* @@ -875,8 +875,8 @@ importers: specifier: 1.105.1 version: 1.105.1 undici: - specifier: 8.11.2 - version: 8.11.2 + specifier: 8.12.1 + version: 8.12.1 optionalDependencies: esbuild: specifier: 0.28.2 @@ -989,15 +989,15 @@ importers: specifier: 3.3.1 version: 3.3.1 oxc-parser: - specifier: 0.153.0 - version: 0.153.0 + specifier: 0.154.0 + version: 0.154.0 typescript: specifier: 6.0.3 version: 6.0.3 devDependencies: '@oxc-project/types': - specifier: 0.153.0 - version: 0.153.0 + specifier: 0.154.0 + version: 0.154.0 tests: devDependencies: @@ -2971,124 +2971,124 @@ packages: resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} engines: {node: '>=14'} - '@oxc-parser/binding-android-arm-eabi@0.153.0': - resolution: {integrity: sha512-BcWu25dMwMjHpaDCEidmpAi7rGg1qZoihJeUUH9bD55pVZ0z4Wa5CQgqSTo0R41H81oozisQKW3WqvAN2m77IQ==} + '@oxc-parser/binding-android-arm-eabi@0.154.0': + resolution: {integrity: sha512-sDdEtDl7vKdCvf54j72RJbowE3jCmyRz/+oOB6IAwQxAHZ0eI+Dcj4hvVnm0b9Dy31plUkdmfds9C+/Zt895Tg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxc-parser/binding-android-arm64@0.153.0': - resolution: {integrity: sha512-9l5rdp2DhRqVriBHsNpu5cEf+hizZ4B58rt93HzyQEBUgZiC6qe2oFpaAAnXGCxHGnQExI1s7S2G0QhFacUZ6w==} + '@oxc-parser/binding-android-arm64@0.154.0': + resolution: {integrity: sha512-UHrDPELzvWZoVkIDdSycj4bzcTMCJG3IbN++mSUgVBaUtNtWHjQ98U6Vz5bpF/1Ic3FYJyYhMr74huO5tVvpZw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxc-parser/binding-darwin-arm64@0.153.0': - resolution: {integrity: sha512-EcpsyRXHhENDpekpG4QNaSZj2F/BAz4Gh4o89zZwNss86R8KyRSQ6sXbAj74Xyeb4z3j/yBZZ6joQZhraIWyfw==} + '@oxc-parser/binding-darwin-arm64@0.154.0': + resolution: {integrity: sha512-mokYzajOSXxtSRDWCdHARGdntrKH+rZZ24Jzo8AtafyNzz0NARmpMm26Tc5B6qiGrr6UliWibHCOif1qRN2vaA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxc-parser/binding-darwin-x64@0.153.0': - resolution: {integrity: sha512-hlj80HUQy07/2lYp6rmxH+3u+H2ik3rjLR52CUdPApxmZCNxASDUf/+ykTzAHS/fehftmVMATKvPaWmuLHuasg==} + '@oxc-parser/binding-darwin-x64@0.154.0': + resolution: {integrity: sha512-WbtUBrclOVItWfLRSvs+Z/WLtXxJ2Ctv50PyuX894HzDN5/e0qzxVpTNPIVMzOerBhgKtFsSMcfxlYIAbvdVgg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxc-parser/binding-freebsd-x64@0.153.0': - resolution: {integrity: sha512-fWRcv2pMSh1qtez46MOu8vuUJ5fiaQZPHSphbWulbL7SHBMKfRgZl2PzjXZYQJbq7NEXyXbgIuIuUm+/Rmkv8w==} + '@oxc-parser/binding-freebsd-x64@0.154.0': + resolution: {integrity: sha512-YooHZSLawOe2fqm+lDdG8oAaQh2NYV/RMYTYzWRLy72stm2BgE9O/8Al6kFENjkmzyyBccDLLBirGxVtpzQfrw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxc-parser/binding-linux-arm-gnueabihf@0.153.0': - resolution: {integrity: sha512-paZeUK1GXShl/bOJQET1/8AQxayFeuN4SIWAkgTRxE7ZQwv9uYSB2n0648smygP22N7jcI3zxAm0Z+ALNiIKxg==} + '@oxc-parser/binding-linux-arm-gnueabihf@0.154.0': + resolution: {integrity: sha512-hKOwhZbrXdTwc4bGVfbLCXl9f2swl6zWdISocLQSNX9MgPmwHE3qGzOUkCrkuGpwdCVHPnkfOwsqTuYsrP5uNg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxc-parser/binding-linux-arm-musleabihf@0.153.0': - resolution: {integrity: sha512-qFPp5NwMf4K1C0O+DCVGmcbOaYyYAq98Rvv9p4VSfb777iUwlJCqMUxf6QG9N5f5ls4TEX6LitOZHi+6GL6rYQ==} + '@oxc-parser/binding-linux-arm-musleabihf@0.154.0': + resolution: {integrity: sha512-tnjiooXEU013349O/yxKbF5Cusp1CfHWQ8kYR8tGeRzR/P4sOpQGQo21fsS71M0fMD6ESLq+lbvXFWi43PuKeQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxc-parser/binding-linux-arm64-gnu@0.153.0': - resolution: {integrity: sha512-oufEhZCX7saeo27Logra8cvBR1jQ/yw2zUI2hHmWw3qA/XYqEW31FOvLQBv7DWN32NjVdlcaP11WBBZTJo4k9g==} + '@oxc-parser/binding-linux-arm64-gnu@0.154.0': + resolution: {integrity: sha512-Cao2kj+8d7BT6XJU1gV9eVQjV+Cr+e8vQm3tddDRZiM2hHrMDxwy3j6t+ofaSl0idyuPPCZ4AlpmQoj8yOT1QA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-arm64-musl@0.153.0': - resolution: {integrity: sha512-zXYzuAqng85h6+LI3iRm0zeMLX1/K2z41ZAMWxVRgt0D10VvZUaV5q+TEB46KDhoKBpdexoTLC6QoB/EiP2oqQ==} + '@oxc-parser/binding-linux-arm64-musl@0.154.0': + resolution: {integrity: sha512-uiwA0V3q8llWA7/8r+a9BBjk4j5YMDmi6wfOsyQfGOJMQSLHEiZ3HI8ulea766ykUa9wJFWk9XWEl4uJrZLQqw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxc-parser/binding-linux-ppc64-gnu@0.153.0': - resolution: {integrity: sha512-J7+NLwLEzdkKM9cKyPHH/AjXXstWOs98KYgLrPPnO4N9MO8EZRBfPNnBcS3S67uMOBkRpUmCl2FhRnWdQ5CbBA==} + '@oxc-parser/binding-linux-ppc64-gnu@0.154.0': + resolution: {integrity: sha512-LICfN0Xs4Zdko+bJy6eOAEQojDuIR26suF2JtOsMaXjgbCrpRSH7/NCvJhY13YvYBx12V6hnwrL8n0lk0rbNJQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-riscv64-gnu@0.153.0': - resolution: {integrity: sha512-sD0K11GQTLWylln54nPMMTtgmBbQrR5It/vMpZpy/fogiw8O2AvIE+9LuWUXddrWk9zvFIHGRcSgFn4IHOfoYg==} + '@oxc-parser/binding-linux-riscv64-gnu@0.154.0': + resolution: {integrity: sha512-gbbSYxLF8ssRbQ2qQPy+2EhGNwNH1bAoRdkk6cnWaKHqmCikpSIPtpXjFbCCtjTi0uojqOM3ghFQwQPbDQsU0Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-riscv64-musl@0.153.0': - resolution: {integrity: sha512-7L66uql2BhvSz51LwfExjOdn6et/ydTiQxl23VApdKzJhTc3TczA1Qt6VR/UcvlQrL2ZbytIJb447vh7p5wmUw==} + '@oxc-parser/binding-linux-riscv64-musl@0.154.0': + resolution: {integrity: sha512-nSnRYYDLCcRVjSQzF3g6rKqCNYwo5o+aQgnn8BBXfe+ofCgMGlGqkfRyvXm6ptZvoxNkkWtLlqM8W7Xc3j6ZnQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxc-parser/binding-linux-s390x-gnu@0.153.0': - resolution: {integrity: sha512-hXV3T7mNyrPR19rbPYkglkQJtoM/UNo/xwbZeeqdAxEg8PXgb4LXXuxPpGgI4bzRRCWwLUxdDSS58xIyC2u1TA==} + '@oxc-parser/binding-linux-s390x-gnu@0.154.0': + resolution: {integrity: sha512-BxBQoJKtzRQgZEKQIt6CDUm8RGKC5T8Qo4576yDa5/xgc10X3fBDItMbRabzLtbUBfTqKLl+8AVr/H6CF7W22g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-x64-gnu@0.153.0': - resolution: {integrity: sha512-Da8Vqs1xdtoDYtEjmozD7wGgJeLBQkMbR0WUBECOSxodyX5DXy8ySlvJWbukyO2Q0+TM9EK+4LT6tbq0jCg4hQ==} + '@oxc-parser/binding-linux-x64-gnu@0.154.0': + resolution: {integrity: sha512-/whkust2vYy+GjRUVL5cWaJmEu6jkdFfo5mkxgckyeOX61eMwo4iBoiwzeJZeMWAdzb/XOtQyLApHhFht3sOWA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-x64-musl@0.153.0': - resolution: {integrity: sha512-zGAPxNTIIw6X5WyTRscIFE/oDjpdNtrrl32ing6NOXdGjzRucadnxBilexLdeYQ9YxixF93GujpXyQ0jw7ddSg==} + '@oxc-parser/binding-linux-x64-musl@0.154.0': + resolution: {integrity: sha512-EXURTyW9riw4B/kZnnE+58emAtw6+3VEszQfXUZkRqGaKIcmWDYkZtKB+xY/blHvuZ+Qy/fDclc31nmUCgtkSA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxc-parser/binding-openharmony-arm64@0.153.0': - resolution: {integrity: sha512-GoHzpqP5XyPIp9DHokoEdCp+K4UPl/h1neFj1uXnUB3pJYyOQ7NOhFVOttNUgCGcj2eywAvu5cRivTOSq4S10g==} + '@oxc-parser/binding-openharmony-arm64@0.154.0': + resolution: {integrity: sha512-ZRFooyH3qsR6vuR4jFGlG3XM36490SvvXtNaUahBK4zHpooMdTHNaOMtGGJI0EW38m5hi4rOco9kw7ZwCIp28w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxc-parser/binding-win32-arm64-msvc@0.153.0': - resolution: {integrity: sha512-xGcy12tO9k7zFbeyQzEuilfWfQpyRq23/fLPfN3wjSWuWv58k46fQT1hsO1KFNykZuVGW9xSJE/z592TmAoSDA==} + '@oxc-parser/binding-win32-arm64-msvc@0.154.0': + resolution: {integrity: sha512-U0Vp+4lvwUa/PnOCJTZOjydj1rX2+VLHz4Y2vSFqlN8/7LTiURgD7z4uQ9yNv9O/NlU3mELBnPDlu7aaSYG1zQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxc-parser/binding-win32-ia32-msvc@0.153.0': - resolution: {integrity: sha512-o1ykUjWncvXX6N5a4KebgLjtD8zRui+f1llMhSGoSC9oP2KOqapRpdwmZ3NcNG0axFouwVKmhGBjd+IhA8BksA==} + '@oxc-parser/binding-win32-ia32-msvc@0.154.0': + resolution: {integrity: sha512-Hc8QgsFY5eUUP25we8TISUruibG2cDt0H4IcPG9RKdabb6odkCzIqjV6Gk9beGWGuOwMVCr81H/Su1q363LCCg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxc-parser/binding-win32-x64-msvc@0.153.0': - resolution: {integrity: sha512-gxQz7G96Up136fd+2zWrP+o6FYGs9NO4Dyv55IoeJFJUDwLFHcLYY11hhA5wQKs0HoM57Q8esQ3nEVhnCdsjAQ==} + '@oxc-parser/binding-win32-x64-msvc@0.154.0': + resolution: {integrity: sha512-hD7judkUMA/hZPoamvKADs6+an1smp8UTK0aMYRijkvi00K/1vl7vEtmyn2JyQ9S+vibtnfcNzxqTLGyJUZCRQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -3096,8 +3096,8 @@ packages: '@oxc-project/types@0.152.0': resolution: {integrity: sha512-oM/5rLBm2tPkg0iBgkH/FOeR3PCDpY19GTgAZjMFM8h9WI9VW7cLgzp6nwtarYKmovavIQZ+Fe/RKX/8C8O/Rw==} - '@oxc-project/types@0.153.0': - resolution: {integrity: sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw==} + '@oxc-project/types@0.154.0': + resolution: {integrity: sha512-KYOUGQFlLWR+s4QMV2Q9ko38TZm7EdO87Qm7rvZLqk/webse/cDjtyxKhg/47l0byCbs/k46LT8qc4PKjAikzA==} '@parcel/watcher-android-arm64@2.6.0': resolution: {integrity: sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==} @@ -3262,8 +3262,8 @@ packages: '@protobufjs/utf8@1.1.2': resolution: {integrity: sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==} - '@puppeteer/browsers@3.2.4': - resolution: {integrity: sha512-okJ6yQMc0SBexOKxMi966omwAV1uAPwgF/YMZdb04gZQPXVjWHl9bmXjZYtIcsN1+PN3Bz4iFfGK3g+c6lZJ0Q==} + '@puppeteer/browsers@3.2.5': + resolution: {integrity: sha512-UoCo3Pynbm37aLEEoydSiG+t24ui7sLD40+07CKxzxNy4PpSowJMkvlLIiV67XjP1lMVynhQVnuwlTABqBH8LQ==} engines: {node: '>=22.12.0'} hasBin: true peerDependencies: @@ -3281,8 +3281,8 @@ packages: cpu: [arm] os: [android] - '@rolldown/binding-android-arm-eabi@1.2.13': - resolution: {integrity: sha512-Vu/NICrgdRvUOeaJZIyB2FP63s6fO/4ud5l8dXmxDx9yDyn+mN0y+gsvsVviSli+T361Aqo0h46EuMoobrwawA==} + '@rolldown/binding-android-arm-eabi@1.2.14': + resolution: {integrity: sha512-aWR+XKH9+rW7m5fWq/5360J3mHycrx/o6xZM2DQFdJnTMdyP7/WzxPjhtLbVWdKo2y612/4U1bWqb3HQhiF7vg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] @@ -3293,8 +3293,8 @@ packages: cpu: [arm64] os: [android] - '@rolldown/binding-android-arm64@1.2.13': - resolution: {integrity: sha512-6LEoIrGy5vvCd2boNnv2soPSUZj/PRvhp8R/t9KlX+mIZxThIE/ZqxrGXxmuNX0FuvQFvLdZr7S4HrYpYBVhEQ==} + '@rolldown/binding-android-arm64@1.2.14': + resolution: {integrity: sha512-QiVxHofl6A8lQU7WAtOUY4QMVZXohxwz7WJJoeh8NBEUyKfIkMRKhYyq8az/1RypNiIXzNTtiS6KwHz0erxYRQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] @@ -3305,8 +3305,8 @@ packages: cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-arm64@1.2.13': - resolution: {integrity: sha512-CaJSRzlQ6Q+zkDMVA9OkVxBjVoPRCDEE3v0FSJ9kIQBgRjFApA3Si4ijhbNVUji7ZJt+PfO0e46qy4nPInHUPA==} + '@rolldown/binding-darwin-arm64@1.2.14': + resolution: {integrity: sha512-lTQOzHuBIooh3jIr5XINQkjPGEuGy+Dsy0meXDr6Sjty0b99kYgGh4uBC/8mJX1T0kC8d6S0aPP1Y+bHkh6aBw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] @@ -3317,8 +3317,8 @@ packages: cpu: [x64] os: [darwin] - '@rolldown/binding-darwin-x64@1.2.13': - resolution: {integrity: sha512-e4r340I5hxSzJkD3YJBxgzq/rJ3wwxwdLLb2FPt1Zpyem20nrQPT11DDEEkazwxaHumH8wpglsp/Ozgj/wT6mw==} + '@rolldown/binding-darwin-x64@1.2.14': + resolution: {integrity: sha512-hyMKEGatjmBYCs/Q4sbIcL/GqpFEqsX3wc+HYVQ/85A4rxc1o7rPm4DUI4GV4k/h0ITddwFSGpqQunI14GXjTA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] @@ -3329,8 +3329,8 @@ packages: cpu: [x64] os: [freebsd] - '@rolldown/binding-freebsd-x64@1.2.13': - resolution: {integrity: sha512-hoBWDZ4/K/mJKVMbsgUd1jfpA2DiOrJ54mpegObU9TBHBBrtX4FLIXJJQRDPZ/2Dn91GvPob+Z2hwKJzf4E5SQ==} + '@rolldown/binding-freebsd-x64@1.2.14': + resolution: {integrity: sha512-u371GbXoVXrEgP20PwzoGNOdAOqAMhzo19JzzY+V4YmmnC+DTOoqdbMu+O+54emM59Mik/UdrtWgcuEDKWRPKA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] @@ -3341,8 +3341,8 @@ packages: cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm-gnueabihf@1.2.13': - resolution: {integrity: sha512-oF9fZu3vTWnTiVAkDFxU9PJLt1nh20K9RRpuHsR7ZnE2L7XookBbDBVLojCVSLGbvtSlxeUNnjAj6DbNsKyzbg==} + '@rolldown/binding-linux-arm-gnueabihf@1.2.14': + resolution: {integrity: sha512-BqwKsdZQf6EqVWr8fv2MrDYzAvOZ7+NYFSJESRGs87fkseEhs0TU9TXgRJTkZoRRkxTizyEg1LKUXfU3/78uqg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] @@ -3354,8 +3354,8 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-gnu@1.2.13': - resolution: {integrity: sha512-DTpb/+jMiqWMPgphn4ksW1zW+XLJ6dJJ9FMvnIk9I291LhCctMPhMYJrP5t9p6C9qa3KXadDdUEZHBaPh3kNxQ==} + '@rolldown/binding-linux-arm64-gnu@1.2.14': + resolution: {integrity: sha512-SD9kY8M009x/7s57Z1dgUVlP5+uYBgKQK0Tkr1WIWngrtUJmRCW1RJFMY7QDla2khXhmg2i5Io7MUjcmZNZ/KQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] @@ -3368,8 +3368,8 @@ packages: os: [linux] libc: [musl] - '@rolldown/binding-linux-arm64-musl@1.2.13': - resolution: {integrity: sha512-xU+Kvv9N2A3SY35zFh1FWWNjxbadE/BKeqnkXe7vScU4GZsw757BlVmDLITZEq8DPpk6m7uoDYkK7P+x/uU5Ow==} + '@rolldown/binding-linux-arm64-musl@1.2.14': + resolution: {integrity: sha512-BJ2CL19M6uuWesMgnqJzgxoI+N+eV7b0A9O9vLV42y+gitC41fNa8KElau1tHVzuLWX5GzEuxMPhAO0tQXQMkg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] @@ -3382,8 +3382,8 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-ppc64-gnu@1.2.13': - resolution: {integrity: sha512-XMk/hnhh25oQ756Lclb1Q11h4ll0xC0Esa5w4Vzp+mAE2S3AGJgeM0SonrIgY8fHhjarb6hcoTuwoFG0VVP2ig==} + '@rolldown/binding-linux-ppc64-gnu@1.2.14': + resolution: {integrity: sha512-4+Kl8daPV8NDHaD7mfCcc1pRM+Qg7ab8DyMm5FG5WoZgv4h2i3KFN1CybYBNbQqmuYm7ftJLvmMI1eHYJ22S/Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] @@ -3396,8 +3396,8 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.2.13': - resolution: {integrity: sha512-U1BoTHYmlywE2n3HUWjzZ+8EQsKr+OwpxYuDWaubx42tUL8QSL7nOqRz/NVHanibbFP3M1Rxuprz/wNcbMKjqw==} + '@rolldown/binding-linux-s390x-gnu@1.2.14': + resolution: {integrity: sha512-V/h8ePq1fKDrmtFMz6xcCN3DKvuvMRrwwD1q0PkBeeo4DpK64biaKvqWGVxqCeYKqeRk7gE7/iKPxLCn08O97A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] @@ -3410,8 +3410,8 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.2.13': - resolution: {integrity: sha512-J4cm80Pc6wEwV5AZ42o62sIQgDk+Y7R2s646jIwuvO+4V46QB58N4vVuMPWCBaNgursXLpmUWJV//WQAkPvHBQ==} + '@rolldown/binding-linux-x64-gnu@1.2.14': + resolution: {integrity: sha512-WxalXzgrLVpKC93xfpaJ3gCXUWzeCr+FRCbDVD2mUAy4L6Vo3lNVz0epUEUpxPWJkLNYUwM4OSIikv36OJ9mLg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] @@ -3424,8 +3424,8 @@ packages: os: [linux] libc: [musl] - '@rolldown/binding-linux-x64-musl@1.2.13': - resolution: {integrity: sha512-W0euZS40U4V6JkmEnVCIX9mcsL6cbXQ4X8c2w+MMOIjFg68TXUW+u3RT+2e1t1pv9mg/EP3pDtK3POXdQ7Rxyw==} + '@rolldown/binding-linux-x64-musl@1.2.14': + resolution: {integrity: sha512-3G3tnAmTpdk9jO3GQtyHXqeFD2SlecfTws/Y3M2mmj9nMBwwuLT4kur8sZKeu7ENUHSpVO3cIsm5A52LEWWwlg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] @@ -3437,8 +3437,8 @@ packages: cpu: [arm64] os: [openharmony] - '@rolldown/binding-openharmony-arm64@1.2.13': - resolution: {integrity: sha512-do/AF/4n9MRshia3a5aXoy8xM2c6mgfT6D7H/dY6my5z+hfCIR4ab7mk4IRj++nsEQpKy39kd0DQnDq+r692tw==} + '@rolldown/binding-openharmony-arm64@1.2.14': + resolution: {integrity: sha512-qyr5XiNGxm2ytx17vvtcJ9nXn6v1gENETi503bJx3OGwZ1tSonj7BosxbMa/xeAfSl5iS9X6KjEWYXLu6v1L7Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] @@ -3449,8 +3449,8 @@ packages: cpu: [arm64] os: [win32] - '@rolldown/binding-win32-arm64-msvc@1.2.13': - resolution: {integrity: sha512-6FtUf2cJZobutJdxnGYX8z0vtbgqU0b2v8vfBhkXb9wp2MppMFtkunE+IaOntyi01rkIQoPW2GHABtfzsC0BRQ==} + '@rolldown/binding-win32-arm64-msvc@1.2.14': + resolution: {integrity: sha512-oA4o5o0S2yB199YyYXDzKUv1Z56Rc+mgOjwm7Z/vJ9Z8igiDPYvoOuDyo6g7AK/ZaF09nPhDKVnGBcYHO11GXA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] @@ -3461,8 +3461,8 @@ packages: cpu: [x64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.2.13': - resolution: {integrity: sha512-UKhFaZTeTcbKrb3iU82m17jVcPEAoqDkCN5MBqgPyZSwp/cQmib21crTS0DdH7T1B7wZRWEI89YQAOJMet5yhg==} + '@rolldown/binding-win32-x64-msvc@1.2.14': + resolution: {integrity: sha512-9mE94bf2GZUaR/fUSXCMpBoWkctu421Mi0ORpm4zqfbkjKep7RxzPFa5etcGs5h+2KApoWBOA/hAJa/7saGgEQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -3506,146 +3506,146 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.64.5': - resolution: {integrity: sha512-MrfgRQSpD5hkkRg6XI16B6EDLb+6+xp8xje6bpdSwkYw+qxrBKbUVrRAQu9h82UT+QumSIVQ8HXsXjPd2dlhqw==} + '@rollup/rollup-android-arm-eabi@4.64.6': + resolution: {integrity: sha512-FkO19Fowv/OQeJZPVfdetJaI3/VpbZmBsnmAlR/rQ+b3QwfiGQiOpVegpSRH331kelvHTVw9hXYG3DwjAaRzyQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.64.5': - resolution: {integrity: sha512-+uu2p/R9Tzn8GpoQyX1pAo5dmKT1DhXevfaCzqzmPFhnLjHLWw7uWkaVGlxmhwYoRiYYhsGfRcD5cTBpL7rgSw==} + '@rollup/rollup-android-arm64@4.64.6': + resolution: {integrity: sha512-si5/Etm6MphPc2xYHnk455Shls/hoMjTy3mhXge4OPmvCw7TwC4KP4fKokAlKLV4XaQvLvgSHfafPcblLMYYdQ==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.64.5': - resolution: {integrity: sha512-17dys+YEmzwzzFVHQAVDONg5FALXY9kd99HFEpfk4gJVHYxoh5bGea3D4t1fXXnwkTcOe25wPyd6nWS0I8IdLQ==} + '@rollup/rollup-darwin-arm64@4.64.6': + resolution: {integrity: sha512-PQCl3q7b0BgvVt72i2xrWM6I5KliwwVe4GpWW5QDGyUQawDS9aPZss/aGyFqBmxdRxlE8wDc9CaxiQ5DHRSp/Q==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.64.5': - resolution: {integrity: sha512-wg0zQEKkEvFZf1UaaX1UELOoPs//OSKUG7D+yITuqOsAvza7LvHTv5Wu4nmMfzNG7EYI2jp2PJC7Id6OETmsYQ==} + '@rollup/rollup-darwin-x64@4.64.6': + resolution: {integrity: sha512-l9DFl1Itb1YYdSrP1K3U8ih44AOHa/p+Q4WMMDfGvH5qVWp+ajfgS1DlYo4yCRh8wJ2ZJv0Fqccf+ULAmMFjmg==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.64.5': - resolution: {integrity: sha512-CoJmWcpEMuwin+TZ/ev/H9uDyF/uxUKQSWXdmIPn/UBx/uGV9+4ebMp0FwnlhWR9PE1AdzYsKf3bZevhif38+A==} + '@rollup/rollup-freebsd-arm64@4.64.6': + resolution: {integrity: sha512-bR4GR3205N9+od0+l5Dd9/iZTDpJkIe6d6Ydp2qbcQZJLmKBdYQQRp8gbWpbMt92twKJY66o1vK4NkoKQODIrA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.64.5': - resolution: {integrity: sha512-PxZnLAaTUAL5xG0W2BXLeYPKrK2b3LIASV2/e/Kf7PZvSLI1iAQIm9B9aJD+YyFIT7hc6qaMV3+OOO35R28LfA==} + '@rollup/rollup-freebsd-x64@4.64.6': + resolution: {integrity: sha512-XTVNaDzcFl2TeBglvxdGgsCv9JGtAGRAoJENmGBR/XvDH2mA2K0IXc2aMfP0dR8mexSXSKifJ85FixoXX1wfTw==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.64.5': - resolution: {integrity: sha512-uPo3IvnONjhbFXwWgroBeFwOicuhT7ZwQrnzkzmOtBJzeQbkUJUE1SJDfDI31ijQ5+ZUIA6sPrdUMxTSnxUWAg==} + '@rollup/rollup-linux-arm-gnueabihf@4.64.6': + resolution: {integrity: sha512-qWc6qbc+25ugG9vqPR9P422KJBbVfZ05mjcMggoq8tsfWP+eRfC+/tiDdIlRF5VL2pDVZWN9zAhWsmu7R1+7Dw==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.64.5': - resolution: {integrity: sha512-ywI8Jyuc4LyHYTjC0mw4yA1ulvZBkHusdpWnoiEBsmBuHvSnt90btTBGCZ+s/2y+YNNfVAEKy33nPo5UI9zTmg==} + '@rollup/rollup-linux-arm-musleabihf@4.64.6': + resolution: {integrity: sha512-V4Nwkp8844X/Xnww3PI1LYS0YPei8XQEVG70R+5MPZGO7AhYoun4hCN7Svs4U3wbQLZbwiz+9xRFhUZZdRl8Ww==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.64.5': - resolution: {integrity: sha512-tmuXJoQ/3ovSr637aykZMdQteU/CB2APAz2CrvsbibuoHZi1BS1Db13cVViBdEARGwXCLn1DSJ8wsjoThLJPGA==} + '@rollup/rollup-linux-arm64-gnu@4.64.6': + resolution: {integrity: sha512-xb72A1aPaaIsp+a88VtRae/ovIEXislbUMyp7b9AQQU7ZkP2m/+ik6DW9TQcJyw5R8/RIailF9zExYwkjR++UA==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.64.5': - resolution: {integrity: sha512-5FMjSYNcUOHx7oW8Qu9KB6jGPpvF/8sG7+BDHwU/Ihh1/6FMJ9ySmsFG4tJ1qbNRuP8OLzCBDso4sF0mQaLuFQ==} + '@rollup/rollup-linux-arm64-musl@4.64.6': + resolution: {integrity: sha512-pbcs1BVBwC43hZkjhjlF8Rx8m5G0KnhLZs9Azy/gqccP6UsNSzJr0hKGIAVPqzAH1O/NdPxxC9GVGb4msQg/aw==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.64.5': - resolution: {integrity: sha512-K8ZJ+neLDbUkIrL8dqF/5LtuVCrKwo27kREgOlxjBEjlOXwHvDnHLU8Z/UKv/B49qi7e8hsSDOyoJwhwqhvX4w==} + '@rollup/rollup-linux-loong64-gnu@4.64.6': + resolution: {integrity: sha512-EKOC8os6Vsg487ZLKUqzLF99Jsmnq6tu7O7mAELakNpcA+8KadktFf/JYdRuHe/DzCUXmN38pUKu4XBcKlqGbQ==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.64.5': - resolution: {integrity: sha512-NlVxsq7PFPv0DBKGuNWRDKixQYQCjM53zl04mxEcKMBmJbCBIUm1JdPfIWDRHyOOFzzYPmLQzfeEwh4716ayQg==} + '@rollup/rollup-linux-loong64-musl@4.64.6': + resolution: {integrity: sha512-v/SQ68GnSlr/HyjB79sNXesGDwkOPu9JjbHfmWaymCiM+nZsQ9TstG1KfA4MuEvTr2d3PoY8PhFxj9bt0e32JA==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.64.5': - resolution: {integrity: sha512-ARhRHJYs5eCFet5azfrHD97vOkD8OzNW2RSMlvo5CcBqXaTOLfp0OHDtUQh7/K5AL5fUYoFp2fgC9KDg4vVYMQ==} + '@rollup/rollup-linux-ppc64-gnu@4.64.6': + resolution: {integrity: sha512-G3pmliMQ7r15zFFNwBlaT/xTdSLi4lfgI7CUrQueyKYheNVhrd8JrWCE6Ll8xf4AA1RZFqq+mNJYntiElsVOyA==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.64.5': - resolution: {integrity: sha512-atSgreM5C7jpxd9aEXN+6vJ5wTd05iYw+S3FiQpw7VsoEl8B90llbq35ARON+GOHj5QlVQEq2vOKWCHTob/BSQ==} + '@rollup/rollup-linux-ppc64-musl@4.64.6': + resolution: {integrity: sha512-XQTB/IPoB/wG6x/wu9uomAt8YH61IAr5iZTubMiad/lu88sotq2ocz9hJd556+Jz2kIkF7ZQZIsUuWE3OWqtcA==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.64.5': - resolution: {integrity: sha512-vmlmwBFGnjVWxSRoVabNkyYuscSmg52Pd0fM8jEbNT3Jmka4A6HcB84x4uAmuumznWfBVaxKOqU6jbEgomWKCA==} + '@rollup/rollup-linux-riscv64-gnu@4.64.6': + resolution: {integrity: sha512-O5mpokth6+ydMuwiGtY8fIjvOBfH7u6SzmDNmZ3k6GK5C6iEAC2q2ZN/T5L9jYILx0IcCT0KnfMDihQ5yQFSBw==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.64.5': - resolution: {integrity: sha512-hhJrP6S9WkbsbcHgUkvCBS5Cn8IdsG8XjlLZyxjnv9+NdoYfbbZE4TWJYr8apdaj1M5t5Y1id2StnEslxpNFyA==} + '@rollup/rollup-linux-riscv64-musl@4.64.6': + resolution: {integrity: sha512-aIFxbAD9v3TvIaEDsKmukjcDg1JS4/tFXw8SHyQQgzOwzWCQ4cyDK7Ju1pQKqUXDFkEu/BZCFDCDATsKhQcB/Q==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.64.5': - resolution: {integrity: sha512-NNVCyN9pGrwFmQa4bf+Cnf5aVH3g6ZpnlOg1Cs/H9swIHT9bRixijfzUqyEIWm1WtiAuR1LJ+rJH6zpBm8kgQA==} + '@rollup/rollup-linux-s390x-gnu@4.64.6': + resolution: {integrity: sha512-fuNo1UwBc6BxnHDOxxguQL/InhheMN3RJcJMb0b4xP8r5Q3CNCrJbVg0eCIFuJ4e/zAfjR2gYbOfbzO/G7CIyw==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.64.5': - resolution: {integrity: sha512-dR9nd6OKnvSS60Ifz/L7Mj5zzYyoqyRn2NwTuaOONKaa3xsVGXyp8YusMbvFyEOR94DxnwgcbgsFqkHd29ZSzQ==} + '@rollup/rollup-linux-x64-gnu@4.64.6': + resolution: {integrity: sha512-05v6wFKDKJPZs9xlytVrrRu6IbRuoSvlH9xNwEOafXsKyjBFZPvAcZz2VIAB/M+lblYeKa9iOYC4RDVdfcAAaw==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.64.5': - resolution: {integrity: sha512-1tzsMjaqhsh3bAO6SJiJqh8hIr9sSPRd+i2vPPxJHod8/XYnf9TEnK0z/u3r1z1AkI347X0KbRSg9dWcxeGahw==} + '@rollup/rollup-linux-x64-musl@4.64.6': + resolution: {integrity: sha512-wJXKcdMjvkc/FaavZXNP1yW4i0pfOmhZAIWRSLG2yJ0PB0TWi7dkLErhX0u0vptDcXKKO/m1Y/YTeuyvb2MXwg==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.64.5': - resolution: {integrity: sha512-01mWMQblKoXXsmk28KXtpbA96w7g/aOWUoV3AC16fdHdqkykGalqyyM+5u8M7uP5/MEMiiPv69Hv7iv/hEH/dA==} + '@rollup/rollup-openbsd-x64@4.64.6': + resolution: {integrity: sha512-cwg7/h0ThvJwy8CBkmACdiHAxRWpbsCmIsjOt+Zzx0hTnIcSUmKYEV03bGg+hD827OnwUsbKh1ZZDW754xWyBA==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.64.5': - resolution: {integrity: sha512-trdnMPb/DNm4V/CgsaoGgr90HfQQ071wfK0KoIs4YpLvjBgVQGXhGabg2Z6nK4EcYNilrb9ZZPcsP6+zpJIdxQ==} + '@rollup/rollup-openharmony-arm64@4.64.6': + resolution: {integrity: sha512-T0RkYIJbdYXJEQFw+tMBO09KDFdgmNxkHsof3wWAABrvnx15Yh8RytmrgYy9+q9cBeBNZF66MMQZC+5nzEz6vg==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.64.5': - resolution: {integrity: sha512-x2LxZlfdfsw99T6/qb9EqE/Qi84JWzibjyOJyhJsgFJy6CafaTiqIXCCnslCGrV5XWNh7fwrS3FbRENcuKnooA==} + '@rollup/rollup-win32-arm64-msvc@4.64.6': + resolution: {integrity: sha512-KlfpmF1AAIdAWxt8QQNClbpLFlAUfYOzqIuJ7IXEStMHpFRuH78RG6FjqPb3Rqhh0K89F5npvG+/i3Fjl6IveQ==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.64.5': - resolution: {integrity: sha512-/Qd/9aDQIo0+jmItgBmPIs8195YVbDxRRApn47GyufgbutCDOh7eP5vSKKlI4QNFeaI+wKQAkSMsPnF3EuMpaA==} + '@rollup/rollup-win32-ia32-msvc@4.64.6': + resolution: {integrity: sha512-MrTLjd7Jlt9/ZavJZYG61KQv9Iy9bzbY+yXy73Xvwoa2uP66wvDShkyBr5Chz/yrE6lbD/zHMuTmKQVNQqBApg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.64.5': - resolution: {integrity: sha512-ngUJ/XvOWrqbd2IMsfXfh2xXFLTP3sY7sCKvxbGvYdBZ1KmXFd3ewDZ9n3/GNzAUgzRuhLT/UvJRivbNoAQRBw==} + '@rollup/rollup-win32-x64-gnu@4.64.6': + resolution: {integrity: sha512-8fWDH1CkPI8GdBKAxzHDza7UmgficsKo2+MVbvUgOGhB0629w5sHMg3Qu5y7TZsrYKHHWpz8fla4KvoT7WsO3Q==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.64.5': - resolution: {integrity: sha512-IhV6ew/DuzUWwHaYmlh7MrPCV3lKFUq/amTEwysi4r/mwNPAEfAMh5dYWeTSPTeMy2pFHGMEWYtPkHzfX3tG5A==} + '@rollup/rollup-win32-x64-msvc@4.64.6': + resolution: {integrity: sha512-9/c9PWdr5GCIHkkxiHM1HjNBQMVdftP4O8QTcoUAaRza2FSqJ4axbf8QAnBuE6BIGQDl71SaRPeDdDYid5ecTw==} cpu: [x64] os: [win32] - '@rollup/wasm-node@4.64.5': - resolution: {integrity: sha512-kN33cPixKuDMgrYkRnkAW7iwiDWzRhNUgVY+IpcniQNXuIvDAAv0cFgZsaLEFP1z8eqVGhKG13dy5hFN3yBy+g==} + '@rollup/wasm-node@4.64.6': + resolution: {integrity: sha512-ufelhiGxNl8RuflC/Tie5ZVcI3MJUtd27nJ0jC2I4LroyZb7n4iwmajEmXXeTLxJtDiiWUwU8v2UjkACBHqQvw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -7070,8 +7070,8 @@ packages: resolution: {integrity: sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==} engines: {node: '>= 0.4'} - oxc-parser@0.153.0: - resolution: {integrity: sha512-cEnpyyV1OJRXv++SFNw0z8i+2o/cr88rVLaOYJafELDoHM5yHvCAbwGRLvxuany6SNLcbblSMUyZaGzH+quSYg==} + oxc-parser@0.154.0: + resolution: {integrity: sha512-Gr/6fkjZwi937c4Tsz8y0iO4U0FLPkZI6JSVucLAIvQyqh379px7RS8ORIc0HOORbFjXZ6zyqWLl53qxhSeofw==} engines: {node: ^20.19.0 || >=22.12.0} p-finally@1.0.0: @@ -7281,6 +7281,10 @@ packages: resolution: {integrity: sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.30: + resolution: {integrity: sha512-zkd+e9S1AQHhmaBKye9zlFHWjOwVgqXl1q3ECYy8561K7qxR2cREf/STLskulBFd78k6AOFeA+ff1TtEzk9bAA==} + engines: {node: ^10 || ^12 || >=14} + powershell-utils@0.2.1: resolution: {integrity: sha512-C+y9x90UElAddDZmV4qOx9W53B61PO7cIqWz2dQsWlwswuq4mr8NEwytdGKboYbQlGZ3awrkTeNvcZiZNHnQ8A==} engines: {node: '>=20'} @@ -7351,12 +7355,12 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - puppeteer-core@25.13.0: - resolution: {integrity: sha512-cyBS0OEx3e9NS53B5F6+UazXtR7f9Tw0cR1/FbPW59/hV6JPZbkIiMnxK2543IkFp3rsGlLn1iPDLF77TJsJsA==} + puppeteer-core@25.14.0: + resolution: {integrity: sha512-LQitnes3tBeVbdZ7V/4iwJPLZGgkl9uBVK0W7YYMh68j/3Y9eNuvj4yl+Fdo7zN0SuajOMrhd7aPj3DifK8k6A==} engines: {node: '>=22.12.0'} - puppeteer@25.13.0: - resolution: {integrity: sha512-vB4KLXTT5QqlikcOQ/xV0RY18bBVtNyLUTfqJ9mW+penHyoM+5DmANYuDCI4jgBtiL0eD9I5ZFSafW6/a6Trpg==} + puppeteer@25.14.0: + resolution: {integrity: sha512-+s1Iqbl9DsGLOaQdgCQyhtgHZsF9hi4Iu8iuBqxzraxUXoRG1QkYQI0CA1/VsNK1gZWJfs50BL/oOb1L+Yz8Yg==} engines: {node: '>=22.12.0'} hasBin: true @@ -7595,8 +7599,8 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rolldown@1.2.13: - resolution: {integrity: sha512-/5apOkwWxtACcQtZ5WlrAsKS4JwXVThQPJZ3RqIruRY9UG9M8e0VlXN068xum/JRKA4aIUoJ13ghe/kGCvidiQ==} + rolldown@1.2.14: + resolution: {integrity: sha512-eTBTTqMR6uHKLgcUqpJP8ntzDI6V4LYA8negAMBEI7gkgVvOdrx6VsvS2Ym+83KhOPdLCHWJu0w7UQFJZhHKNw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -7621,8 +7625,8 @@ packages: '@types/node': optional: true - rollup@4.64.5: - resolution: {integrity: sha512-EAP5ZHcz2ijbgCWwPkpI7zh6bfsri2Ez5FtCy2dCp1k62duXzfG7DLGGh7RU2QQXWwavT+u4qpvDF/TWOiiGTw==} + rollup@4.64.6: + resolution: {integrity: sha512-fX1Vy+UNKdXn+xKDnu/HBXbHVr1AY8cSdQj9BU4kLv5aFCMqGpvrVbyUMmjN3DdzWhSAuTbcX8PCNEVaumthYA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -8350,6 +8354,10 @@ packages: resolution: {integrity: sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ==} engines: {node: '>=22.19.0'} + undici@8.12.1: + resolution: {integrity: sha512-usz3OVQBeh1LxNn0DzU0voLXMgn5CU/WUdpBsY6Ti5afNao+vTkmn4H/NxoXolc10cOqe2+YIG0Hspq2rsl64w==} + engines: {node: '>=22.19.0'} + unicode-canonical-property-names-ecmascript@2.0.1: resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} engines: {node: '>=4'} @@ -11073,66 +11081,66 @@ snapshots: '@opentelemetry/semantic-conventions@1.43.0': {} - '@oxc-parser/binding-android-arm-eabi@0.153.0': + '@oxc-parser/binding-android-arm-eabi@0.154.0': optional: true - '@oxc-parser/binding-android-arm64@0.153.0': + '@oxc-parser/binding-android-arm64@0.154.0': optional: true - '@oxc-parser/binding-darwin-arm64@0.153.0': + '@oxc-parser/binding-darwin-arm64@0.154.0': optional: true - '@oxc-parser/binding-darwin-x64@0.153.0': + '@oxc-parser/binding-darwin-x64@0.154.0': optional: true - '@oxc-parser/binding-freebsd-x64@0.153.0': + '@oxc-parser/binding-freebsd-x64@0.154.0': optional: true - '@oxc-parser/binding-linux-arm-gnueabihf@0.153.0': + '@oxc-parser/binding-linux-arm-gnueabihf@0.154.0': optional: true - '@oxc-parser/binding-linux-arm-musleabihf@0.153.0': + '@oxc-parser/binding-linux-arm-musleabihf@0.154.0': optional: true - '@oxc-parser/binding-linux-arm64-gnu@0.153.0': + '@oxc-parser/binding-linux-arm64-gnu@0.154.0': optional: true - '@oxc-parser/binding-linux-arm64-musl@0.153.0': + '@oxc-parser/binding-linux-arm64-musl@0.154.0': optional: true - '@oxc-parser/binding-linux-ppc64-gnu@0.153.0': + '@oxc-parser/binding-linux-ppc64-gnu@0.154.0': optional: true - '@oxc-parser/binding-linux-riscv64-gnu@0.153.0': + '@oxc-parser/binding-linux-riscv64-gnu@0.154.0': optional: true - '@oxc-parser/binding-linux-riscv64-musl@0.153.0': + '@oxc-parser/binding-linux-riscv64-musl@0.154.0': optional: true - '@oxc-parser/binding-linux-s390x-gnu@0.153.0': + '@oxc-parser/binding-linux-s390x-gnu@0.154.0': optional: true - '@oxc-parser/binding-linux-x64-gnu@0.153.0': + '@oxc-parser/binding-linux-x64-gnu@0.154.0': optional: true - '@oxc-parser/binding-linux-x64-musl@0.153.0': + '@oxc-parser/binding-linux-x64-musl@0.154.0': optional: true - '@oxc-parser/binding-openharmony-arm64@0.153.0': + '@oxc-parser/binding-openharmony-arm64@0.154.0': optional: true - '@oxc-parser/binding-win32-arm64-msvc@0.153.0': + '@oxc-parser/binding-win32-arm64-msvc@0.154.0': optional: true - '@oxc-parser/binding-win32-ia32-msvc@0.153.0': + '@oxc-parser/binding-win32-ia32-msvc@0.154.0': optional: true - '@oxc-parser/binding-win32-x64-msvc@0.153.0': + '@oxc-parser/binding-win32-x64-msvc@0.154.0': optional: true '@oxc-project/types@0.152.0': {} - '@oxc-project/types@0.153.0': {} + '@oxc-project/types@0.154.0': {} '@parcel/watcher-android-arm64@2.6.0': optional: true @@ -11309,7 +11317,7 @@ snapshots: '@protobufjs/utf8@1.1.2': {} - '@puppeteer/browsers@3.2.4': + '@puppeteer/browsers@3.2.5': dependencies: modern-tar: 0.8.5 yargs: 18.2.0 @@ -11317,98 +11325,98 @@ snapshots: '@rolldown/binding-android-arm-eabi@1.2.12': optional: true - '@rolldown/binding-android-arm-eabi@1.2.13': + '@rolldown/binding-android-arm-eabi@1.2.14': optional: true '@rolldown/binding-android-arm64@1.2.12': optional: true - '@rolldown/binding-android-arm64@1.2.13': + '@rolldown/binding-android-arm64@1.2.14': optional: true '@rolldown/binding-darwin-arm64@1.2.12': optional: true - '@rolldown/binding-darwin-arm64@1.2.13': + '@rolldown/binding-darwin-arm64@1.2.14': optional: true '@rolldown/binding-darwin-x64@1.2.12': optional: true - '@rolldown/binding-darwin-x64@1.2.13': + '@rolldown/binding-darwin-x64@1.2.14': optional: true '@rolldown/binding-freebsd-x64@1.2.12': optional: true - '@rolldown/binding-freebsd-x64@1.2.13': + '@rolldown/binding-freebsd-x64@1.2.14': optional: true '@rolldown/binding-linux-arm-gnueabihf@1.2.12': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.2.13': + '@rolldown/binding-linux-arm-gnueabihf@1.2.14': optional: true '@rolldown/binding-linux-arm64-gnu@1.2.12': optional: true - '@rolldown/binding-linux-arm64-gnu@1.2.13': + '@rolldown/binding-linux-arm64-gnu@1.2.14': optional: true '@rolldown/binding-linux-arm64-musl@1.2.12': optional: true - '@rolldown/binding-linux-arm64-musl@1.2.13': + '@rolldown/binding-linux-arm64-musl@1.2.14': optional: true '@rolldown/binding-linux-ppc64-gnu@1.2.12': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.2.13': + '@rolldown/binding-linux-ppc64-gnu@1.2.14': optional: true '@rolldown/binding-linux-s390x-gnu@1.2.12': optional: true - '@rolldown/binding-linux-s390x-gnu@1.2.13': + '@rolldown/binding-linux-s390x-gnu@1.2.14': optional: true '@rolldown/binding-linux-x64-gnu@1.2.12': optional: true - '@rolldown/binding-linux-x64-gnu@1.2.13': + '@rolldown/binding-linux-x64-gnu@1.2.14': optional: true '@rolldown/binding-linux-x64-musl@1.2.12': optional: true - '@rolldown/binding-linux-x64-musl@1.2.13': + '@rolldown/binding-linux-x64-musl@1.2.14': optional: true '@rolldown/binding-openharmony-arm64@1.2.12': optional: true - '@rolldown/binding-openharmony-arm64@1.2.13': + '@rolldown/binding-openharmony-arm64@1.2.14': optional: true '@rolldown/binding-win32-arm64-msvc@1.2.12': optional: true - '@rolldown/binding-win32-arm64-msvc@1.2.13': + '@rolldown/binding-win32-arm64-msvc@1.2.14': optional: true '@rolldown/binding-win32-x64-msvc@1.2.12': optional: true - '@rolldown/binding-win32-x64-msvc@1.2.13': + '@rolldown/binding-win32-x64-msvc@1.2.14': optional: true '@rolldown/pluginutils@1.0.1': {} - '@rollup/plugin-commonjs@29.0.3(rollup@4.64.5)': + '@rollup/plugin-commonjs@29.0.3(rollup@4.64.6)': dependencies: - '@rollup/pluginutils': 5.4.0(rollup@4.64.5) + '@rollup/pluginutils': 5.4.0(rollup@4.64.6) commondir: 1.0.1 estree-walker: 2.0.2 fdir: 6.5.0(picomatch@4.0.7) @@ -11416,108 +11424,108 @@ snapshots: magic-string: 0.30.21 picomatch: 4.0.7 optionalDependencies: - rollup: 4.64.5 + rollup: 4.64.6 - '@rollup/plugin-json@6.1.0(rollup@4.64.5)': + '@rollup/plugin-json@6.1.0(rollup@4.64.6)': dependencies: - '@rollup/pluginutils': 5.4.0(rollup@4.64.5) + '@rollup/pluginutils': 5.4.0(rollup@4.64.6) optionalDependencies: - rollup: 4.64.5 + rollup: 4.64.6 - '@rollup/plugin-node-resolve@16.0.3(rollup@4.64.5)': + '@rollup/plugin-node-resolve@16.0.3(rollup@4.64.6)': dependencies: - '@rollup/pluginutils': 5.4.0(rollup@4.64.5) + '@rollup/pluginutils': 5.4.0(rollup@4.64.6) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.13 optionalDependencies: - rollup: 4.64.5 + rollup: 4.64.6 - '@rollup/pluginutils@5.4.0(rollup@4.64.5)': + '@rollup/pluginutils@5.4.0(rollup@4.64.6)': dependencies: '@types/estree': 1.0.9 estree-walker: 2.0.2 picomatch: 4.0.7 optionalDependencies: - rollup: 4.64.5 + rollup: 4.64.6 - '@rollup/rollup-android-arm-eabi@4.64.5': + '@rollup/rollup-android-arm-eabi@4.64.6': optional: true - '@rollup/rollup-android-arm64@4.64.5': + '@rollup/rollup-android-arm64@4.64.6': optional: true - '@rollup/rollup-darwin-arm64@4.64.5': + '@rollup/rollup-darwin-arm64@4.64.6': optional: true - '@rollup/rollup-darwin-x64@4.64.5': + '@rollup/rollup-darwin-x64@4.64.6': optional: true - '@rollup/rollup-freebsd-arm64@4.64.5': + '@rollup/rollup-freebsd-arm64@4.64.6': optional: true - '@rollup/rollup-freebsd-x64@4.64.5': + '@rollup/rollup-freebsd-x64@4.64.6': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.64.5': + '@rollup/rollup-linux-arm-gnueabihf@4.64.6': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.64.5': + '@rollup/rollup-linux-arm-musleabihf@4.64.6': optional: true - '@rollup/rollup-linux-arm64-gnu@4.64.5': + '@rollup/rollup-linux-arm64-gnu@4.64.6': optional: true - '@rollup/rollup-linux-arm64-musl@4.64.5': + '@rollup/rollup-linux-arm64-musl@4.64.6': optional: true - '@rollup/rollup-linux-loong64-gnu@4.64.5': + '@rollup/rollup-linux-loong64-gnu@4.64.6': optional: true - '@rollup/rollup-linux-loong64-musl@4.64.5': + '@rollup/rollup-linux-loong64-musl@4.64.6': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.64.5': + '@rollup/rollup-linux-ppc64-gnu@4.64.6': optional: true - '@rollup/rollup-linux-ppc64-musl@4.64.5': + '@rollup/rollup-linux-ppc64-musl@4.64.6': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.64.5': + '@rollup/rollup-linux-riscv64-gnu@4.64.6': optional: true - '@rollup/rollup-linux-riscv64-musl@4.64.5': + '@rollup/rollup-linux-riscv64-musl@4.64.6': optional: true - '@rollup/rollup-linux-s390x-gnu@4.64.5': + '@rollup/rollup-linux-s390x-gnu@4.64.6': optional: true - '@rollup/rollup-linux-x64-gnu@4.64.5': + '@rollup/rollup-linux-x64-gnu@4.64.6': optional: true - '@rollup/rollup-linux-x64-musl@4.64.5': + '@rollup/rollup-linux-x64-musl@4.64.6': optional: true - '@rollup/rollup-openbsd-x64@4.64.5': + '@rollup/rollup-openbsd-x64@4.64.6': optional: true - '@rollup/rollup-openharmony-arm64@4.64.5': + '@rollup/rollup-openharmony-arm64@4.64.6': optional: true - '@rollup/rollup-win32-arm64-msvc@4.64.5': + '@rollup/rollup-win32-arm64-msvc@4.64.6': optional: true - '@rollup/rollup-win32-ia32-msvc@4.64.5': + '@rollup/rollup-win32-ia32-msvc@4.64.6': optional: true - '@rollup/rollup-win32-x64-gnu@4.64.5': + '@rollup/rollup-win32-x64-gnu@4.64.6': optional: true - '@rollup/rollup-win32-x64-msvc@4.64.5': + '@rollup/rollup-win32-x64-msvc@4.64.6': optional: true - '@rollup/wasm-node@4.64.5': + '@rollup/wasm-node@4.64.6': dependencies: '@types/estree': 1.0.9 optionalDependencies: @@ -11682,7 +11690,7 @@ snapshots: '@types/loader-utils@3.0.0(esbuild@0.28.2)(lightningcss@1.33.0)(uglify-js@3.19.3)': dependencies: '@types/node': 22.20.5 - webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3) + webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3) transitivePeerDependencies: - '@minify-html/node' - '@napi-rs/image' @@ -12459,13 +12467,13 @@ snapshots: atomic-sleep@1.0.0: {} - autoprefixer@10.6.1(postcss@8.5.29): + autoprefixer@10.6.1(postcss@8.5.30): dependencies: browserslist: 4.29.3 caniuse-lite: 1.0.30001815 fraction.js: 5.3.4 picocolors: 1.1.1 - postcss: 8.5.29 + postcss: 8.5.30 postcss-value-parser: 4.2.0 available-typed-arrays@1.0.7: @@ -12478,12 +12486,12 @@ snapshots: b4a@1.9.0: {} - babel-loader@10.1.1(@babel/core@8.0.7)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)): + babel-loader@10.1.1(@babel/core@8.0.7)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)): dependencies: '@babel/core': 8.0.7 find-up: 5.0.0 optionalDependencies: - webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3) + webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3) babel-plugin-polyfill-corejs3@1.0.0(@babel/core@8.0.7): dependencies: @@ -12544,9 +12552,9 @@ snapshots: domhandler: 6.0.1 htmlparser2: 12.0.0 picocolors: 1.1.1 - postcss: 8.5.29 + postcss: 8.5.30 postcss-media-query-parser: 0.2.3 - postcss-safe-parser: 7.1.0(postcss@8.5.29) + postcss-safe-parser: 7.1.0(postcss@8.5.30) before-after-hook@4.0.0: {} @@ -12796,7 +12804,7 @@ snapshots: dependencies: devtools-protocol: 0.0.1696802 mitt: 3.0.1 - zod: 4.6.5 + zod: 4.6.7 chunk-data@0.1.0: {} @@ -12959,14 +12967,14 @@ snapshots: dependencies: is-what: 4.1.16 - copy-webpack-plugin@14.0.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)): + copy-webpack-plugin@14.0.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)): dependencies: glob-parent: 6.0.2 normalize-path: 3.0.0 schema-utils: 4.5.0 serialize-javascript: 7.1.2 tinyglobby: 0.2.17 - webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3) + webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3) core-js-compat@3.50.0: dependencies: @@ -12996,18 +13004,18 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - css-loader@7.1.5(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)): + css-loader@7.1.5(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)): dependencies: - icss-utils: 5.1.0(postcss@8.5.29) - postcss: 8.5.29 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.29) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.29) - postcss-modules-scope: 3.2.1(postcss@8.5.29) - postcss-modules-values: 4.0.0(postcss@8.5.29) + icss-utils: 5.1.0(postcss@8.5.30) + postcss: 8.5.30 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.30) + postcss-modules-local-by-default: 4.2.0(postcss@8.5.30) + postcss-modules-scope: 3.2.1(postcss@8.5.30) + postcss-modules-values: 4.0.0(postcss@8.5.30) postcss-value-parser: 4.2.0 semver: 7.8.5 optionalDependencies: - webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3) + webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3) css-select@7.0.0: dependencies: @@ -14296,9 +14304,9 @@ snapshots: dependencies: safer-buffer: 2.1.2 - icss-utils@5.1.0(postcss@8.5.29): + icss-utils@5.1.0(postcss@8.5.30): dependencies: - postcss: 8.5.29 + postcss: 8.5.30 idb@7.1.1: {} @@ -14795,12 +14803,12 @@ snapshots: picocolors: 1.1.1 shell-quote: 1.12.0 - less-loader@13.0.0(less@4.9.1(supports-color@11.0.0))(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)): + less-loader@13.0.0(less@4.9.1(supports-color@11.0.0))(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)): dependencies: '@types/less': 3.0.8 less: 4.9.1(supports-color@11.0.0) optionalDependencies: - webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3) + webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3) less@4.9.1(supports-color@11.0.0): dependencies: @@ -14822,11 +14830,11 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - license-webpack-plugin@4.0.2(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)): + license-webpack-plugin@4.0.2(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)): dependencies: webpack-sources: 3.6.0 optionalDependencies: - webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3) + webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3) lightningcss-android-arm64@1.33.0: optional: true @@ -15081,11 +15089,11 @@ snapshots: mimic-response@4.0.0: {} - mini-css-extract-plugin@2.10.2(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)): + mini-css-extract-plugin@2.10.2(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)): dependencies: schema-utils: 4.5.0 tapable: 2.3.3 - webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3) + webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3) minimatch@10.2.6: dependencies: @@ -15118,6 +15126,19 @@ snapshots: postcss: 8.5.29 uglify-js: 3.19.3 + minimizer-webpack-plugin@5.13.0(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)): + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + jest-worker: 27.5.1 + schema-utils: 4.5.0 + terser: 5.51.2 + webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3) + optionalDependencies: + esbuild: 0.28.2 + lightningcss: 1.33.0 + postcss: 8.5.30 + uglify-js: 3.19.3 + minipass@7.1.3: {} mitt@1.2.0: {} @@ -15396,29 +15417,29 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 - oxc-parser@0.153.0: + oxc-parser@0.154.0: dependencies: - '@oxc-project/types': 0.153.0 + '@oxc-project/types': 0.154.0 optionalDependencies: - '@oxc-parser/binding-android-arm-eabi': 0.153.0 - '@oxc-parser/binding-android-arm64': 0.153.0 - '@oxc-parser/binding-darwin-arm64': 0.153.0 - '@oxc-parser/binding-darwin-x64': 0.153.0 - '@oxc-parser/binding-freebsd-x64': 0.153.0 - '@oxc-parser/binding-linux-arm-gnueabihf': 0.153.0 - '@oxc-parser/binding-linux-arm-musleabihf': 0.153.0 - '@oxc-parser/binding-linux-arm64-gnu': 0.153.0 - '@oxc-parser/binding-linux-arm64-musl': 0.153.0 - '@oxc-parser/binding-linux-ppc64-gnu': 0.153.0 - '@oxc-parser/binding-linux-riscv64-gnu': 0.153.0 - '@oxc-parser/binding-linux-riscv64-musl': 0.153.0 - '@oxc-parser/binding-linux-s390x-gnu': 0.153.0 - '@oxc-parser/binding-linux-x64-gnu': 0.153.0 - '@oxc-parser/binding-linux-x64-musl': 0.153.0 - '@oxc-parser/binding-openharmony-arm64': 0.153.0 - '@oxc-parser/binding-win32-arm64-msvc': 0.153.0 - '@oxc-parser/binding-win32-ia32-msvc': 0.153.0 - '@oxc-parser/binding-win32-x64-msvc': 0.153.0 + '@oxc-parser/binding-android-arm-eabi': 0.154.0 + '@oxc-parser/binding-android-arm64': 0.154.0 + '@oxc-parser/binding-darwin-arm64': 0.154.0 + '@oxc-parser/binding-darwin-x64': 0.154.0 + '@oxc-parser/binding-freebsd-x64': 0.154.0 + '@oxc-parser/binding-linux-arm-gnueabihf': 0.154.0 + '@oxc-parser/binding-linux-arm-musleabihf': 0.154.0 + '@oxc-parser/binding-linux-arm64-gnu': 0.154.0 + '@oxc-parser/binding-linux-arm64-musl': 0.154.0 + '@oxc-parser/binding-linux-ppc64-gnu': 0.154.0 + '@oxc-parser/binding-linux-riscv64-gnu': 0.154.0 + '@oxc-parser/binding-linux-riscv64-musl': 0.154.0 + '@oxc-parser/binding-linux-s390x-gnu': 0.154.0 + '@oxc-parser/binding-linux-x64-gnu': 0.154.0 + '@oxc-parser/binding-linux-x64-musl': 0.154.0 + '@oxc-parser/binding-openharmony-arm64': 0.154.0 + '@oxc-parser/binding-win32-arm64-msvc': 0.154.0 + '@oxc-parser/binding-win32-ia32-msvc': 0.154.0 + '@oxc-parser/binding-win32-x64-msvc': 0.154.0 p-finally@1.0.0: {} @@ -15572,43 +15593,43 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-loader@8.2.1(postcss@8.5.29)(typescript@6.0.3)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)): + postcss-loader@8.2.1(postcss@8.5.30)(typescript@6.0.3)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)): dependencies: cosmiconfig: 9.0.2(typescript@6.0.3) jiti: 2.7.0 - postcss: 8.5.29 + postcss: 8.5.30 semver: 7.8.5 optionalDependencies: - webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3) + webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3) transitivePeerDependencies: - typescript postcss-media-query-parser@0.2.3: {} - postcss-modules-extract-imports@3.1.0(postcss@8.5.29): + postcss-modules-extract-imports@3.1.0(postcss@8.5.30): dependencies: - postcss: 8.5.29 + postcss: 8.5.30 - postcss-modules-local-by-default@4.2.0(postcss@8.5.29): + postcss-modules-local-by-default@4.2.0(postcss@8.5.30): dependencies: - icss-utils: 5.1.0(postcss@8.5.29) - postcss: 8.5.29 + icss-utils: 5.1.0(postcss@8.5.30) + postcss: 8.5.30 postcss-selector-parser: 7.1.6 postcss-value-parser: 4.2.0 - postcss-modules-scope@3.2.1(postcss@8.5.29): + postcss-modules-scope@3.2.1(postcss@8.5.30): dependencies: - postcss: 8.5.29 + postcss: 8.5.30 postcss-selector-parser: 7.1.6 - postcss-modules-values@4.0.0(postcss@8.5.29): + postcss-modules-values@4.0.0(postcss@8.5.30): dependencies: - icss-utils: 5.1.0(postcss@8.5.29) - postcss: 8.5.29 + icss-utils: 5.1.0(postcss@8.5.30) + postcss: 8.5.30 - postcss-safe-parser@7.1.0(postcss@8.5.29): + postcss-safe-parser@7.1.0(postcss@8.5.30): dependencies: - postcss: 8.5.29 + postcss: 8.5.30 postcss-selector-parser@7.1.6: dependencies: @@ -15623,6 +15644,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.2 + postcss@8.5.30: + dependencies: + nanoid: 3.3.20 + picocolors: 1.1.1 + source-map-js: 1.2.2 + powershell-utils@0.2.1: {} prelude-ls@1.2.1: {} @@ -15691,9 +15718,9 @@ snapshots: punycode@2.3.1: {} - puppeteer-core@25.13.0(bufferutil@4.1.0)(utf-8-validate@6.0.6): + puppeteer-core@25.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6): dependencies: - '@puppeteer/browsers': 3.2.4 + '@puppeteer/browsers': 3.2.5 chromium-bidi: 157.0.8090-0(devtools-protocol@0.0.1696802) devtools-protocol: 0.0.1696802 typed-query-selector: 2.12.3 @@ -15705,13 +15732,13 @@ snapshots: - utf-8-validate - yauzl - puppeteer@25.13.0(bufferutil@4.1.0)(utf-8-validate@6.0.6): + puppeteer@25.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6): dependencies: - '@puppeteer/browsers': 3.2.4 + '@puppeteer/browsers': 3.2.5 chromium-bidi: 157.0.8090-0(devtools-protocol@0.0.1696802) devtools-protocol: 0.0.1696802 lilconfig: 3.1.3 - puppeteer-core: 25.13.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + puppeteer-core: 25.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) typed-query-selector: 2.12.3 transitivePeerDependencies: - bufferutil @@ -15880,7 +15907,7 @@ snapshots: adjust-sourcemap-loader: 4.0.0 convert-source-map: 1.9.0 loader-utils: 2.0.4 - postcss: 8.5.29 + postcss: 8.5.30 source-map: 0.6.1 resolve@1.22.13: @@ -15952,12 +15979,12 @@ snapshots: transitivePeerDependencies: - oxc-resolver - rolldown-plugin-dts@0.28.8(rolldown@1.2.13)(typescript@6.0.3): + rolldown-plugin-dts@0.28.8(rolldown@1.2.14)(typescript@6.0.3): dependencies: dts-resolver: 3.0.0 get-tsconfig: 5.0.0-beta.6 obug: 3.0.0 - rolldown: 1.2.13 + rolldown: 1.2.14 yuku-ast: 0.19.0 yuku-codegen: 0.19.0 yuku-parser: 0.19.0 @@ -15987,75 +16014,75 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.2.12 '@rolldown/binding-win32-x64-msvc': 1.2.12 - rolldown@1.2.13: + rolldown@1.2.14: dependencies: - '@oxc-project/types': 0.153.0 + '@oxc-project/types': 0.154.0 '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm-eabi': 1.2.13 - '@rolldown/binding-android-arm64': 1.2.13 - '@rolldown/binding-darwin-arm64': 1.2.13 - '@rolldown/binding-darwin-x64': 1.2.13 - '@rolldown/binding-freebsd-x64': 1.2.13 - '@rolldown/binding-linux-arm-gnueabihf': 1.2.13 - '@rolldown/binding-linux-arm64-gnu': 1.2.13 - '@rolldown/binding-linux-arm64-musl': 1.2.13 - '@rolldown/binding-linux-ppc64-gnu': 1.2.13 - '@rolldown/binding-linux-s390x-gnu': 1.2.13 - '@rolldown/binding-linux-x64-gnu': 1.2.13 - '@rolldown/binding-linux-x64-musl': 1.2.13 - '@rolldown/binding-openharmony-arm64': 1.2.13 - '@rolldown/binding-win32-arm64-msvc': 1.2.13 - '@rolldown/binding-win32-x64-msvc': 1.2.13 - - rollup-plugin-dts@6.5.1(rollup@4.64.5)(typescript@6.0.3): + '@rolldown/binding-android-arm-eabi': 1.2.14 + '@rolldown/binding-android-arm64': 1.2.14 + '@rolldown/binding-darwin-arm64': 1.2.14 + '@rolldown/binding-darwin-x64': 1.2.14 + '@rolldown/binding-freebsd-x64': 1.2.14 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.14 + '@rolldown/binding-linux-arm64-gnu': 1.2.14 + '@rolldown/binding-linux-arm64-musl': 1.2.14 + '@rolldown/binding-linux-ppc64-gnu': 1.2.14 + '@rolldown/binding-linux-s390x-gnu': 1.2.14 + '@rolldown/binding-linux-x64-gnu': 1.2.14 + '@rolldown/binding-linux-x64-musl': 1.2.14 + '@rolldown/binding-openharmony-arm64': 1.2.14 + '@rolldown/binding-win32-arm64-msvc': 1.2.14 + '@rolldown/binding-win32-x64-msvc': 1.2.14 + + rollup-plugin-dts@6.5.1(rollup@4.64.6)(typescript@6.0.3): dependencies: '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.6.0 convert-source-map: 2.0.0 magic-string: 0.30.21 - rollup: 4.64.5 + rollup: 4.64.6 typescript: 6.0.3 optionalDependencies: '@babel/code-frame': 8.0.6 - rollup-plugin-sourcemaps2@0.5.9(@types/node@22.20.5)(rollup@4.64.5): + rollup-plugin-sourcemaps2@0.5.9(@types/node@22.20.5)(rollup@4.64.6): dependencies: - '@rollup/pluginutils': 5.4.0(rollup@4.64.5) - rollup: 4.64.5 + '@rollup/pluginutils': 5.4.0(rollup@4.64.6) + rollup: 4.64.6 optionalDependencies: '@types/node': 22.20.5 - rollup@4.64.5: + rollup@4.64.6: dependencies: '@types/estree': 1.0.9 optionalDependencies: '@napi-rs/lzma-linux-x64-gnu': 1.5.1 - '@rollup/rollup-android-arm-eabi': 4.64.5 - '@rollup/rollup-android-arm64': 4.64.5 - '@rollup/rollup-darwin-arm64': 4.64.5 - '@rollup/rollup-darwin-x64': 4.64.5 - '@rollup/rollup-freebsd-arm64': 4.64.5 - '@rollup/rollup-freebsd-x64': 4.64.5 - '@rollup/rollup-linux-arm-gnueabihf': 4.64.5 - '@rollup/rollup-linux-arm-musleabihf': 4.64.5 - '@rollup/rollup-linux-arm64-gnu': 4.64.5 - '@rollup/rollup-linux-arm64-musl': 4.64.5 - '@rollup/rollup-linux-loong64-gnu': 4.64.5 - '@rollup/rollup-linux-loong64-musl': 4.64.5 - '@rollup/rollup-linux-ppc64-gnu': 4.64.5 - '@rollup/rollup-linux-ppc64-musl': 4.64.5 - '@rollup/rollup-linux-riscv64-gnu': 4.64.5 - '@rollup/rollup-linux-riscv64-musl': 4.64.5 - '@rollup/rollup-linux-s390x-gnu': 4.64.5 - '@rollup/rollup-linux-x64-gnu': 4.64.5 - '@rollup/rollup-linux-x64-musl': 4.64.5 - '@rollup/rollup-openbsd-x64': 4.64.5 - '@rollup/rollup-openharmony-arm64': 4.64.5 - '@rollup/rollup-win32-arm64-msvc': 4.64.5 - '@rollup/rollup-win32-ia32-msvc': 4.64.5 - '@rollup/rollup-win32-x64-gnu': 4.64.5 - '@rollup/rollup-win32-x64-msvc': 4.64.5 + '@rollup/rollup-android-arm-eabi': 4.64.6 + '@rollup/rollup-android-arm64': 4.64.6 + '@rollup/rollup-darwin-arm64': 4.64.6 + '@rollup/rollup-darwin-x64': 4.64.6 + '@rollup/rollup-freebsd-arm64': 4.64.6 + '@rollup/rollup-freebsd-x64': 4.64.6 + '@rollup/rollup-linux-arm-gnueabihf': 4.64.6 + '@rollup/rollup-linux-arm-musleabihf': 4.64.6 + '@rollup/rollup-linux-arm64-gnu': 4.64.6 + '@rollup/rollup-linux-arm64-musl': 4.64.6 + '@rollup/rollup-linux-loong64-gnu': 4.64.6 + '@rollup/rollup-linux-loong64-musl': 4.64.6 + '@rollup/rollup-linux-ppc64-gnu': 4.64.6 + '@rollup/rollup-linux-ppc64-musl': 4.64.6 + '@rollup/rollup-linux-riscv64-gnu': 4.64.6 + '@rollup/rollup-linux-riscv64-musl': 4.64.6 + '@rollup/rollup-linux-s390x-gnu': 4.64.6 + '@rollup/rollup-linux-x64-gnu': 4.64.6 + '@rollup/rollup-linux-x64-musl': 4.64.6 + '@rollup/rollup-openbsd-x64': 4.64.6 + '@rollup/rollup-openharmony-arm64': 4.64.6 + '@rollup/rollup-win32-arm64-msvc': 4.64.6 + '@rollup/rollup-win32-ia32-msvc': 4.64.6 + '@rollup/rollup-win32-x64-gnu': 4.64.6 + '@rollup/rollup-win32-x64-msvc': 4.64.6 fsevents: 2.3.3 router@2.2.0(supports-color@11.0.0): @@ -16198,11 +16225,11 @@ snapshots: sass-embedded-win32-arm64: 1.105.1 sass-embedded-win32-x64: 1.105.1 - sass-loader@17.0.1(sass-embedded@1.105.1)(sass@1.105.1)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)): + sass-loader@17.0.1(sass-embedded@1.105.1)(sass@1.105.1)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)): optionalDependencies: sass: 1.105.1 sass-embedded: 1.105.1 - webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3) + webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3) sass@1.105.1: dependencies: @@ -16428,11 +16455,11 @@ snapshots: source-map-js@1.2.2: {} - source-map-loader@5.0.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)): + source-map-loader@5.0.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)): dependencies: iconv-lite: 0.6.3 source-map-js: 1.2.2 - webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3) + webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3) source-map-support@0.5.21: dependencies: @@ -16860,6 +16887,8 @@ snapshots: undici@8.11.2: {} + undici@8.12.1: {} + unicode-canonical-property-names-ecmascript@2.0.1: {} unicode-match-property-ecmascript@2.0.0: @@ -17002,8 +17031,8 @@ snapshots: dependencies: lightningcss: 1.33.0 picomatch: 4.0.7 - postcss: 8.5.29 - rolldown: 1.2.12 + postcss: 8.5.30 + rolldown: 1.2.14 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 22.20.5 @@ -17074,6 +17103,16 @@ snapshots: optionalDependencies: webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3) + webpack-dev-middleware@8.3.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)): + dependencies: + ansi-html-community: 0.0.8 + memfs: 4.80.0 + mime-types: 3.0.2 + range-parser: 1.3.0 + schema-utils: 4.5.0 + optionalDependencies: + webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3) + webpack-dev-server@6.0.0(bufferutil@4.1.0)(supports-color@11.0.0)(utf-8-validate@6.0.6)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)): dependencies: '@types/bonjour': 3.5.13 @@ -17108,6 +17147,40 @@ snapshots: - supports-color - utf-8-validate + webpack-dev-server@6.0.0(bufferutil@4.1.0)(supports-color@11.0.0)(utf-8-validate@6.0.6)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)): + dependencies: + '@types/bonjour': 3.5.13 + '@types/connect-history-api-fallback': 1.5.4 + '@types/express': 5.0.6 + '@types/express-serve-static-core': 5.1.3 + '@types/serve-index': 1.9.4 + '@types/serve-static': 2.2.0 + '@types/ws': 8.18.2 + ansi-html-community: 0.0.8 + bonjour-service: 1.4.4 + chokidar: 5.0.0 + compression: 1.8.2(supports-color@11.0.0) + connect-history-api-fallback: 2.0.0 + express: 5.2.1(supports-color@11.0.0) + graceful-fs: 4.2.11 + http-proxy-middleware: 4.2.0(supports-color@11.0.0) + ipaddr.js: 2.5.0 + launch-editor: 2.14.2 + open: 11.0.4 + p-retry: 8.0.1 + schema-utils: 4.5.0 + selfsigned: 5.5.0 + serve-index: 1.9.2(supports-color@11.0.0) + tinyglobby: 0.2.17 + webpack-dev-middleware: 8.3.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)) + ws: 8.22.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + optionalDependencies: + webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + webpack-merge@6.0.1: dependencies: clone-deep: 4.0.1 @@ -17116,10 +17189,10 @@ snapshots: webpack-sources@3.6.0: {} - webpack-subresource-integrity@5.1.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3)): + webpack-subresource-integrity@5.1.0(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)): dependencies: typed-assert: 1.0.9 - webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3) + webpack: 5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3) webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.29)(uglify-js@3.19.3): dependencies: @@ -17158,6 +17231,43 @@ snapshots: - svgo - uglify-js + webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3): + dependencies: + '@types/estree': 1.0.9 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + browserslist: 4.29.3 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.26.0 + es-module-lexer: 2.3.2 + events: 3.3.0 + graceful-fs: 4.2.11 + mime-db: 1.54.0 + minimizer-webpack-plugin: 5.13.0(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)(webpack@5.111.1(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.30)(uglify-js@3.19.3)) + schema-utils: 4.5.0 + tapable: 2.3.3 + watchpack: 2.5.2 + webpack-sources: 3.6.0 + transitivePeerDependencies: + - '@minify-html/node' + - '@napi-rs/image' + - '@swc/core' + - '@swc/css' + - '@swc/html' + - clean-css + - cssnano + - csso + - esbuild + - html-minifier-terser + - imagemin + - lightningcss + - postcss + - sharp + - svgo + - uglify-js + websocket-driver@0.7.5: dependencies: http-parser-js: 0.5.10 From 93f238c9781897997b1c64d607f3bb3c91ba1fd1 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Thu, 15 Oct 2026 10:58:56 +0000 Subject: [PATCH 45/52] fix(@angular/build): rebuild library when transitive stylesheet dependencies change in watch mode Track transitive stylesheet resource references per containing component and stylesheet file in `BuilderState.addFileReferences`, and resolve affected files via `BuilderState.getAffectedFiles` during watch mode rebuilds. Previously, modifying a Sass partial imported by an inline component stylesheet did not invalidate the containing component file or reset the Sass worker pool cache. --- .../src/builders/library/builder-state.ts | 97 ++++++++++++++++++- .../builders/library/builder-state_spec.ts | 52 ++++++++++ .../build/src/builders/library/builder.ts | 27 ++---- .../builders/library/pipeline/compilation.ts | 21 ++-- .../library/tests/behavior/watch_spec.ts | 48 +++++++++ 5 files changed, 213 insertions(+), 32 deletions(-) diff --git a/packages/angular/build/src/builders/library/builder-state.ts b/packages/angular/build/src/builders/library/builder-state.ts index c20ef26ea7c5..81b4e21e778d 100644 --- a/packages/angular/build/src/builders/library/builder-state.ts +++ b/packages/angular/build/src/builders/library/builder-state.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ +import { toPosixPath } from '../../utils/path'; import { ExecutionResult } from './execution-result'; import type { BundleResult, @@ -15,10 +16,12 @@ import type { } from './types'; /** - * Encapsulates incremental compilation state, watched compilation file tracking, - * and execution results across watch-mode rebuilds. + * Encapsulates incremental compilation state, transitive resource reference tracking, + * watched compilation file tracking, and execution results across watch-mode rebuilds. */ export class BuilderState { + readonly #referencingFiles = new Map>(); + readonly #referencedByFile = new Map>(); readonly #watchedCompilationFiles = new Set(); readonly #pendingCompilationFiles = new Set(); @@ -116,6 +119,94 @@ export class BuilderState { return this.#executionResult; } + /** + * Records transitive resource dependencies (such as Sass partials) for a containing + * component or stylesheet file and registers them in `watchedCompilationFiles`. + * Multiple calls for the same containing file accumulate references additively. + * + * @param containingFile Path of the referencing component or stylesheet file. + * @param referencedFiles Paths of the referenced files. + */ + addFileReferences(containingFile: string, referencedFiles: Iterable): void { + const posixContainingFile = toPosixPath(containingFile); + let forwardReferences = this.#referencedByFile.get(posixContainingFile); + + for (const file of referencedFiles) { + const posixFile = toPosixPath(file); + this.#watchedCompilationFiles.add(posixFile); + if (posixFile === posixContainingFile) { + continue; + } + + if (!forwardReferences) { + forwardReferences = new Set(); + this.#referencedByFile.set(posixContainingFile, forwardReferences); + } + forwardReferences.add(posixFile); + + let referencing = this.#referencingFiles.get(posixFile); + if (!referencing) { + referencing = new Set(); + this.#referencingFiles.set(posixFile, referencing); + } + referencing.add(posixContainingFile); + } + } + + /** + * Clears previously recorded outgoing resource references for the given containing files + * before they are recompiled. + * + * @param containingFiles Paths of the containing or stylesheet files being recompiled. + */ + clearFileReferences(containingFiles: Iterable): void { + for (const containingFile of containingFiles) { + const posixContainingFile = toPosixPath(containingFile); + const forwardReferences = this.#referencedByFile.get(posixContainingFile); + if (!forwardReferences) { + continue; + } + + for (const prevRef of forwardReferences) { + const referencing = this.#referencingFiles.get(prevRef); + if (referencing) { + referencing.delete(posixContainingFile); + if (referencing.size === 0) { + this.#referencingFiles.delete(prevRef); + } + } + } + + this.#referencedByFile.delete(posixContainingFile); + } + } + + /** + * Returns the set of all files affected by the given changed files, including the + * changed files themselves and all transitively referencing files + * (e.g., partial `.scss` -> component `.scss` -> component `.ts`). + * + * @param files Initial changed file paths. + * @returns Set of POSIX paths including all transitively referencing files. + */ + getAffectedFiles(files: Iterable): Set { + const affected = new Set(); + for (const file of files) { + affected.add(toPosixPath(file)); + } + + for (const file of affected) { + const referencing = this.#referencingFiles.get(file); + if (referencing) { + for (const refFile of referencing) { + affected.add(refFile); + } + } + } + + return affected; + } + /** * Determines whether compilation and bundling need to run for the current build iteration. * Also records incoming modified files so they are retained if the iteration aborts early. @@ -235,6 +326,8 @@ export class BuilderState { this.pendingChangedEsmFiles.clear(); this.pendingChangedDtsFiles.clear(); this.#pendingCompilationFiles.clear(); + this.#referencingFiles.clear(); + this.#referencedByFile.clear(); this.#watchedCompilationFiles.clear(); } } diff --git a/packages/angular/build/src/builders/library/builder-state_spec.ts b/packages/angular/build/src/builders/library/builder-state_spec.ts index 9cf744d288bc..ae84bbaa7331 100644 --- a/packages/angular/build/src/builders/library/builder-state_spec.ts +++ b/packages/angular/build/src/builders/library/builder-state_spec.ts @@ -70,6 +70,58 @@ describe('BuilderState', () => { }); }); + describe('file reference tracking', () => { + it('should expand transitive multi-hop references and ignore self-references', () => { + const state = new BuilderState(); + const compTs = '/workspace/projects/my-lib/src/lib/comp.ts'; + const compScss = '/workspace/projects/my-lib/src/lib/comp.scss'; + const varsScss = '/workspace/projects/my-lib/src/lib/_vars.scss'; + + state.addFileReferences(compTs, [compTs, compScss, varsScss]); + state.addFileReferences(compScss, [compScss, varsScss]); + + expect(state.watchedCompilationFiles.has(compTs)).toBeTrue(); + expect(state.watchedCompilationFiles.has(compScss)).toBeTrue(); + expect(state.watchedCompilationFiles.has(varsScss)).toBeTrue(); + + const affected = state.getAffectedFiles([varsScss]); + expect(affected).toEqual(new Set([varsScss, compTs, compScss])); + + // Subsequent getAffectedFiles calls preserve mappings when not yet overwritten + const affectedAgain = state.getAffectedFiles([varsScss]); + expect(affectedAgain).toEqual(new Set([varsScss, compTs, compScss])); + }); + + it('should accumulate references across multiple stylesheets for the same containing file', () => { + const state = new BuilderState(); + const compTs = '/workspace/projects/my-lib/src/lib/comp.ts'; + const firstPartial = '/workspace/projects/my-lib/src/lib/_first.scss'; + const secondPartial = '/workspace/projects/my-lib/src/lib/_second.scss'; + + state.addFileReferences(compTs, [compTs, firstPartial]); + state.addFileReferences(compTs, [compTs, secondPartial]); + + expect(state.getAffectedFiles([firstPartial])).toEqual(new Set([firstPartial, compTs])); + expect(state.getAffectedFiles([secondPartial])).toEqual(new Set([secondPartial, compTs])); + }); + + it('should prune stale references when a containing file is cleared and re-recorded', () => { + const state = new BuilderState(); + const compTs = '/workspace/projects/my-lib/src/lib/comp.ts'; + const oldPartial = '/workspace/projects/my-lib/src/lib/_old.scss'; + const newPartial = '/workspace/projects/my-lib/src/lib/_new.scss'; + + state.addFileReferences(compTs, [compTs, oldPartial]); + expect(state.getAffectedFiles([oldPartial])).toEqual(new Set([oldPartial, compTs])); + + // Clear and re-record references for compTs without oldPartial + state.clearFileReferences([compTs]); + state.addFileReferences(compTs, [compTs, newPartial]); + expect(state.getAffectedFiles([oldPartial])).toEqual(new Set([oldPartial])); + expect(state.getAffectedFiles([newPartial])).toEqual(new Set([newPartial, compTs])); + }); + }); + describe('shouldCompileEntryPoints & getCompilationModifiedFiles', () => { it('should preserve pending compilation files across aborted iterations', () => { const state = new BuilderState({ diff --git a/packages/angular/build/src/builders/library/builder.ts b/packages/angular/build/src/builders/library/builder.ts index fa8e717c9776..42be7f99b211 100644 --- a/packages/angular/build/src/builders/library/builder.ts +++ b/packages/angular/build/src/builders/library/builder.ts @@ -261,29 +261,14 @@ async function* runWatchLoop( console.clear(); } - const changedFiles = new Set(); - let hasStyleChanges = false; - let hasSassChanges = false; - for (const file of changes.all) { - const posixFile = toPosixPath(file); - changedFiles.add(posixFile); - if (/\.(?:scss|sass)$/i.test(posixFile)) { - hasStyleChanges = true; - hasSassChanges = true; - } else if (/\.(?:less|css)$/i.test(posixFile)) { - hasStyleChanges = true; - } - } + const rawChangedFiles = changes.all.map(toPosixPath); + stylesheetBundler.invalidate(rawChangedFiles); + const changedFiles = buildState.getAffectedFiles(rawChangedFiles); - if (hasStyleChanges) { - if (hasSassChanges) { + for (const posixFile of changedFiles) { + if (/\.(?:scss|sass)$/i.test(posixFile)) { resetSassWorkerPoolCaches(); - } - const invalidatedStyles = stylesheetBundler.invalidate(changedFiles); - if (invalidatedStyles) { - for (const styleFile of invalidatedStyles) { - changedFiles.add(toPosixPath(styleFile)); - } + break; } } diff --git a/packages/angular/build/src/builders/library/pipeline/compilation.ts b/packages/angular/build/src/builders/library/pipeline/compilation.ts index 38b28f442df6..1c026c5e9fec 100644 --- a/packages/angular/build/src/builders/library/pipeline/compilation.ts +++ b/packages/angular/build/src/builders/library/pipeline/compilation.ts @@ -26,7 +26,7 @@ const EMITTED_EXTENSIONS = ['.js', '.mjs', '.cjs', '.d.ts', '.d.mts', '.d.cts']; * * @param options The normalized library builder options with POSIX paths. * @param stylesheetBundler The component stylesheet bundler instance. - * @param buildState The build state tracking compilation caches and diagnostics. + * @param buildState The build state tracking compilation caches, file references, and diagnostics. * @param modifiedFiles Optional set of modified POSIX file paths for incremental compilation. * @returns A promise resolving to the compilation output containing emitted files and cache state. */ @@ -70,9 +70,9 @@ export async function compileLibrary( if (effectiveModifiedFiles && effectiveModifiedFiles.size > 0) { await compilationInstance.update?.(effectiveModifiedFiles); + buildState.clearFileReferences(effectiveModifiedFiles); } - const allReferencedFiles = new Set(); const stylesheetWarnings: PartialMessage[] = []; const stylesheetErrors: PartialMessage[] = []; const failedFiles = new Set(); @@ -88,7 +88,13 @@ export async function compileLibrary( ? await stylesheetBundler.bundleFile(stylesheetFile) : await stylesheetBundler.bundleInline(data, containingFile); - result.referencedFiles?.forEach((f) => allReferencedFiles.add(toPosixPath(f))); + if (result.referencedFiles) { + buildState.addFileReferences(containingFile, result.referencedFiles); + if (stylesheetFile) { + buildState.addFileReferences(stylesheetFile, result.referencedFiles); + } + } + if (result.warnings.length > 0) { stylesheetWarnings.push(...result.warnings); } @@ -137,14 +143,11 @@ export async function compileLibrary( const dtsFiles = cached?.dtsFiles ?? new Map(); const changedEsmFiles = new Set(); const changedDtsFiles = new Set(); - - for (const ref of referencedFiles) { - allReferencedFiles.add(toPosixPath(ref)); - } + const posixReferencedFiles = new Set(referencedFiles.map(toPosixPath)); if (cached && effectiveModifiedFiles) { for (const modifiedFile of effectiveModifiedFiles) { - if (allReferencedFiles.has(modifiedFile)) { + if (posixReferencedFiles.has(modifiedFile)) { continue; } @@ -187,7 +190,7 @@ export async function compileLibrary( dtsFiles, changedEsmFiles, changedDtsFiles, - referencedFiles: allReferencedFiles, + referencedFiles: posixReferencedFiles, cache: { compilationInstance, esmFiles, diff --git a/packages/angular/build/src/builders/library/tests/behavior/watch_spec.ts b/packages/angular/build/src/builders/library/tests/behavior/watch_spec.ts index 415f24d269c0..e9b7e57ddd9f 100644 --- a/packages/angular/build/src/builders/library/tests/behavior/watch_spec.ts +++ b/packages/angular/build/src/builders/library/tests/behavior/watch_spec.ts @@ -8,6 +8,7 @@ import { rm } from 'node:fs/promises'; import { executeLibraryBuilder } from '../../builder'; +import { InlineStyleLanguage } from '../../schema'; import { BASE_OPTIONS, LIBRARY_BUILDER_INFO, describeLibraryBuilder } from '../setup'; describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => { @@ -601,5 +602,52 @@ describeLibraryBuilder(executeLibraryBuilder, LIBRARY_BUILDER_INFO, (harness) => }, ]); }); + + it('should rebuild when a Sass partial imported by an inline component stylesheet is modified in watch mode', async () => { + await harness.writeFiles({ + 'projects/lib/src/lib/_vars.scss': '$primary-color: rgb(10, 20, 30);', + 'projects/lib/src/lib/_spacing.scss': '$pad: 12px;', + 'projects/lib/src/lib/lib.component.ts': ` + import { Component } from '@angular/core'; + + @Component({ + selector: 'lib-inline-sass', + template: 'Inline Sass', + styles: [ + '@use "./vars"; :host { color: vars.$primary-color; }', + '@use "./spacing"; :host { padding: spacing.$pad; }', + ], + }) + export class LibComponent {} + `, + }); + + harness.useTarget('build', { + ...BASE_OPTIONS, + inlineStyleLanguage: InlineStyleLanguage.Scss, + watch: true, + }); + + await harness.executeWithCases([ + async ({ result }) => { + expect(result?.success).toBeTrue(); + const content = harness.readFile('dist/lib/fesm2022/lib.mjs'); + expect(content).toMatch(/color:\s*(?:#0a141e|rgb\(10,\s*20,\s*30\))/); + expect(content).toMatch(/padding:\s*12px/); + + // Modify the Sass partial referenced by the first inline component style + await harness.writeFile( + 'projects/lib/src/lib/_vars.scss', + '$primary-color: rgb(200, 100, 50);', + ); + }, + ({ result }) => { + expect(result?.success).toBeTrue(); + const content = harness.readFile('dist/lib/fesm2022/lib.mjs'); + expect(content).toMatch(/color:\s*(?:#c86432|rgb\(200,\s*100,\s*50\))/); + expect(content).toMatch(/padding:\s*12px/); + }, + ]); + }); }); }); From 554c1eb801ca9b83877eaf03cba9f2a0e5ffe178 Mon Sep 17 00:00:00 2001 From: Doug Parker Date: Thu, 15 Oct 2026 11:33:25 -0700 Subject: [PATCH 46/52] docs: release notes for the v22.2.3 release --- CHANGELOG.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce91a1e74158..367c576b8b99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,52 @@ + + +# 22.2.3 (2026-10-15) + +### @angular/cli + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------------------- | +| [3158e865f](https://github.com/angular/angular-cli/commit/3158e865ffdd828711d645dff16cc17fd26bb58e) | fix | accept multi-digit array indices in ng config | +| [bcff0e76a](https://github.com/angular/angular-cli/commit/bcff0e76adf73cfa32b02c5256490189675cb132) | fix | keep ng version working when the package manager is not installed | +| [5570c91d2](https://github.com/angular/angular-cli/commit/5570c91d2f38764cd841fcce146f1d13fef49b0c) | fix | resolve package name in npm workspace members | + +### @schematics/angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------------------------- | +| [881865f36](https://github.com/angular/angular-cli/commit/881865f364b33b36630aa6ab7a129f7ed665cfa7) | fix | keep the workspace build version in the use-application-builder migration | + +### @angular-devkit/schematics + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------- | +| [cf1f3b9d4](https://github.com/angular/angular-cli/commit/cf1f3b9d43177e15cf9a00973e6da3baeaf4b2dd) | fix | avoid stack overflow when chaining many rules | + +### @angular/build + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------------------- | +| [1d477d6bc](https://github.com/angular/angular-cli/commit/1d477d6bc27159cb0c78288e047fcadfe6fc31d4) | fix | add CSP nonce to stylesheet and modulepreload link elements | +| [fbe208f83](https://github.com/angular/angular-cli/commit/fbe208f8392ec0ce82d597e8b690f146370bdc81) | fix | always use AOT when extracting i18n messages | +| [c1c4216a6](https://github.com/angular/angular-cli/commit/c1c4216a680891b80670660a621d6736c4aecaf0) | fix | coalesce external watcher directories to avoid macOS FSEvents limit | +| [792990bc2](https://github.com/angular/angular-cli/commit/792990bc2eacdcc8ed4de6ef46e58ceeb5fe8741) | fix | disable Vitest fsModuleCache in unit-test builder | +| [82439399c](https://github.com/angular/angular-cli/commit/82439399cbfb4c1d21d1c80d976021efa9e4a39a) | fix | ensure Sass importers return global Promise instances | +| [a818de415](https://github.com/angular/angular-cli/commit/a818de415e933819e7a2e3e679cd0b2d2be734de) | fix | keep Vite server file watcher disabled in Vitest watch mode | +| [91bad469e](https://github.com/angular/angular-cli/commit/91bad469ec5ce7b2dfd07e394b482d2cef411407) | fix | sort discovered unit-test files for deterministic builds | +| [e84db4af7](https://github.com/angular/angular-cli/commit/e84db4af70ca9be490b462e6d8112524dc8eb6d4) | fix | use module.registerHooks() for in-memory ESM loader | +| [a428021b7](https://github.com/angular/angular-cli/commit/a428021b77dbccf404f39712f1c88bed9b8e4272) | perf | avoid invalidating Angular diagnostic cache on stylesheet change | +| [b0ac394a0](https://github.com/angular/angular-cli/commit/b0ac394a063f084d885df67660224b6a25e2c614) | perf | resolve asset patterns concurrently with bounded concurrency | + +### @angular/ssr + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------ | +| [bd09b98fc](https://github.com/angular/angular-cli/commit/bd09b98fcaff4b76c7fd65999b51bfaa942d1858) | fix | preserve preload metadata for nested empty-path routes | +| [a92546892](https://github.com/angular/angular-cli/commit/a925468929c74c30a3e64b361a6dc5d6fdc1006a) | fix | preserve query parameters on relative route redirects | +| [a2b86cc94](https://github.com/angular/angular-cli/commit/a2b86cc94d408ba4c3d422224b58e26b7a68f692) | fix | resolve relative redirects against the parent route | + + + # 21.2.27 (2026-10-14) From 00c25090960adfea437997a8e3cdec17634bf9eb Mon Sep 17 00:00:00 2001 From: Doug Parker Date: Thu, 15 Oct 2026 12:01:18 -0700 Subject: [PATCH 47/52] release: cut the v22.3.0-next.2 release --- CHANGELOG.md | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 367c576b8b99..a3c4fa9dd66e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,62 @@ + + +# 22.3.0-next.2 (2026-10-15) + +### @angular/cli + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------------------- | +| [5c656152e](https://github.com/angular/angular-cli/commit/5c656152ef91e2731155f6027a845d8014b53e4f) | fix | accept multi-digit array indices in ng config | +| [2e0f48e3f](https://github.com/angular/angular-cli/commit/2e0f48e3ff40289725d3590fa8e1fc059fbaeb88) | fix | keep ng version working when the package manager is not installed | +| [a1cf33bc4](https://github.com/angular/angular-cli/commit/a1cf33bc45882fb74578cc7d1faeba8cecec7b73) | fix | resolve package name in npm workspace members | + +### @schematics/angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------------------------- | +| [639d31f11](https://github.com/angular/angular-cli/commit/639d31f11b102a12776ae8dce6369d6edd1b6ff3) | feat | add use-library-builder migration to migrate from ng-packagr | +| [445cc767e](https://github.com/angular/angular-cli/commit/445cc767e62b72631dd53c0c5324b458fee76608) | fix | keep the workspace build version in the use-application-builder migration | + +### @angular-devkit/schematics + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------- | +| [b39a5fcda](https://github.com/angular/angular-cli/commit/b39a5fcdac288e317f3b00468c09173a1d306f98) | fix | avoid stack overflow when chaining many rules | + +### @angular/build + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------------------------------------------- | +| [b975da4b0](https://github.com/angular/angular-cli/commit/b975da4b016eaa107acc259eb8205135d9396f95) | fix | add CSP nonce to stylesheet and modulepreload link elements | +| [13923047f](https://github.com/angular/angular-cli/commit/13923047f64b6e1063f7f07029c70295b5c99d69) | fix | always use AOT when extracting i18n messages | +| [d2233e225](https://github.com/angular/angular-cli/commit/d2233e225aa5fd507e3ce7bfd35ae2268c036aa4) | fix | coalesce external watcher directories to avoid macOS FSEvents limit | +| [23d42fc80](https://github.com/angular/angular-cli/commit/23d42fc806f174c7da961c35e07a42aa1e00d1e7) | fix | conditionally declare tslib in built library package | +| [f0a74e8f0](https://github.com/angular/angular-cli/commit/f0a74e8f0ea04fd3f839be0120346067440b1350) | fix | disable Vitest fsModuleCache in unit-test builder | +| [2c518a6db](https://github.com/angular/angular-cli/commit/2c518a6dbe8734d247dfe4eb2c1c4af5e169fa94) | fix | enhance build logs and output location for library builder | +| [47c328d3e](https://github.com/angular/angular-cli/commit/47c328d3ef7b409af02f270a48f5e99a520fbe14) | fix | ensure Sass importers return global Promise instances | +| [432aea016](https://github.com/angular/angular-cli/commit/432aea0161840bc135704c040108e46092e61c27) | fix | filter Rolldown warnings and disable .d.ts annotation comments in library builder | +| [39d230e18](https://github.com/angular/angular-cli/commit/39d230e1862f2f626d3fba03bbf51873f3578153) | fix | keep Vite server file watcher disabled in Vitest watch mode | +| [93f238c97](https://github.com/angular/angular-cli/commit/93f238c9781897997b1c64d607f3bb3c91ba1fd1) | fix | rebuild library when transitive stylesheet dependencies change in watch mode | +| [7714a8537](https://github.com/angular/angular-cli/commit/7714a8537589afc6180443cc36acd5149a459c57) | fix | resolve unimported NgModule scopes when filtering unit-test files | +| [ad4845583](https://github.com/angular/angular-cli/commit/ad4845583b8d1b8de26ccc0e45b4e6e58d95b362) | fix | respect tsconfig declarationMap and compilationMode in library builder | +| [01afbf418](https://github.com/angular/angular-cli/commit/01afbf418cf6a7688f3f131988eeba3cdac2bde4) | fix | sort discovered unit-test files for deterministic builds | +| [b640b32e1](https://github.com/angular/angular-cli/commit/b640b32e148ab68f820b390b1d9f03ae9a809266) | fix | use module.registerHooks() for in-memory ESM loader | +| [0a077eeed](https://github.com/angular/angular-cli/commit/0a077eeed92b43fa195bf10f479d39a7aca2d3f7) | perf | avoid invalidating Angular diagnostic cache on stylesheet change | +| [2b5a9a620](https://github.com/angular/angular-cli/commit/2b5a9a620495b4c85bf5cfa3db39b632d88e6ca5) | perf | enable TypeScript incremental build cache in library builder | +| [07845f019](https://github.com/angular/angular-cli/commit/07845f019cf7d70c17f037d711b430a776f96031) | perf | optimize incremental watch rebuilds in AOT compilation | +| [fb7efc862](https://github.com/angular/angular-cli/commit/fb7efc86228164330f68ed86801f9d5bbe9ad5b0) | perf | resolve asset patterns concurrently with bounded concurrency | +| [dcf906a62](https://github.com/angular/angular-cli/commit/dcf906a6261a00f95cfbdb18cf9065e1c966e182) | perf | reuse extendedConfigCache in TypeScript compilation | + +### @angular/ssr + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------ | +| [0b9a52cc9](https://github.com/angular/angular-cli/commit/0b9a52cc9516d28afa0d9ef0d07ec745967faf56) | fix | preserve preload metadata for nested empty-path routes | +| [f2cd8c8cf](https://github.com/angular/angular-cli/commit/f2cd8c8cf7c5aa7e7076c87e9c0c55b3bf880f4b) | fix | preserve query parameters on relative route redirects | +| [b3bbada1e](https://github.com/angular/angular-cli/commit/b3bbada1efd0d3a414cce8843b7284e9560f66fc) | fix | resolve relative redirects against the parent route | + + + # 22.2.3 (2026-10-15) diff --git a/package.json b/package.json index 9bc88e433859..911eea20e9f6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "22.3.0-next.1", + "version": "22.3.0-next.2", "private": true, "description": "Software Development Kit for Angular", "keywords": [ From 972302ac3dc7b675e4b36dac465b876014a02b1e Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Thu, 15 Oct 2026 12:05:58 -0400 Subject: [PATCH 48/52] fix(@angular/build): watch only explicitly added paths in chokidar watcher When preserveSymlinks or polling is enabled, the build watcher falls back to Chokidar. Previously, createChokidarWatcher initialized Chokidar on the entire workspace root directory and expanded any watched file inside node_modules to its full package root directory via ChokidarNodeModulesManager. Because Chokidar v5 recursively walks watched directories and attaches individual fs.watch handles to every subdirectory and file, projects with many workspace subdirectories or large imported packages could exceed the macOS per-process directory watch limit and crash with an unhandled EMFILE error. This change initializes Chokidar with an empty watch set and registers only the specific paths passed to add() and remove(), eliminating recursive directory scans across the workspace root and node_modules packages. When a directory is explicitly watched (such as when NG_BUILD_WATCH_ROOT is enabled), node_modules subdirectories are pruned unless directly added to the watch set. An error listener is also attached to prevent unhandled watcher errors from terminating the process, and removed files that remain in the watch set are re-registered so subsequent file recreation is detected across multiple watched directories. Closes #34312 --- packages/angular/build/src/utils/watcher.ts | 299 +++++++++--------- .../angular/build/src/utils/watcher_spec.ts | 96 +++++- 2 files changed, 242 insertions(+), 153 deletions(-) diff --git a/packages/angular/build/src/utils/watcher.ts b/packages/angular/build/src/utils/watcher.ts index ca0e86f987ff..fd865ee80b56 100644 --- a/packages/angular/build/src/utils/watcher.ts +++ b/packages/angular/build/src/utils/watcher.ts @@ -8,7 +8,6 @@ import type * as ParcelWatcher from '@parcel/watcher'; import type * as Chokidar from 'chokidar'; -import { once } from 'node:events'; import * as fs from 'node:fs'; import * as path from 'node:path'; import picomatch from 'picomatch'; @@ -1086,92 +1085,94 @@ async function createParcelWatcher( return buildWatcher; } -/** - * Manages selective node_modules watching for Chokidar. - * - * During Chokidar's initial scan, the allowed packages set is empty, causing Chokidar to prune the entire - * node_modules directory immediately and avoid blocking the 'ready' event for minutes. - * Packages are dynamically allowed and watched at the package root level as files are added via `watcher.add`. - * Tracking files per package allows reference-counting so that package directories are unwatched when no - * longer needed. - */ -class ChokidarNodeModulesManager { - private readonly allowedPackages = new Map>(); - - constructor(private readonly isCaseSensitive: boolean) {} - - registerPackage( - posixPath: string, - lookupKey: string, - ): { isPackage: boolean; newPkgDir?: string } { - const packageDir = extractNodeModulesPackageDir(posixPath); - if (!packageDir) { - return { isPackage: false }; - } - - const packageKey = toLookupKey(packageDir, this.isCaseSensitive); - let watchedInPkg = this.allowedPackages.get(packageKey); - if (!watchedInPkg) { - watchedInPkg = new Set(); - this.allowedPackages.set(packageKey, watchedInPkg); - watchedInPkg.add(lookupKey); - - return { isPackage: true, newPkgDir: packageDir }; - } - - watchedInPkg.add(lookupKey); +function createChokidarIgnored( + ignoredPatterns: string[] | undefined, + isCaseSensitive: boolean, + watchedFiles: ReadonlySet, +): Chokidar.Matcher[] { + // Strip static node_modules ignore patterns (e.g. `**/node_modules/**` from setupWatcher). + // If left in place, picomatch would unconditionally ignore all node_modules files and prevent + // watching explicitly added files inside node_modules. + const customIgnored = + ignoredPatterns + ?.filter((pattern) => { + const base = toPosixPathNormalized(pattern).replace(/\/\*\*$/, ''); - return { isPackage: true }; - } + return base !== NODE_MODULES && !base.endsWith(`/${NODE_MODULES}`); + }) + .map((pattern) => { + if (/[*?[\]{}()]/.test(pattern)) { + const isMatch = picomatch(pattern, { dot: true }); - removePackageFile( - posixPath: string, - lookupKey: string, - ): { isPackage: boolean; unwatchPkgDir?: string } { - const packageDir = extractNodeModulesPackageDir(posixPath); - if (!packageDir) { - return { isPackage: false }; - } + return (filePath: string) => isMatch(toPosixPathNormalized(filePath)); + } - const packageKey = toLookupKey(packageDir, this.isCaseSensitive); - const watchedInPkg = this.allowedPackages.get(packageKey); - if (watchedInPkg) { - watchedInPkg.delete(lookupKey); - if (watchedInPkg.size === 0) { - this.allowedPackages.delete(packageKey); + return { path: toPosixPathNormalized(pattern), recursive: true }; + }) ?? []; - return { isPackage: true, unwatchPkgDir: packageDir }; + // When watching a directory (e.g. projectRoot via NG_BUILD_WATCH_ROOT), prune `node_modules` + // directories unless explicitly added to `watchedFiles`. Explicitly added files inside + // `node_modules` do not end with `/node_modules` and remain watchable. + return [ + ...customIgnored, + (filePath: string) => { + if (!filePath.includes(NODE_MODULES)) { + return false; } - } - - return { isPackage: true }; - } - - isIgnored(filePath: string): boolean { - // Fast path: avoid expensive normalization for non-node_modules files - if (!filePath.includes(NODE_MODULES)) { - return false; - } - const posixPath = toPosixPathNormalized(filePath); - const lookupKey = toLookupKey(posixPath, this.isCaseSensitive); + const posixPath = toPosixPathNormalized(filePath); + const lookupKey = toLookupKey(posixPath, isCaseSensitive); - if (!`${lookupKey}/`.includes(NODE_MODULES_SEGMENT)) { - return false; - } + return ( + (lookupKey === NODE_MODULES || lookupKey.endsWith(`/${NODE_MODULES}`)) && + !watchedFiles.has(lookupKey) + ); + }, + ]; +} - if (this.allowedPackages.has(lookupKey)) { - return false; - } +interface ChokidarBaselineEntry { + posixPath: string; + mtimeMs?: number; + size?: number; +} - for (const pkg of this.allowedPackages.keys()) { - if (isPathInside(lookupKey, pkg)) { - return false; +// Chokidar initializes file watchers asynchronously (`await stat(path)` followed by +// `fs.watch` or `fs.watchFile`). If a file is modified or recreated immediately after +// `watcher.add()` is called, Chokidar may capture the post-modification state as its initial +// baseline (or suppress the initial `'add'` event due to `ignoreInitial: true`) and miss the +// change. Re-statting after a short delay catches any modifications or recreations that occurred +// during asynchronous watcher registration, while `fileStats` deduplicates if Chokidar also fired. +async function checkChokidarBaselines( + baselineStats: ReadonlyMap, + watchedFiles: ReadonlySet, + fileStats: ReadonlyMap, + watcher: Chokidar.FSWatcher, + handleEvent: (type: 'added' | 'modified' | 'removed', rawPath: string) => void, +): Promise { + await Promise.all( + Array.from(baselineStats, async ([lookupKey, baseline]) => { + if (!watchedFiles.has(lookupKey)) { + return; + } + const currentStat = await fs.promises.stat(baseline.posixPath).catch(() => null); + if (!watchedFiles.has(lookupKey) || !currentStat?.isFile()) { + return; } - } - return true; - } + if (baseline.mtimeMs === undefined || baseline.size === undefined) { + const recorded = fileStats.get(lookupKey); + if (!recorded) { + watcher.add(baseline.posixPath); + handleEvent('added', path.normalize(baseline.posixPath)); + } else if (currentStat.mtimeMs !== recorded.mtimeMs || currentStat.size !== recorded.size) { + handleEvent('modified', path.normalize(baseline.posixPath)); + } + } else if (currentStat.mtimeMs !== baseline.mtimeMs || currentStat.size !== baseline.size) { + handleEvent('modified', path.normalize(baseline.posixPath)); + } + }), + ); } async function createChokidarWatcher( @@ -1181,43 +1182,19 @@ async function createChokidarWatcher( const chokidar = chokidarModule ?? (await import('chokidar')); const watchedFiles = new Set(); const fileStats = new Map(); + const pendingTimers = new Set>(); - let queue: WatcherQueue; - if (options?.polling) { - const pollingInterval = options.interval ?? 100; - const debounceMs = Math.min(250, Math.max(100, Math.ceil(pollingInterval * 1.5))); - const maxWaitMs = Math.max(500, debounceMs * 3); - queue = new WatcherQueue(debounceMs, maxWaitMs); - } else { - queue = new WatcherQueue(); - } + const pollingInterval = options?.interval ?? 100; + const debounceMs = Math.min(250, Math.max(100, Math.ceil(pollingInterval * 1.5))); + const queue = options?.polling + ? new WatcherQueue(debounceMs, Math.max(500, debounceMs * 3)) + : new WatcherQueue(); const rootDir = options?.cwd ?? process.cwd(); const isCaseSensitive = isFileSystemCaseSensitive(rootDir); - const rootDirPosix = toPosixPathNormalized(rootDir); - const rootDirLookupKey = toLookupKey(rootDirPosix, isCaseSensitive); - - const nodeModulesManager = new ChokidarNodeModulesManager(isCaseSensitive); + const ignored = createChokidarIgnored(options?.ignored, isCaseSensitive, watchedFiles); - // Strip static node_modules ignore patterns (e.g. `**/node_modules/**` from setupWatcher). - // If left in place, picomatch would unconditionally ignore all node_modules files and override - // our dynamic package allowlist above. - const customIgnored = - options?.ignored - ?.filter((pattern) => !pattern.includes(NODE_MODULES)) - .map((pattern) => { - if (/[*?[\]{}()]/.test(pattern)) { - const isMatch = picomatch(pattern, { dot: true }); - - return (filePath: string) => isMatch(toPosixPathNormalized(filePath)); - } - - return { path: toPosixPathNormalized(pattern), recursive: true }; - }) ?? []; - - const ignored = [...customIgnored, (filePath: string) => nodeModulesManager.isIgnored(filePath)]; - - const watcher = chokidar.watch(rootDir, { + const watcher = chokidar.watch([], { ignoreInitial: true, ignored, followSymlinks: options?.followSymlinks, @@ -1225,13 +1202,10 @@ async function createChokidarWatcher( interval: options?.interval, }); - const initTime = Date.now(); + // Prevent unhandled watcher errors (such as EMFILE or EACCES) from crashing the process. + watcher.on('error', () => {}); - // Wait for the watcher to complete its initial filesystem scan before returning. - // With `ignoreInitial: true`, any file visited during the initial scan is treated as the initial baseline - // and will not emit 'add' or 'change' events. Awaiting 'ready' ensures that rapid file modifications - // made right after watcher setup (e.g. in rebuild tests) are not swallowed as initial files. - await once(watcher, 'ready'); + const initTime = Date.now(); const handleEvent = (type: 'added' | 'modified' | 'removed', rawPath: string) => { const posixPath = toPosixPathNormalized(rawPath); @@ -1248,14 +1222,10 @@ async function createChokidarWatcher( } const stat = fs.statSync(rawPath, { throwIfNoEntry: false }); - if (!stat) { - return; - } - // Ignore historical events from before watcher initialization, but allow a 1000 ms window // to account for coarse filesystem timestamp resolution (e.g., ext4/overlayfs integer second // mtime truncation on Linux) where files modified during startup may have truncated .000 ms mtimes. - if (stat.mtimeMs < initTime - 1000) { + if (!stat || stat.mtimeMs < initTime - 1000) { return; } @@ -1273,11 +1243,55 @@ async function createChokidarWatcher( queue.addChange(type, rawPath); }; + const scheduleBaselineCheck = (baselineStats: ReadonlyMap) => { + if (baselineStats.size === 0) { + return; + } + + const timer = setTimeout(() => { + pendingTimers.delete(timer); + void checkChokidarBaselines(baselineStats, watchedFiles, fileStats, watcher, handleEvent); + }, 50); + timer.unref(); + pendingTimers.add(timer); + }; + watcher.on('add', (path) => handleEvent('added', path)); watcher.on('change', (path) => handleEvent('modified', path)); - watcher.on('unlink', (path) => handleEvent('removed', path)); + watcher.on('unlink', (rawPath) => { + const posixPath = toPosixPathNormalized(rawPath); + const lookupKey = toLookupKey(posixPath, isCaseSensitive); + if (!isPathWatched(lookupKey, watchedFiles)) { + return; + } - const buildWatcher: BuildWatcher = { + // When Chokidar processes a file removal, it closes the underlying file watcher unless only a + // single directory is tracked (`_watched.size === 1`). Re-adding a directly watched path + // ensures Chokidar continues watching either the recreated file (if replaced within the atomic + // window) or its parent directory for future recreation. + if (watchedFiles.has(lookupKey)) { + fileStats.delete(lookupKey); + watcher.add(posixPath); + const stat = fs.statSync(rawPath, { throwIfNoEntry: false }); + if (stat?.isFile()) { + handleEvent('modified', rawPath); + scheduleBaselineCheck( + new Map([[lookupKey, { posixPath, mtimeMs: stat.mtimeMs, size: stat.size }]]), + ); + + return; + } + + handleEvent('removed', rawPath); + scheduleBaselineCheck(new Map([[lookupKey, { posixPath }]])); + + return; + } + + handleEvent('removed', rawPath); + }); + + return { [Symbol.asyncIterator]() { return this; }, @@ -1304,28 +1318,23 @@ async function createChokidarWatcher( add(paths) { const targets = typeof paths === 'string' ? [paths] : paths; const newPaths: string[] = []; + const baselineStats = new Map(); + for (const p of targets) { const posixPath = toPosixPathNormalized(p); const lookupKey = toLookupKey(posixPath, isCaseSensitive); if (!watchedFiles.has(lookupKey)) { watchedFiles.add(lookupKey); - - // For files inside node_modules, register their package directory. Only newly encountered - // package directories need to be added to Chokidar. - const { isPackage, newPkgDir } = nodeModulesManager.registerPackage(posixPath, lookupKey); - if (newPkgDir) { - newPaths.push(newPkgDir); - } else if ( - !isPackage && - !isPathInside(lookupKey, rootDirLookupKey) && - lookupKey !== rootDirLookupKey - ) { - newPaths.push(posixPath); + newPaths.push(posixPath); + const stat = fs.statSync(posixPath, { throwIfNoEntry: false }); + if (stat?.isFile()) { + baselineStats.set(lookupKey, { posixPath, mtimeMs: stat.mtimeMs, size: stat.size }); } } } if (newPaths.length > 0) { watcher.add(newPaths); + scheduleBaselineCheck(baselineStats); } }, @@ -1338,21 +1347,7 @@ async function createChokidarWatcher( if (watchedFiles.has(lookupKey)) { watchedFiles.delete(lookupKey); fileStats.delete(lookupKey); - - // When the last watched file in a package is removed, unwatch the package directory. - const { isPackage, unwatchPkgDir } = nodeModulesManager.removePackageFile( - posixPath, - lookupKey, - ); - if (unwatchPkgDir) { - removePaths.push(unwatchPkgDir); - } else if ( - !isPackage && - !isPathInside(lookupKey, rootDirLookupKey) && - lookupKey !== rootDirLookupKey - ) { - removePaths.push(posixPath); - } + removePaths.push(posixPath); } } if (removePaths.length > 0) { @@ -1361,13 +1356,15 @@ async function createChokidarWatcher( }, async close() { + for (const timer of pendingTimers) { + clearTimeout(timer); + } + pendingTimers.clear(); try { await watcher.close(); } finally { queue.close(); } }, - }; - - return buildWatcher; + } satisfies BuildWatcher; } diff --git a/packages/angular/build/src/utils/watcher_spec.ts b/packages/angular/build/src/utils/watcher_spec.ts index 3703eb9f4ce1..ef7a14d831d2 100644 --- a/packages/angular/build/src/utils/watcher_spec.ts +++ b/packages/angular/build/src/utils/watcher_spec.ts @@ -775,7 +775,7 @@ describe('Watcher', () => { } }, 10000); - it('should unwatch linked package directory when all its files are removed via watcher.remove', async () => { + it('should unwatch linked package file when removed via watcher.remove', async () => { const externalDir = fs.mkdtempSync(path.join(TMP_DIR, 'watcher-remove-npm-link-')); let watcher: BuildWatcher | undefined; @@ -813,7 +813,7 @@ describe('Watcher', () => { // Remove the linked file from the watcher watcher.remove(linkedFile); - // Allow a brief moment for Chokidar to asynchronously complete unwatching the package directory + // Allow a brief moment for Chokidar to asynchronously complete unwatching the file await setTimeout(250); // Modify both the removed linked file and the regular file @@ -876,6 +876,98 @@ describe('Watcher', () => { fs.rmSync(externalRoot, { recursive: true, force: true }); } }, 10000); + + it('should detect file deletion and recreation when watching multiple files with followSymlinks: true', async () => { + const subDirA = path.join(tempDir, 'dir-a'); + const subDirB = path.join(tempDir, 'dir-b'); + fs.mkdirSync(subDirA); + fs.mkdirSync(subDirB); + + const fileA = path.join(subDirA, 'a.ts'); + const fileB = path.join(subDirB, 'b.ts'); + fs.writeFileSync(fileA, 'export const a = 1;'); + fs.writeFileSync(fileB, 'export const b = 1;'); + + const watcher = await createWatcher({ + followSymlinks: true, + cwd: tempDir, + }); + + try { + watcher.add([fileA, fileB]); + await setTimeout(250); + + const iterator = watcher[Symbol.asyncIterator](); + + // Delete fileA and wait past Chokidar's atomic write window + fs.rmSync(fileA); + let result = await iterator.next(); + expect(result.done).toBeFalsy(); + expect(result.value?.removed.size).toBeGreaterThan(0); + + await setTimeout(150); + + // Recreate fileA and verify the watcher still detects it + fs.writeFileSync(fileA, 'export const a = 2;'); + result = await iterator.next(); + expect(result.done).toBeFalsy(); + expect(result.value?.all.some((f: string) => f.includes('a.ts'))).toBeTrue(); + + // Modify recreated fileA again to ensure ongoing changes are tracked + await setTimeout(150); + fs.writeFileSync(fileA, 'export const a = 3;'); + result = await iterator.next(); + expect(result.done).toBeFalsy(); + expect(result.value?.all.some((f: string) => f.includes('a.ts'))).toBeTrue(); + } finally { + await watcher.close(); + } + }, 10000); + + it('should prune node_modules when watching root directory while watching added package files', async () => { + const nodeModulesDir = path.join(tempDir, 'node_modules'); + const pkgDir = path.join(nodeModulesDir, 'some-pkg'); + fs.mkdirSync(pkgDir, { recursive: true }); + + const watchedPkgFile = path.join(pkgDir, 'index.js'); + const unwatchedPkgFile = path.join(pkgDir, 'other.js'); + const rootFile = path.join(tempDir, 'main.ts'); + fs.writeFileSync(watchedPkgFile, 'export const idx = 1;'); + fs.writeFileSync(unwatchedPkgFile, 'export const other = 1;'); + fs.writeFileSync(rootFile, 'export const main = 1;'); + + const pastTime = new Date(Date.now() - 5000); + fs.utimesSync(watchedPkgFile, pastTime, pastTime); + fs.utimesSync(unwatchedPkgFile, pastTime, pastTime); + fs.utimesSync(rootFile, pastTime, pastTime); + + const watcher = await createWatcher({ + followSymlinks: true, + cwd: tempDir, + }); + + try { + // Watch both the root directory and a specific file in node_modules + watcher.add([tempDir, watchedPkgFile]); + await setTimeout(250); + + const iterator = watcher[Symbol.asyncIterator](); + const nextPromise = iterator.next(); + + // Modify unwatched file in node_modules (should be ignored even though tempDir is watched) + // and watched file in node_modules + fs.writeFileSync(unwatchedPkgFile, 'export const other = 2;'); + fs.writeFileSync(watchedPkgFile, 'export const idx = 2;'); + + const result = await nextPromise; + expect(result.done).toBeFalsy(); + const changed = result.value?.all ?? []; + expect(changed.some((f: string) => f.includes('index.js'))).toBeTrue(); + expect(changed.some((f: string) => f.includes('other.js'))).toBeFalse(); + } finally { + await watcher.close(); + } + }, 10000); }); describe('ParcelExternalManager', () => { From 0608ebf8992bc11b43dfb8b042e9322f8b6bdd87 Mon Sep 17 00:00:00 2001 From: Shuaib Hasan Akib <48770016+MeAkib@users.noreply.github.com> Date: Fri, 16 Oct 2026 22:25:25 +0600 Subject: [PATCH 49/52] docs(@schematics/angular): correct `directory` and `entryFile` option descriptions The `ng new` `directory` option claimed the workspace is created in the current directory when the option is omitted, but a new directory named after the workspace is created instead. The library `entryFile` option described a path relative to the workspace root, but the value is a file name without the `.ts` extension that is placed in the library's `src` directory. --- packages/schematics/angular/library/schema.json | 2 +- packages/schematics/angular/ng-new/schema.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/schematics/angular/library/schema.json b/packages/schematics/angular/library/schema.json index bb3d227e5245..02c6c6f8acaa 100644 --- a/packages/schematics/angular/library/schema.json +++ b/packages/schematics/angular/library/schema.json @@ -19,7 +19,7 @@ "entryFile": { "type": "string", "format": "path", - "description": "The path to the library's public API file, relative to the workspace root. This file defines what parts of the library are accessible to applications that import it.", + "description": "The name of the library's public API file, without the `.ts` extension, created in the library's `src` directory. This file defines what parts of the library are accessible to applications that import it.", "default": "public-api" }, "prefix": { diff --git a/packages/schematics/angular/ng-new/schema.json b/packages/schematics/angular/ng-new/schema.json index 257628fcda9e..2c69fa84aaad 100644 --- a/packages/schematics/angular/ng-new/schema.json +++ b/packages/schematics/angular/ng-new/schema.json @@ -8,7 +8,7 @@ "properties": { "directory": { "type": "string", - "description": "The directory where the new workspace and project should be created. If not specified, the workspace will be created in the current directory." + "description": "The directory where the new workspace and project should be created. If not specified, the workspace will be created in a subfolder within the current directory, using the workspace's name." }, "name": { "description": "The name for the new workspace and the initial project. This name will be used for the root directory and various identifiers throughout the project.", From 490a6fe2f1938ea3da5299dabf3a41dec4ef8399 Mon Sep 17 00:00:00 2001 From: MeAkib Date: Fri, 16 Oct 2026 00:09:22 +0600 Subject: [PATCH 50/52] fix(@schematics/angular): show routing module suffixes in `findModule` error When only routing modules are found, the error message printed the optional `routingModuleExt` parameter, which no schematic passes, so users saw "Modules with suffix 'undefined' are strictly reserved for routing.". Since 0b7d48c7ca the lookup checks both `-routing-module.ts` and `-routing.module.ts`, so list the suffixes that are actually used. --- packages/schematics/angular/utility/find-module.ts | 2 +- packages/schematics/angular/utility/find-module_spec.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/schematics/angular/utility/find-module.ts b/packages/schematics/angular/utility/find-module.ts index c98b52a0cbe2..e6ad0c5620e6 100644 --- a/packages/schematics/angular/utility/find-module.ts +++ b/packages/schematics/angular/utility/find-module.ts @@ -117,7 +117,7 @@ export function findModule( const errorMsg = foundRoutingModule ? 'Could not find a non Routing NgModule.' + - `\nModules with suffix '${routingModuleExt}' are strictly reserved for routing.` + + `\nModules with suffix '${routingModuleExtensions.join("' or '")}' are strictly reserved for routing.` + `\nUse the '--skip-import' option to skip importing in NgModule.` : `Could not find an NgModule. Use the '--skip-import' option to skip importing in NgModule.`; diff --git a/packages/schematics/angular/utility/find-module_spec.ts b/packages/schematics/angular/utility/find-module_spec.ts index 0db295ae384f..dcc8a7df057e 100644 --- a/packages/schematics/angular/utility/find-module_spec.ts +++ b/packages/schematics/angular/utility/find-module_spec.ts @@ -56,6 +56,9 @@ describe('find-module', () => { expect(() => findModule(host, 'foo/src/app/anything-routing')).toThrowError( /Could not find a non Routing NgModule/, ); + expect(() => findModule(host, 'foo/src/app/anything-routing')).toThrowError( + /Modules with suffix '-routing-module\.ts' or '-routing\.module\.ts' are strictly reserved/, + ); }); it('should throw if two modules found', () => { From c1cfe8f48059e2d48731cf933f8f407e65466428 Mon Sep 17 00:00:00 2001 From: MeAkib Date: Fri, 16 Oct 2026 00:11:22 +0600 Subject: [PATCH 51/52] docs(@angular/build): include component templates in dev-server `hmr` description The `hmr` option description stated that only global and component stylesheets are supported. Component template hot replacement is also enabled by default when HMR is active, so list templates alongside the supported stylesheets. --- packages/angular/build/src/builders/dev-server/schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/angular/build/src/builders/dev-server/schema.json b/packages/angular/build/src/builders/dev-server/schema.json index 023478ff7e52..3517d3098887 100644 --- a/packages/angular/build/src/builders/dev-server/schema.json +++ b/packages/angular/build/src/builders/dev-server/schema.json @@ -91,7 +91,7 @@ }, "hmr": { "type": "boolean", - "description": "Enable hot module replacement. Defaults to the value of 'liveReload'. Currently, only global and component stylesheets are supported." + "description": "Enable hot module replacement. Defaults to the value of 'liveReload'. Currently, global stylesheets, component stylesheets, and component templates are supported." }, "watch": { "type": "boolean", From 9469dcddedb931251a9883d9f82142c8fffc56f2 Mon Sep 17 00:00:00 2001 From: Angular Robot Date: Fri, 16 Oct 2026 06:47:17 +0000 Subject: [PATCH 52/52] build: update dependency node to v24.22.0 See associated pull request for more information. --- .nvmrc | 2 +- MODULE.bazel | 20 ++++++++++---------- MODULE.bazel.lock | 3 +++ 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/.nvmrc b/.nvmrc index df6ae3370f9f..a43a5b943d99 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -24.21.0 +24.22.0 diff --git a/MODULE.bazel b/MODULE.bazel index f81a41dd6522..69ddf30cdb73 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -40,15 +40,15 @@ git_override( node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node") node.toolchain( node_repositories = { - "24.21.0-darwin_arm64": ("node-v24.21.0-darwin-arm64.tar.gz", "node-v24.21.0-darwin-arm64", "bed7eea5325e1108f32ce5228ddd6a5f0f08a499ee42aa7442aea583702f6057"), - "24.21.0-darwin_amd64": ("node-v24.21.0-darwin-x64.tar.gz", "node-v24.21.0-darwin-x64", "1462cb3b3046b815cf8ea436d3da450ec1a9f11dac7e5a46b0ada5305d7e8097"), - "24.21.0-linux_arm64": ("node-v24.21.0-linux-arm64.tar.xz", "node-v24.21.0-linux-arm64", "6ad1325edbdb5649c379b75a237147a666c95d4f9ae8d340fef2d1575d289ad2"), - "24.21.0-linux_ppc64le": ("node-v24.21.0-linux-ppc64le.tar.xz", "node-v24.21.0-linux-ppc64le", "1936fd64623a2f98d1fb31b456686d10c30e92639899cfefdefa8835d22adccd"), - "24.21.0-linux_s390x": ("node-v24.21.0-linux-s390x.tar.xz", "node-v24.21.0-linux-s390x", "2ef7e2ecbf7a6c2f3d08d106f6b2f279419c6dac89fe91b8cad193af7890082c"), - "24.21.0-linux_amd64": ("node-v24.21.0-linux-x64.tar.xz", "node-v24.21.0-linux-x64", "fd8e59d5a511510f6a298afb548f18c7d2b1be404d8b4a27d94fbe49f56cb2d6"), - "24.21.0-windows_amd64": ("node-v24.21.0-win-x64.zip", "node-v24.21.0-win-x64", "158f7685b44de51f6c0df1d153526cbcd3e1bc739a8dfc607721cef75de9e541"), + "24.22.0-darwin_arm64": ("node-v24.22.0-darwin-arm64.tar.gz", "node-v24.22.0-darwin-arm64", "6a9724d9b50a5f22b4816cded441b5a8d9ddae546191a5e5b7efa5a5e2ee26d5"), + "24.22.0-darwin_amd64": ("node-v24.22.0-darwin-x64.tar.gz", "node-v24.22.0-darwin-x64", "495e3f273c645f3c4677d438304cdfc701729ea5dec5728f5c8e76a2dece4b91"), + "24.22.0-linux_arm64": ("node-v24.22.0-linux-arm64.tar.xz", "node-v24.22.0-linux-arm64", "fef00bb4d36e1c50104a9775a10359beee98f162b4104dd12472c75065c6a143"), + "24.22.0-linux_ppc64le": ("node-v24.22.0-linux-ppc64le.tar.xz", "node-v24.22.0-linux-ppc64le", "edfc950d84a74b4fb4fedc8d2a569976682f6bbbf182961a4e916b7aad856013"), + "24.22.0-linux_s390x": ("node-v24.22.0-linux-s390x.tar.xz", "node-v24.22.0-linux-s390x", "ee3a16f7700188d62cd87b50fde39f8cbd8ab82f25611114e5ed6ef00d914431"), + "24.22.0-linux_amd64": ("node-v24.22.0-linux-x64.tar.xz", "node-v24.22.0-linux-x64", "cc2f601cee82d9a5a233302fe307abc600727035fd7d2c3a3571755989e95008"), + "24.22.0-windows_amd64": ("node-v24.22.0-win-x64.zip", "node-v24.22.0-win-x64", "f9683a19877e12a9b167305c8db71040d812876359de21f0d2e97c3f321f80c3"), }, - node_version = "24.21.0", + node_version = "24.22.0", ) use_repo( node, @@ -131,8 +131,8 @@ use_repo( pnpm = use_extension("@aspect_rules_js//npm:extensions.bzl", "pnpm") pnpm.pnpm( name = "pnpm", - pnpm_version = "12.3.4", - pnpm_version_integrity = "sha512-lhqkH7B32joEpEHZ+OFevAyW2o73ELLrZ7+e58sGEOq9SPH9hfUc/+c4RnhfoPh8VqOocqHYk/hEZ0G1zORUVw==", + pnpm_version = "12.11.2", + pnpm_version_integrity = "sha512-JaUWUqGWeFr18ovabf6NxYLr76SsHRgCIc4TkCMcX7dmN4IupLbkYzznSs3LCnf3Ja8RutOBd/3t2u6BipVcuQ==", ) use_repo(pnpm, "pnpm") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 4cb3f4cc542f..ec705b4eb497 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -1069,6 +1069,9 @@ } }, "facts": { + "@@aspect_rules_js+//npm:extensions.bzl%pnpm": { + "exe:12.11.2": "{\"darwin-arm64\":\"sha512-n9M4On66y8FDxUAKgMO1FXt0qihyG4e+56p3/F0uo8Bx9KplW8BwKVnXigzCJ8aNM6sVVPkOE6M9XXbeVIxnZA==\",\"darwin-x64\":\"sha512-oSW7n3sBT0c0cyk4kj10T2Y6Mpm+OFEiCAWozgX039tdoI6yqJF1uaFD3sw7ugLdu6VV3+uY0pa1TUZIPdxDWA==\",\"linux-arm64\":\"sha512-6e8ZAQUwFXAWHHHv5FesWqf/kEK04wuitBv5f/gxzkC0DiBfaixr+f+6JQede8SF4Ji5LcMwVFJbzAtffpWxEg==\",\"linux-arm64-musl\":\"sha512-uMEYDwKRktGwANubQ+kYCwmhNwg3Ik6qK89ahsbQ5cP30R/5FVJb/T99vr9XRUBC/A7mZI6eeT92oyVas9ACyg==\",\"linux-x64\":\"sha512-FK7QKe24AYgppJwO3mpooYptduuvIGqKJPi5ac7MdnWkjUy46JBfYhCW0grnkWKC8YOf0x+vGviuQqJEj3SpQQ==\",\"linux-x64-musl\":\"sha512-7eIxQR05fvJxCujUSKp5KTtehJ7QqrgqP/HD1+BcB/SaV2Be4XI1PEHiOgA1zxsiMIeMvTF6E4G4dYHrFjeXRg==\",\"win32-arm64\":\"sha512-PCTjVDdJb6VvraZxrEeFv6EqEA0hhIsAySx28e95J2Tqpi88hLpgOXgNqV0vpxq9A+b8GLQfyk/D+1UlJPv/YQ==\",\"win32-x64\":\"sha512-8sgX86OvRjJ3yZs/TvGR2L31wH9ScPZ+f+geKI3ikuB0RRiK3i4LlTRO8OXN6pdRqj8epMde4312MCjj7JsJdA==\"}" + }, "@@aspect_tools_telemetry+//:extension.bzl%telemetry": { "notice_version": "3" }