diff --git a/.github/workflows/dev-infra.yml b/.github/workflows/dev-infra.yml index 79c2f4854902..7f5b0b413c2c 100644 --- a/.github/workflows/dev-infra.yml +++ b/.github/workflows/dev-infra.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: angular/dev-infra/github-actions/commit-message-based-labels@6f44591738d6f0374148fffc723788c62e5cb775 + - uses: angular/dev-infra/github-actions/pull-request-labeling@3a765b303ce300f607b658abd4eb8a981bc7277f with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} post_approval_changes: diff --git a/.ng-dev/dx-perf-workflows.yml b/.ng-dev/dx-perf-workflows.yml index 21c8b95acff3..70960ff760db 100644 --- a/.ng-dev/dx-perf-workflows.yml +++ b/.ng-dev/dx-perf-workflows.yml @@ -19,24 +19,24 @@ workflows: prepare: - bazel clean workflow: - - bazel test //packages/ngtools/webpack:webpack_test + - bazel test //packages/ngtools/webpack:test devkit-core-tests: name: '@angular/devkit/core tests' prepare: - bazel clean workflow: - - bazel test //packages/angular_devkit/core:core_test + - bazel test //packages/angular_devkit/core:test devkit-core-tests-rerun: name: '@angular/devkit/core return test' prepare: - bazel clean workflow: - - bazel test //packages/angular_devkit/core:core_test + - bazel test //packages/angular_devkit/core:test # Add a single line to the beginning of a file to trigger a rebuild/retest - sed -i '1i // comment' packages/angular_devkit/core/src/workspace/core_spec.ts - - bazel test //packages/angular_devkit/core:core_test + - bazel test //packages/angular_devkit/core:test cleanup: # Remove the single line added - sed -i '1d' packages/angular_devkit/core/src/workspace/core_spec.ts @@ -46,4 +46,4 @@ workflows: prepare: - bazel clean workflow: - - bazel test //packages/angular/build:unit_tests + - bazel test //packages/angular/build:test diff --git a/CHANGELOG.md b/CHANGELOG.md index 503b2567d3fc..80c0e6ef7771 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ + + +# 20.0.2 (2025-06-11) + +### @schematics/angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------------------------------- | +| [bf64a0f2d](https://github.com/angular/angular-cli/commit/bf64a0f2dcc2cbd5dc56e575dd337c16f2a3342b) | fix | add `less` as a devDependency when selected as the style preprocessor | +| [cb258a3e1](https://github.com/angular/angular-cli/commit/cb258a3e1525cda985109692fb88449259119ff2) | fix | correctly detect modules using new file extension format | + +### @angular/build + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ---------------------------------------------------------- | +| [424f1cbbf](https://github.com/angular/angular-cli/commit/424f1cbbfb709b4d6f480e6321ec1a152813cf5c) | fix | do not consider internal Angular files as external imports | + + + # 20.0.1 (2025-06-04) diff --git a/modules/testing/builder/BUILD.bazel b/modules/testing/builder/BUILD.bazel index 9814ad27811d..154f494af35f 100644 --- a/modules/testing/builder/BUILD.bazel +++ b/modules/testing/builder/BUILD.bazel @@ -45,6 +45,6 @@ ts_project( ) jasmine_test( - name = "unit_test", + name = "test", data = [":unit_test_lib"], ) diff --git a/package.json b/package.json index d21b5262a7a8..b5190c6e0a7a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "20.0.1", + "version": "20.0.2", "private": true, "description": "Software Development Kit for Angular", "keywords": [ diff --git a/packages/angular/build/BUILD.bazel b/packages/angular/build/BUILD.bazel index de157d169bbb..8762ac9e3880 100644 --- a/packages/angular/build/BUILD.bazel +++ b/packages/angular/build/BUILD.bazel @@ -162,7 +162,7 @@ ts_project( ) jasmine_test( - name = "unit_tests", + name = "test", data = [":unit_test_lib"], ) diff --git a/packages/angular/build/src/tools/esbuild/bundler-context.ts b/packages/angular/build/src/tools/esbuild/bundler-context.ts index 9b722e41640e..864ca2c6fdd9 100644 --- a/packages/angular/build/src/tools/esbuild/bundler-context.ts +++ b/packages/angular/build/src/tools/esbuild/bundler-context.ts @@ -366,6 +366,7 @@ export class BundlerContext { if ( !external || SERVER_GENERATED_EXTERNALS.has(path) || + isInternalAngularFile(path) || (kind !== 'import-statement' && kind !== 'dynamic-import' && kind !== 'require-call') ) { continue; diff --git a/packages/angular/cli/BUILD.bazel b/packages/angular/cli/BUILD.bazel index efa8d5f601f0..e06af1316a27 100644 --- a/packages/angular/cli/BUILD.bazel +++ b/packages/angular/cli/BUILD.bazel @@ -117,7 +117,7 @@ ts_project( ) jasmine_test( - name = "angular-cli_test", + name = "test", data = [":angular-cli_test_lib"], ) diff --git a/packages/angular/pwa/BUILD.bazel b/packages/angular/pwa/BUILD.bazel index 4fc36b05adc6..6072cdd88d51 100644 --- a/packages/angular/pwa/BUILD.bazel +++ b/packages/angular/pwa/BUILD.bazel @@ -58,7 +58,7 @@ ts_project( ) jasmine_test( - name = "pwa_test", + name = "test", data = [":pwa_test_lib"], ) diff --git a/packages/angular/ssr/schematics/BUILD.bazel b/packages/angular/ssr/schematics/BUILD.bazel index 34d4cb1591ec..b0d2d0b9cbd8 100644 --- a/packages/angular/ssr/schematics/BUILD.bazel +++ b/packages/angular/ssr/schematics/BUILD.bazel @@ -83,7 +83,7 @@ ts_project( ) jasmine_test( - name = "ssr_schematics_test", + name = "test", data = [ ":schematics_assets", ":ssr_schematics_test_lib", diff --git a/packages/angular_devkit/architect/BUILD.bazel b/packages/angular_devkit/architect/BUILD.bazel index b724096e4219..f76e44f93f9d 100644 --- a/packages/angular_devkit/architect/BUILD.bazel +++ b/packages/angular_devkit/architect/BUILD.bazel @@ -88,7 +88,7 @@ ts_project( ) jasmine_test( - name = "architect_test", + name = "test", data = [":architect_test_lib"], ) diff --git a/packages/angular_devkit/architect/node/BUILD.bazel b/packages/angular_devkit/architect/node/BUILD.bazel index 8cdaa1c72049..fad21dd46480 100644 --- a/packages/angular_devkit/architect/node/BUILD.bazel +++ b/packages/angular_devkit/architect/node/BUILD.bazel @@ -42,6 +42,6 @@ ts_project( ) jasmine_test( - name = "node_test", + name = "test", data = [":node_test_lib"], ) diff --git a/packages/angular_devkit/build_angular/BUILD.bazel b/packages/angular_devkit/build_angular/BUILD.bazel index 40884c857ee2..c4c283676ec4 100644 --- a/packages/angular_devkit/build_angular/BUILD.bazel +++ b/packages/angular_devkit/build_angular/BUILD.bazel @@ -235,7 +235,7 @@ ts_project( ) jasmine_test( - name = "build_angular_test", + name = "test", data = [":build_angular_test_lib"], ) diff --git a/packages/angular_devkit/core/BUILD.bazel b/packages/angular_devkit/core/BUILD.bazel index dc27e8e3f5c1..93892ecc3e2c 100644 --- a/packages/angular_devkit/core/BUILD.bazel +++ b/packages/angular_devkit/core/BUILD.bazel @@ -59,7 +59,7 @@ ts_project( ) jasmine_test( - name = "core_test", + name = "test", data = [":core_test_lib"], ) diff --git a/packages/angular_devkit/core/node/BUILD.bazel b/packages/angular_devkit/core/node/BUILD.bazel index a023a861589c..83e49baecd78 100644 --- a/packages/angular_devkit/core/node/BUILD.bazel +++ b/packages/angular_devkit/core/node/BUILD.bazel @@ -47,6 +47,6 @@ ts_project( ) jasmine_test( - name = "node_test", + name = "test", data = [":node_test_lib"], ) diff --git a/packages/angular_devkit/schematics/BUILD.bazel b/packages/angular_devkit/schematics/BUILD.bazel index d4376bc57d4a..0b1d0e0f781b 100644 --- a/packages/angular_devkit/schematics/BUILD.bazel +++ b/packages/angular_devkit/schematics/BUILD.bazel @@ -48,7 +48,7 @@ ts_project( ) jasmine_test( - name = "schematics_test", + name = "test", data = [":schematics_test_lib"], ) diff --git a/packages/angular_devkit/schematics/tools/BUILD.bazel b/packages/angular_devkit/schematics/tools/BUILD.bazel index 84d3bd9d8e54..f1b13a40ea77 100644 --- a/packages/angular_devkit/schematics/tools/BUILD.bazel +++ b/packages/angular_devkit/schematics/tools/BUILD.bazel @@ -52,6 +52,6 @@ ts_project( ) jasmine_test( - name = "tools_test", + name = "test", data = [":tools_test_lib"], ) diff --git a/packages/angular_devkit/schematics_cli/test/BUILD.bazel b/packages/angular_devkit/schematics_cli/test/BUILD.bazel index d75151c168ac..29eb34e8b7ea 100644 --- a/packages/angular_devkit/schematics_cli/test/BUILD.bazel +++ b/packages/angular_devkit/schematics_cli/test/BUILD.bazel @@ -21,7 +21,7 @@ npm_link_package( ) jasmine_test( - name = "schematics_cli_test", + name = "test", data = [ ":schematics_cli_test_lib", # The npm package itself is needed for the test at runtime, so we diff --git a/packages/ngtools/webpack/BUILD.bazel b/packages/ngtools/webpack/BUILD.bazel index 1a5b8b0b486d..eb75d42a0185 100644 --- a/packages/ngtools/webpack/BUILD.bazel +++ b/packages/ngtools/webpack/BUILD.bazel @@ -56,7 +56,7 @@ ts_project( ) jasmine_test( - name = "webpack_test", + name = "test", data = [ ":webpack_test_lib", # Needed at runtime for runtime TS compilations performed by tests. diff --git a/packages/schematics/angular/BUILD.bazel b/packages/schematics/angular/BUILD.bazel index 0e5ba72fed90..57887c2cf63d 100644 --- a/packages/schematics/angular/BUILD.bazel +++ b/packages/schematics/angular/BUILD.bazel @@ -138,7 +138,7 @@ ts_project( ) jasmine_test( - name = "angular_test", + name = "test", data = [":angular_test_lib"], ) diff --git a/packages/schematics/angular/application/index.ts b/packages/schematics/angular/application/index.ts index 14c0688cf334..ce8c83b2871f 100644 --- a/packages/schematics/angular/application/index.ts +++ b/packages/schematics/angular/application/index.ts @@ -49,12 +49,12 @@ function addTsProjectReference(...paths: string[]) { } export default function (options: ApplicationOptions): Rule { - return async (host: Tree, context: SchematicContext) => { + return async (host: Tree) => { const { appDir, appRootSelector, componentOptions, folderName, sourceDir } = await getAppOptions(host, options); return chain([ - addAppToWorkspaceFile(options, appDir, folderName), + addAppToWorkspaceFile(options, appDir), addTsProjectReference('./' + join(normalize(appDir), 'tsconfig.app.json')), options.skipTests || options.minimal ? noop() @@ -157,6 +157,14 @@ function addDependenciesToPackageJson(options: ApplicationOptions) { }); } + if (options.style === Style.Less) { + addPackageJsonDependency(host, { + type: NodeDependencyType.Dev, + name: 'less', + version: latestVersions['less'], + }); + } + if (!options.skipInstall) { context.addTask(new NodePackageInstallTask()); } @@ -165,11 +173,7 @@ function addDependenciesToPackageJson(options: ApplicationOptions) { }; } -function addAppToWorkspaceFile( - options: ApplicationOptions, - appDir: string, - folderName: string, -): Rule { +function addAppToWorkspaceFile(options: ApplicationOptions, appDir: string): Rule { let projectRoot = appDir; if (projectRoot) { projectRoot += '/'; diff --git a/packages/schematics/angular/application/index_spec.ts b/packages/schematics/angular/application/index_spec.ts index 60700c9f45ff..6db8671aabb6 100644 --- a/packages/schematics/angular/application/index_spec.ts +++ b/packages/schematics/angular/application/index_spec.ts @@ -282,6 +282,20 @@ describe('Application Schematic', () => { expect(pkg.dependencies['zone.js']).toEqual(latestVersions['zone.js']); }); + it('should add "less" to devDependencies when Less is selected as the style option', async () => { + const tree = await schematicRunner.runSchematic( + 'application', + { + ...defaultOptions, + style: Style.Less, + }, + workspaceTree, + ); + + const pkg = JSON.parse(tree.readContent('/package.json')); + expect(pkg.devDependencies['less']).toEqual(latestVersions['less']); + }); + it('should include zone.js if "zoneless" option is not present', async () => { const tree = await schematicRunner.runSchematic( 'application', diff --git a/packages/schematics/angular/component/index.ts b/packages/schematics/angular/component/index.ts index acbb82fadca6..359aa28fa94e 100644 --- a/packages/schematics/angular/component/index.ts +++ b/packages/schematics/angular/component/index.ts @@ -53,16 +53,7 @@ export default function (options: ComponentOptions): Rule { options.path = buildDefaultPath(project); } - try { - options.module = findModuleFromOptions(host, options); - } catch { - options.module = findModuleFromOptions(host, { - ...options, - moduleExt: '-module.ts', - routingModuleExt: '-routing-module.ts', - }); - } - + options.module = findModuleFromOptions(host, options); // Schematic templates require a defined type value options.type ??= ''; diff --git a/packages/schematics/angular/directive/index.ts b/packages/schematics/angular/directive/index.ts index e05c64ca9e5b..77d68d2e3073 100644 --- a/packages/schematics/angular/directive/index.ts +++ b/packages/schematics/angular/directive/index.ts @@ -38,15 +38,7 @@ export default function (options: DirectiveOptions): Rule { options.path = buildDefaultPath(project); } - try { - options.module = findModuleFromOptions(host, options); - } catch { - options.module = findModuleFromOptions(host, { - ...options, - moduleExt: '-module.ts', - routingModuleExt: '-routing-module.ts', - }); - } + options.module = findModuleFromOptions(host, options); const parsedPath = parseName(options.path, options.name); options.name = parsedPath.name; options.path = parsedPath.path; diff --git a/packages/schematics/angular/module/index.ts b/packages/schematics/angular/module/index.ts index f7657783d866..1a6065fedf95 100644 --- a/packages/schematics/angular/module/index.ts +++ b/packages/schematics/angular/module/index.ts @@ -27,7 +27,9 @@ import { addImportToModule, addRouteDeclarationToModule } from '../utility/ast-u import { InsertChange } from '../utility/change'; import { MODULE_EXT, + MODULE_EXT_LEGACY, ROUTING_MODULE_EXT, + ROUTING_MODULE_EXT_LEGACY, buildRelativePath, findModuleFromOptions, } from '../utility/find-module'; @@ -114,11 +116,11 @@ function addRouteDeclarationToNgModule( function getRoutingModulePath(host: Tree, modulePath: string): string | undefined { const routingModulePath = - modulePath.endsWith(ROUTING_MODULE_EXT) || modulePath.endsWith('-routing-module.ts') + modulePath.endsWith(ROUTING_MODULE_EXT_LEGACY) || modulePath.endsWith(ROUTING_MODULE_EXT) ? modulePath : modulePath - .replace(MODULE_EXT, ROUTING_MODULE_EXT) - .replace('-module.ts', '-routing-module.ts'); + .replace(MODULE_EXT_LEGACY, ROUTING_MODULE_EXT_LEGACY) + .replace(MODULE_EXT, ROUTING_MODULE_EXT); return host.exists(routingModulePath) ? routingModulePath : undefined; } @@ -138,15 +140,7 @@ export default function (options: ModuleOptions): Rule { } if (options.module) { - try { - options.module = findModuleFromOptions(host, options); - } catch { - options.module = findModuleFromOptions(host, { - ...options, - moduleExt: '-module.ts', - routingModuleExt: '-routing-module.ts', - }); - } + options.module = findModuleFromOptions(host, options); } let routingModulePath; diff --git a/packages/schematics/angular/pipe/index.ts b/packages/schematics/angular/pipe/index.ts index 150b0bc20c57..e266839cbcc2 100644 --- a/packages/schematics/angular/pipe/index.ts +++ b/packages/schematics/angular/pipe/index.ts @@ -18,16 +18,7 @@ import { Schema as PipeOptions } from './schema'; export default function (options: PipeOptions): Rule { return async (host: Tree) => { options.path ??= await createDefaultPath(host, options.project); - try { - options.module = findModuleFromOptions(host, options); - } catch { - options.module = findModuleFromOptions(host, { - ...options, - moduleExt: '-module.ts', - routingModuleExt: '-routing-module.ts', - }); - } - + options.module = findModuleFromOptions(host, options); const parsedPath = parseName(options.path, options.name); options.name = parsedPath.name; options.path = parsedPath.path; diff --git a/packages/schematics/angular/utility/find-module.ts b/packages/schematics/angular/utility/find-module.ts index 69e10dc1368e..c98b52a0cbe2 100644 --- a/packages/schematics/angular/utility/find-module.ts +++ b/packages/schematics/angular/utility/find-module.ts @@ -20,8 +20,10 @@ export interface ModuleOptions { standalone?: boolean; } -export const MODULE_EXT = '.module.ts'; -export const ROUTING_MODULE_EXT = '-routing.module.ts'; +export const MODULE_EXT = '-module.ts'; +export const ROUTING_MODULE_EXT = '-routing-module.ts'; +export const MODULE_EXT_LEGACY = '.module.ts'; +export const ROUTING_MODULE_EXT_LEGACY = '-routing.module.ts'; /** * Find the module referred by a set of options passed to the schematics. @@ -31,13 +33,10 @@ export function findModuleFromOptions(host: Tree, options: ModuleOptions): Path return undefined; } - const moduleExt = options.moduleExt || MODULE_EXT; - const routingModuleExt = options.routingModuleExt || ROUTING_MODULE_EXT; - if (!options.module) { const pathToCheck = (options.path || '') + '/' + options.name; - return normalize(findModule(host, pathToCheck, moduleExt, routingModuleExt)); + return normalize(findModule(host, pathToCheck, options.moduleExt, options.routingModuleExt)); } else { const modulePath = normalize(`/${options.path}/${options.module}`); const componentPath = normalize(`/${options.path}/${options.name}`); @@ -53,14 +52,21 @@ export function findModuleFromOptions(host: Tree, options: ModuleOptions): Path } const candidatesDirs = [...candidateSet].sort((a, b) => b.length - a.length); - for (const c of candidatesDirs) { - const candidateFiles = ['', `${moduleBaseName}.ts`, `${moduleBaseName}${moduleExt}`].map( - (x) => join(c, x), + const candidateFiles: string[] = ['', `${moduleBaseName}.ts`]; + if (options.moduleExt) { + candidateFiles.push(`${moduleBaseName}${options.moduleExt}`); + } else { + candidateFiles.push( + `${moduleBaseName}${MODULE_EXT}`, + `${moduleBaseName}${MODULE_EXT_LEGACY}`, ); + } + for (const c of candidatesDirs) { for (const sc of candidateFiles) { - if (host.exists(sc) && host.readText(sc).includes('@NgModule')) { - return normalize(sc); + const scPath = join(c, sc); + if (host.exists(scPath) && host.readText(scPath).includes('@NgModule')) { + return normalize(scPath); } } } @@ -78,15 +84,22 @@ export function findModuleFromOptions(host: Tree, options: ModuleOptions): Path export function findModule( host: Tree, generateDir: string, - moduleExt = MODULE_EXT, - routingModuleExt = ROUTING_MODULE_EXT, + moduleExt?: string, + routingModuleExt?: string, ): Path { let dir: DirEntry | null = host.getDir('/' + generateDir); let foundRoutingModule = false; + const moduleExtensions: string[] = moduleExt ? [moduleExt] : [MODULE_EXT, MODULE_EXT_LEGACY]; + const routingModuleExtensions: string[] = routingModuleExt + ? [routingModuleExt] + : [ROUTING_MODULE_EXT, ROUTING_MODULE_EXT_LEGACY]; + while (dir) { - const allMatches = dir.subfiles.filter((p) => p.endsWith(moduleExt)); - const filteredMatches = allMatches.filter((p) => !p.endsWith(routingModuleExt)); + const allMatches = dir.subfiles.filter((p) => moduleExtensions.some((m) => p.endsWith(m))); + const filteredMatches = allMatches.filter( + (p) => !routingModuleExtensions.some((m) => p.endsWith(m)), + ); foundRoutingModule = foundRoutingModule || allMatches.length !== filteredMatches.length; diff --git a/packages/schematics/angular/utility/find-module_spec.ts b/packages/schematics/angular/utility/find-module_spec.ts index 9680f15949c8..0db295ae384f 100644 --- a/packages/schematics/angular/utility/find-module_spec.ts +++ b/packages/schematics/angular/utility/find-module_spec.ts @@ -143,6 +143,15 @@ describe('find-module', () => { expect(modPath).toEqual('/projects/my-proj/src/admin/foo.module.ts'); }); + it('should find a module in a sub dir when using the `-module` suffix', () => { + tree.create('/projects/my-proj/src/admin/foo-module.ts', '@NgModule'); + options.name = 'other/test'; + options.module = 'admin/foo'; + options.path = '/projects/my-proj/src'; + const modPath = findModuleFromOptions(tree, options) as string; + expect(modPath).toEqual('/projects/my-proj/src/admin/foo-module.ts'); + }); + it('should find a module in a sub dir (2)', () => { tree.create('/projects/my-proj/src/admin/foo.module.ts', '@NgModule'); options.name = 'admin/hello'; diff --git a/tools/baseline_browserslist/BUILD.bazel b/tools/baseline_browserslist/BUILD.bazel index 34141cd15759..7680d4e021d0 100644 --- a/tools/baseline_browserslist/BUILD.bazel +++ b/tools/baseline_browserslist/BUILD.bazel @@ -32,7 +32,7 @@ ts_project( ) jasmine_test( - name = "baseline_browserslist_test", + name = "test", data = [":baseline_browserslist_test_lib"], ) diff --git a/tools/defaults.bzl b/tools/defaults.bzl index 18f7f0d5fdc0..cde6f8c43dd6 100644 --- a/tools/defaults.bzl +++ b/tools/defaults.bzl @@ -65,9 +65,10 @@ def jasmine_test(data = [], args = [], **kwargs): chdir = native.package_name(), args = [ "--require=%s/node_modules/source-map-support/register.js" % relative_to_root, - "**/*spec.js", - "**/*spec.mjs", - "**/*spec.cjs", + # Escape so that the `js_binary` launcher triggers Bash expansion. + "'**/*+(.|_)spec.js'", + "'**/*+(.|_)spec.mjs'", + "'**/*+(.|_)spec.cjs'", ] + args, data = data + ["//:node_modules/source-map-support"], **kwargs