From 725b252b49dfa769c406ca789e183147a7357445 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Mon, 18 Aug 2025 08:19:15 +0000 Subject: [PATCH] refactor: remove version 20 migrations This commit remove the non optional migrations for version 20 as these have already been executed. --- .../migrations/migration-collection.json | 24 +-- .../previous-style-guide/migration.ts | 51 ------- .../previous-style-guide/migration_spec.ts | 141 ------------------ .../migration.ts | 111 -------------- .../migration_spec.ts | 91 ----------- .../migration.ts | 119 --------------- .../migration_spec.ts | 113 -------------- .../update-module-resolution/migration.ts | 60 -------- .../migration_spec.ts | 118 --------------- 9 files changed, 2 insertions(+), 826 deletions(-) delete mode 100644 packages/schematics/angular/migrations/previous-style-guide/migration.ts delete mode 100644 packages/schematics/angular/migrations/previous-style-guide/migration_spec.ts delete mode 100644 packages/schematics/angular/migrations/replace-provide-server-rendering-import/migration.ts delete mode 100644 packages/schematics/angular/migrations/replace-provide-server-rendering-import/migration_spec.ts delete mode 100644 packages/schematics/angular/migrations/replace-provide-server-routing/migration.ts delete mode 100644 packages/schematics/angular/migrations/replace-provide-server-routing/migration_spec.ts delete mode 100644 packages/schematics/angular/migrations/update-module-resolution/migration.ts delete mode 100644 packages/schematics/angular/migrations/update-module-resolution/migration_spec.ts diff --git a/packages/schematics/angular/migrations/migration-collection.json b/packages/schematics/angular/migrations/migration-collection.json index ec0311d27d97..36e6fba7a631 100644 --- a/packages/schematics/angular/migrations/migration-collection.json +++ b/packages/schematics/angular/migrations/migration-collection.json @@ -1,27 +1,7 @@ { "schematics": { - "replace-provide-server-rendering-import": { - "version": "20.0.0", - "factory": "./replace-provide-server-rendering-import/migration", - "description": "Migrate imports of 'provideServerRendering' from '@angular/platform-server' to '@angular/ssr'." - }, - "replace-provide-server-routing": { - "version": "20.0.0", - "factory": "./replace-provide-server-routing/migration", - "description": "Migrate 'provideServerRendering' to use 'withRoutes', and remove 'provideServerRouting' and 'provideServerRoutesConfig' from '@angular/ssr'." - }, - "update-module-resolution": { - "version": "20.0.0", - "factory": "./update-module-resolution/migration", - "description": "Update 'moduleResolution' to 'bundler' in TypeScript configurations. You can read more about this, here: https://www.typescriptlang.org/tsconfig/#moduleResolution" - }, - "previous-style-guide": { - "version": "20.0.0", - "factory": "./previous-style-guide/migration", - "description": "Update workspace generation defaults to maintain previous style guide behavior." - }, "use-application-builder": { - "version": "20.0.0", + "version": "21.0.0", "factory": "./use-application-builder/migration", "description": "Migrate application projects to the new build system. Application projects that are using the '@angular-devkit/build-angular' package's 'browser' and/or 'browser-esbuild' builders will be migrated to use the new 'application' builder. You can read more about this, including known issues and limitations, here: https://angular.dev/tools/cli/build-system-migration", "optional": true, @@ -29,7 +9,7 @@ "documentation": "tools/cli/build-system-migration" }, "remove-default-karma-config": { - "version": "20.2.0", + "version": "21.0.0", "factory": "./karma/migration", "description": "Remove any karma configuration files that only contain the default content. The default configuration is automatically available without a specific project file." } diff --git a/packages/schematics/angular/migrations/previous-style-guide/migration.ts b/packages/schematics/angular/migrations/previous-style-guide/migration.ts deleted file mode 100644 index 1590948b243d..000000000000 --- a/packages/schematics/angular/migrations/previous-style-guide/migration.ts +++ /dev/null @@ -1,51 +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 type { Rule } from '@angular-devkit/schematics'; -import { updateWorkspace } from '../../utility/workspace'; - -const TYPE_SCHEMATICS = ['component', 'directive', 'service'] as const; - -const SEPARATOR_SCHEMATICS = ['guard', 'interceptor', 'module', 'pipe', 'resolver'] as const; - -export default function (): Rule { - return updateWorkspace((workspace) => { - let schematicsDefaults = workspace.extensions['schematics']; - - // Ensure "schematics" field is an object - if ( - !schematicsDefaults || - typeof schematicsDefaults !== 'object' || - Array.isArray(schematicsDefaults) - ) { - schematicsDefaults = workspace.extensions['schematics'] = {}; - } - - // Add "type" value for each schematic to continue generating a type suffix. - // New default is an empty type value. - for (const schematicName of TYPE_SCHEMATICS) { - const schematic = (schematicsDefaults[`@schematics/angular:${schematicName}`] ??= {}); - if (typeof schematic === 'object' && !Array.isArray(schematic) && !('type' in schematic)) { - schematic['type'] = schematicName; - } - } - - // Add "typeSeparator" value for each schematic to continue generating "." before type. - // New default is an "-" type value. - for (const schematicName of SEPARATOR_SCHEMATICS) { - const schematic = (schematicsDefaults[`@schematics/angular:${schematicName}`] ??= {}); - if ( - typeof schematic === 'object' && - !Array.isArray(schematic) && - !('typeSeparator' in schematic) - ) { - schematic['typeSeparator'] = '.'; - } - } - }); -} diff --git a/packages/schematics/angular/migrations/previous-style-guide/migration_spec.ts b/packages/schematics/angular/migrations/previous-style-guide/migration_spec.ts deleted file mode 100644 index 342da3910e74..000000000000 --- a/packages/schematics/angular/migrations/previous-style-guide/migration_spec.ts +++ /dev/null @@ -1,141 +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 { EmptyTree } from '@angular-devkit/schematics'; -import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; -import { ProjectType, WorkspaceSchema } from '../../utility/workspace-models'; - -function createWorkSpaceConfig(tree: UnitTestTree, initialSchematicsValue?: unknown) { - const angularConfig: WorkspaceSchema = { - version: 1, - projects: { - app: { - root: '/project/lib', - sourceRoot: '/project/app/src', - projectType: ProjectType.Application, - prefix: 'app', - architect: {}, - }, - }, - }; - - if (initialSchematicsValue !== undefined) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (angularConfig as any).schematics = initialSchematicsValue; - } - - tree.create('/angular.json', JSON.stringify(angularConfig, undefined, 2)); -} - -describe(`Migration to update 'angular.json'.`, () => { - const schematicName = 'previous-style-guide'; - const schematicRunner = new SchematicTestRunner( - 'migrations', - require.resolve('../migration-collection.json'), - ); - - let tree: UnitTestTree; - beforeEach(() => { - tree = new UnitTestTree(new EmptyTree()); - }); - - it(`should add defaults if no "schematics" workspace field is present`, async () => { - createWorkSpaceConfig(tree); - - const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); - const { schematics } = JSON.parse(newTree.readContent('/angular.json')); - - expect(schematics).toEqual({ - '@schematics/angular:component': { type: 'component' }, - '@schematics/angular:directive': { type: 'directive' }, - '@schematics/angular:service': { type: 'service' }, - '@schematics/angular:guard': { typeSeparator: '.' }, - '@schematics/angular:interceptor': { typeSeparator: '.' }, - '@schematics/angular:module': { typeSeparator: '.' }, - '@schematics/angular:pipe': { typeSeparator: '.' }, - '@schematics/angular:resolver': { typeSeparator: '.' }, - }); - }); - - it(`should add defaults if empty "schematics" workspace field is present`, async () => { - createWorkSpaceConfig(tree, {}); - - const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); - const { schematics } = JSON.parse(newTree.readContent('/angular.json')); - - expect(schematics).toEqual({ - '@schematics/angular:component': { type: 'component' }, - '@schematics/angular:directive': { type: 'directive' }, - '@schematics/angular:service': { type: 'service' }, - '@schematics/angular:guard': { typeSeparator: '.' }, - '@schematics/angular:interceptor': { typeSeparator: '.' }, - '@schematics/angular:module': { typeSeparator: '.' }, - '@schematics/angular:pipe': { typeSeparator: '.' }, - '@schematics/angular:resolver': { typeSeparator: '.' }, - }); - }); - - it(`should add defaults if invalid "schematics" workspace field is present`, async () => { - createWorkSpaceConfig(tree, 10); - - const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); - const { schematics } = JSON.parse(newTree.readContent('/angular.json')); - - expect(schematics).toEqual({ - '@schematics/angular:component': { type: 'component' }, - '@schematics/angular:directive': { type: 'directive' }, - '@schematics/angular:service': { type: 'service' }, - '@schematics/angular:guard': { typeSeparator: '.' }, - '@schematics/angular:interceptor': { typeSeparator: '.' }, - '@schematics/angular:module': { typeSeparator: '.' }, - '@schematics/angular:pipe': { typeSeparator: '.' }, - '@schematics/angular:resolver': { typeSeparator: '.' }, - }); - }); - - it(`should add defaults if existing unrelated "schematics" workspace defaults are present`, async () => { - createWorkSpaceConfig(tree, { - '@schematics/angular:component': { style: 'scss' }, - }); - - const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); - const { schematics } = JSON.parse(newTree.readContent('/angular.json')); - - expect(schematics).toEqual({ - '@schematics/angular:component': { style: 'scss', type: 'component' }, - '@schematics/angular:directive': { type: 'directive' }, - '@schematics/angular:service': { type: 'service' }, - '@schematics/angular:guard': { typeSeparator: '.' }, - '@schematics/angular:interceptor': { typeSeparator: '.' }, - '@schematics/angular:module': { typeSeparator: '.' }, - '@schematics/angular:pipe': { typeSeparator: '.' }, - '@schematics/angular:resolver': { typeSeparator: '.' }, - }); - }); - - it(`should not overwrite defaults if existing "schematics" workspace defaults are present`, async () => { - createWorkSpaceConfig(tree, { - '@schematics/angular:component': { type: 'example' }, - '@schematics/angular:guard': { typeSeparator: '-' }, - }); - - const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); - const { schematics } = JSON.parse(newTree.readContent('/angular.json')); - - expect(schematics).toEqual({ - '@schematics/angular:component': { type: 'example' }, - '@schematics/angular:directive': { type: 'directive' }, - '@schematics/angular:service': { type: 'service' }, - '@schematics/angular:guard': { typeSeparator: '-' }, - '@schematics/angular:interceptor': { typeSeparator: '.' }, - '@schematics/angular:module': { typeSeparator: '.' }, - '@schematics/angular:pipe': { typeSeparator: '.' }, - '@schematics/angular:resolver': { typeSeparator: '.' }, - }); - }); -}); diff --git a/packages/schematics/angular/migrations/replace-provide-server-rendering-import/migration.ts b/packages/schematics/angular/migrations/replace-provide-server-rendering-import/migration.ts deleted file mode 100644 index 05b2f5fb6ff4..000000000000 --- a/packages/schematics/angular/migrations/replace-provide-server-rendering-import/migration.ts +++ /dev/null @@ -1,111 +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 { DirEntry, Rule } from '@angular-devkit/schematics'; -import ts from '../../third_party/github.com/Microsoft/TypeScript/lib/typescript'; -import { addDependency } from '../../utility/dependency'; -import { latestVersions } from '../../utility/latest-versions'; - -function* visit(directory: DirEntry): IterableIterator<[fileName: string, contents: string]> { - for (const path of directory.subfiles) { - if (path.endsWith('.ts') && !path.endsWith('.d.ts')) { - const entry = directory.file(path); - if (entry) { - const content = entry.content; - if ( - content.includes('provideServerRendering') && - content.includes('@angular/platform-server') - ) { - // Only need to rename the import so we can just string replacements. - yield [entry.path, content.toString()]; - } - } - } - } - - for (const path of directory.subdirs) { - if (path === 'node_modules' || path.startsWith('.')) { - continue; - } - - yield* visit(directory.dir(path)); - } -} - -export default function (): Rule { - return async (tree) => { - let rule: Rule | undefined; - - for (const [filePath, content] of visit(tree.root)) { - let updatedContent = content; - const ssrImports = new Set(); - const platformServerImports = new Set(); - const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true); - - sourceFile.forEachChild((node) => { - if (ts.isImportDeclaration(node)) { - const moduleSpecifier = node.moduleSpecifier.getText(sourceFile); - if (moduleSpecifier.includes('@angular/platform-server')) { - const importClause = node.importClause; - if ( - importClause && - importClause.namedBindings && - ts.isNamedImports(importClause.namedBindings) - ) { - const namedImports = importClause.namedBindings.elements.map((e) => - e.getText(sourceFile), - ); - namedImports.forEach((importName) => { - if (importName === 'provideServerRendering') { - ssrImports.add(importName); - } else { - platformServerImports.add(importName); - } - }); - } - updatedContent = updatedContent.replace(node.getFullText(sourceFile), ''); - } else if (moduleSpecifier.includes('@angular/ssr')) { - const importClause = node.importClause; - if ( - importClause && - importClause.namedBindings && - ts.isNamedImports(importClause.namedBindings) - ) { - importClause.namedBindings.elements.forEach((e) => { - ssrImports.add(e.getText(sourceFile)); - }); - } - updatedContent = updatedContent.replace(node.getFullText(sourceFile), ''); - } - } - }); - - if (platformServerImports.size > 0) { - updatedContent = - `import { ${Array.from(platformServerImports).sort().join(', ')} } from '@angular/platform-server';\n` + - updatedContent; - } - - if (ssrImports.size > 0) { - updatedContent = - `import { ${Array.from(ssrImports).sort().join(', ')} } from '@angular/ssr';\n` + - updatedContent; - } - - if (content !== updatedContent) { - tree.overwrite(filePath, updatedContent); - - if (rule === undefined) { - rule = addDependency('@angular/ssr', latestVersions.AngularSSR); - } - } - } - - return rule; - }; -} diff --git a/packages/schematics/angular/migrations/replace-provide-server-rendering-import/migration_spec.ts b/packages/schematics/angular/migrations/replace-provide-server-rendering-import/migration_spec.ts deleted file mode 100644 index 6746172882fb..000000000000 --- a/packages/schematics/angular/migrations/replace-provide-server-rendering-import/migration_spec.ts +++ /dev/null @@ -1,91 +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 { EmptyTree } from '@angular-devkit/schematics'; -import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; - -describe(`Migration to use the 'provideServerRendering' from '@angular/ssr'`, () => { - const schematicRunner = new SchematicTestRunner( - 'migrations', - require.resolve('../migration-collection.json'), - ); - - let tree: UnitTestTree; - const schematicName = 'replace-provide-server-rendering-import'; - - beforeEach(() => { - tree = new UnitTestTree(new EmptyTree()); - tree.create( - '/package.json', - JSON.stringify({ - dependencies: {}, - }), - ); - }); - - it('should replace provideServerRendering with @angular/ssr and keep other imports', async () => { - tree.create( - 'test.ts', - `import { provideServerRendering, otherFunction } from '@angular/platform-server';`, - ); - const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); - const content = newTree.readContent('test.ts'); - expect(content).toContain("import { provideServerRendering } from '@angular/ssr';"); - expect(content).toContain("import { otherFunction } from '@angular/platform-server';"); - }); - - it('should not replace provideServerRendering that is imported from @angular/ssr', async () => { - tree.create( - 'test.ts', - ` - import { otherFunction } from '@angular/platform-server'; - import { provideServerRendering, provideServerRouting } from '@angular/ssr'; - `, - ); - const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); - const content = newTree.readContent('test.ts'); - expect(content).toContain( - "import { provideServerRendering, provideServerRouting } from '@angular/ssr';", - ); - expect(content).toContain("import { otherFunction } from '@angular/platform-server';"); - }); - - it('should merge with existing @angular/ssr imports', async () => { - tree.create( - 'test.ts', - ` - import { provideServerRouting } from '@angular/ssr'; - import { provideServerRendering } from '@angular/platform-server'; - `, - ); - const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); - const content = newTree.readContent('test.ts'); - expect(content).toContain( - "import { provideServerRendering, provideServerRouting } from '@angular/ssr';", - ); - expect(content.match(/@angular\/ssr/g) || []).toHaveSize(1); - }); - - it(`should add '@angular/ssr' when import has been changed`, async () => { - tree.create('test.ts', `import { provideServerRendering } from '@angular/platform-server';`); - const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); - const { dependencies } = newTree.readJson('package.json') as { - dependencies: Record; - }; - expect(dependencies['@angular/ssr']).toBeDefined(); - }); - - it(`should not add '@angular/ssr' dependency if no imports have been updated`, async () => { - tree.create('test.ts', `import { provideClientHydration } from '@angular/platform-browser';`); - const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); - const { dependencies } = newTree.readJson('package.json') as { - dependencies: Record; - }; - expect(dependencies['@angular/ssr']).toBeUndefined(); - }); -}); diff --git a/packages/schematics/angular/migrations/replace-provide-server-routing/migration.ts b/packages/schematics/angular/migrations/replace-provide-server-routing/migration.ts deleted file mode 100644 index 8b0510aee62b..000000000000 --- a/packages/schematics/angular/migrations/replace-provide-server-routing/migration.ts +++ /dev/null @@ -1,119 +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 { DirEntry, Rule } from '@angular-devkit/schematics'; -import * as ts from '../../third_party/github.com/Microsoft/TypeScript/lib/typescript'; -import { getPackageJsonDependency } from '../../utility/dependencies'; - -function* visit(directory: DirEntry): IterableIterator<[fileName: string, contents: string]> { - for (const path of directory.subfiles) { - if (path.endsWith('.ts') && !path.endsWith('.d.ts')) { - const entry = directory.file(path); - if (entry) { - const content = entry.content; - if ( - (content.includes('provideServerRouting') || - content.includes('provideServerRoutesConfig')) && - content.includes('@angular/ssr') - ) { - // Only need to rename the import so we can just string replacements. - yield [entry.path, content.toString()]; - } - } - } - } - - for (const path of directory.subdirs) { - if (path === 'node_modules' || path.startsWith('.')) { - continue; - } - - yield* visit(directory.dir(path)); - } -} - -export default function (): Rule { - return async (tree) => { - if (!getPackageJsonDependency(tree, '@angular/ssr')) { - return; - } - - for (const [filePath, content] of visit(tree.root)) { - const recorder = tree.beginUpdate(filePath); - const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true); - - function visit(node: ts.Node) { - if ( - ts.isPropertyAssignment(node) && - ts.isIdentifier(node.name) && - node.name.text === 'providers' && - ts.isArrayLiteralExpression(node.initializer) - ) { - const providersArray = node.initializer; - const newProviders = providersArray.elements - .filter((el) => { - return !( - ts.isCallExpression(el) && - ts.isIdentifier(el.expression) && - el.expression.text === 'provideServerRendering' - ); - }) - .map((el) => { - if ( - ts.isCallExpression(el) && - ts.isIdentifier(el.expression) && - (el.expression.text === 'provideServerRouting' || - el.expression.text === 'provideServerRoutesConfig') - ) { - const [withRouteVal, ...others] = el.arguments.map((arg) => arg.getText()); - - return `provideServerRendering(withRoutes(${withRouteVal})${others.length ? ', ' + others.join(', ') : ''})`; - } - - return el.getText(); - }); - - // Update the 'providers' array in the source file - recorder.remove(providersArray.getStart(), providersArray.getWidth()); - recorder.insertRight(providersArray.getStart(), `[${newProviders.join(', ')}]`); - } - - ts.forEachChild(node, visit); - } - - // Visit all nodes to update 'providers' - visit(sourceFile); - - // Update imports by removing 'provideServerRouting' - const importDecl = sourceFile.statements.find( - (stmt) => - ts.isImportDeclaration(stmt) && - ts.isStringLiteral(stmt.moduleSpecifier) && - stmt.moduleSpecifier.text === '@angular/ssr', - ) as ts.ImportDeclaration | undefined; - - if (importDecl?.importClause?.namedBindings) { - const namedBindings = importDecl?.importClause.namedBindings; - - if (ts.isNamedImports(namedBindings)) { - const elements = namedBindings.elements; - const updatedElements = elements - .map((el) => el.getText()) - .filter((x) => x !== 'provideServerRouting' && x !== 'provideServerRoutesConfig'); - - updatedElements.push('withRoutes'); - - recorder.remove(namedBindings.getStart(), namedBindings.getWidth()); - recorder.insertLeft(namedBindings.getStart(), `{ ${updatedElements.sort().join(', ')} }`); - } - } - - tree.commitUpdate(recorder); - } - }; -} diff --git a/packages/schematics/angular/migrations/replace-provide-server-routing/migration_spec.ts b/packages/schematics/angular/migrations/replace-provide-server-routing/migration_spec.ts deleted file mode 100644 index c570ea81c077..000000000000 --- a/packages/schematics/angular/migrations/replace-provide-server-routing/migration_spec.ts +++ /dev/null @@ -1,113 +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 { EmptyTree } from '@angular-devkit/schematics'; -import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; - -describe(`Migration to replace 'provideServerRouting' with 'provideServerRendering' from '@angular/ssr'`, () => { - const schematicRunner = new SchematicTestRunner( - 'migrations', - require.resolve('../migration-collection.json'), - ); - - const schematicName = 'replace-provide-server-routing'; - let tree: UnitTestTree; - - beforeEach(async () => { - tree = new UnitTestTree(new EmptyTree()); - tree.create( - '/package.json', - JSON.stringify({ - dependencies: { - '@angular/ssr': '0.0.0', - }, - }), - ); - - tree.create( - 'src/app/app.config.ts', - ` - import { ApplicationConfig } from '@angular/core'; - import { provideServerRendering, provideServerRouting } from '@angular/ssr'; - import { serverRoutes } from './app.routes'; - - const serverConfig: ApplicationConfig = { - providers: [ - provideServerRendering(), - provideServerRouting(serverRoutes) - ] - }; - `, - ); - }); - - it('should add "withRoutes" to the import statement', async () => { - const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); - const content = newTree.readContent('src/app/app.config.ts'); - - expect(content).toContain(`import { provideServerRendering, withRoutes } from '@angular/ssr';`); - }); - - it('should remove "provideServerRouting" and update "provideServerRendering"', async () => { - const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); - const content = newTree.readContent('src/app/app.config.ts'); - - expect(content).toContain(`providers: [provideServerRendering(withRoutes(serverRoutes))]`); - expect(content).not.toContain(`provideServerRouting(serverRoutes)`); - }); - - it('should remove "provideServerRoutesConfig" and update "provideServerRendering"', async () => { - tree.overwrite( - 'src/app/app.config.ts', - ` - import { ApplicationConfig } from '@angular/core'; - import { provideServerRendering, provideServerRoutesConfig } from '@angular/ssr'; - import { serverRoutes } from './app.routes'; - - const serverConfig: ApplicationConfig = { - providers: [ - provideServerRendering(), - provideServerRoutesConfig(serverRoutes) - ] - }; - `, - ); - - const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); - const content = newTree.readContent('src/app/app.config.ts'); - - expect(content).toContain(`providers: [provideServerRendering(withRoutes(serverRoutes))]`); - expect(content).not.toContain(`provideServerRoutesConfig(serverRoutes)`); - }); - - it('should correctly handle provideServerRouting with extra arguments', async () => { - tree.overwrite( - 'src/app/app.config.ts', - ` - import { ApplicationConfig } from '@angular/core'; - import { provideServerRendering, provideServerRouting } from '@angular/ssr'; - import { serverRoutes } from './app.routes'; - - const serverConfig: ApplicationConfig = { - providers: [ - provideServerRendering(), - provideServerRouting(serverRoutes, withAppShell(AppShellComponent)) - ] - }; - `, - ); - - const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); - const content = newTree.readContent('src/app/app.config.ts'); - - expect(content).toContain( - `providers: [provideServerRendering(withRoutes(serverRoutes), withAppShell(AppShellComponent))]`, - ); - expect(content).not.toContain(`provideServerRouting(serverRoutes)`); - }); -}); diff --git a/packages/schematics/angular/migrations/update-module-resolution/migration.ts b/packages/schematics/angular/migrations/update-module-resolution/migration.ts deleted file mode 100644 index ca0419a4eeab..000000000000 --- a/packages/schematics/angular/migrations/update-module-resolution/migration.ts +++ /dev/null @@ -1,60 +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 { JsonObject } from '@angular-devkit/core'; -import { Rule, Tree } from '@angular-devkit/schematics'; -import { JSONFile } from '../../utility/json-file'; -import { allTargetOptions, allWorkspaceTargets, getWorkspace } from '../../utility/workspace'; - -export default function (): Rule { - return async (host) => { - const uniqueTsConfigs = new Set(); - - if (host.exists('tsconfig.json')) { - // Workspace level tsconfig - uniqueTsConfigs.add('tsconfig.json'); - } - - const workspace = await getWorkspace(host); - for (const [, target] of allWorkspaceTargets(workspace)) { - for (const [, opt] of allTargetOptions(target)) { - if (typeof opt?.tsConfig === 'string') { - uniqueTsConfigs.add(opt.tsConfig); - } - } - } - - for (const tsConfig of uniqueTsConfigs) { - if (host.exists(tsConfig)) { - updateModuleResolution(host, tsConfig); - } - } - }; -} - -function updateModuleResolution(host: Tree, tsConfigPath: string): void { - const json = new JSONFile(host, tsConfigPath); - const jsonPath = ['compilerOptions']; - const compilerOptions = json.get(jsonPath); - - if (compilerOptions && typeof compilerOptions === 'object') { - const { moduleResolution, module } = compilerOptions as JsonObject; - if (typeof moduleResolution !== 'string' || moduleResolution.toLowerCase() === 'bundler') { - return; - } - - if (typeof module === 'string' && module.toLowerCase() === 'preserve') { - return; - } - - json.modify(jsonPath, { - ...compilerOptions, - 'moduleResolution': 'bundler', - }); - } -} diff --git a/packages/schematics/angular/migrations/update-module-resolution/migration_spec.ts b/packages/schematics/angular/migrations/update-module-resolution/migration_spec.ts deleted file mode 100644 index 53448e80b66a..000000000000 --- a/packages/schematics/angular/migrations/update-module-resolution/migration_spec.ts +++ /dev/null @@ -1,118 +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 { isJsonObject } from '@angular-devkit/core'; -import { EmptyTree } from '@angular-devkit/schematics'; -import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; -import { Builders, ProjectType, WorkspaceSchema } from '../../utility/workspace-models'; - -describe('Migration to update moduleResolution', () => { - const schematicName = 'update-module-resolution'; - const schematicRunner = new SchematicTestRunner( - 'migrations', - require.resolve('../migration-collection.json'), - ); - - function createJsonFile(tree: UnitTestTree, filePath: string, content: {}): void { - const stringifiedContent = JSON.stringify(content, undefined, 2); - if (tree.exists(filePath)) { - tree.overwrite(filePath, stringifiedContent); - } else { - tree.create(filePath, stringifiedContent); - } - } - - function getCompilerOptionsValue(tree: UnitTestTree, filePath: string): Record { - const json = tree.readJson(filePath); - if (isJsonObject(json) && isJsonObject(json.compilerOptions)) { - return json.compilerOptions; - } - - throw new Error(`Cannot retrieve 'compilerOptions'.`); - } - - const angularConfig: WorkspaceSchema = { - version: 1, - projects: { - app: { - root: '', - sourceRoot: 'src', - projectType: ProjectType.Application, - prefix: 'app', - architect: { - build: { - builder: Builders.Browser, - options: { - tsConfig: 'src/tsconfig.app.json', - main: '', - polyfills: '', - }, - configurations: { - production: { - tsConfig: 'src/tsconfig.app.prod.json', - }, - }, - }, - test: { - builder: Builders.Karma, - options: { - karmaConfig: '', - tsConfig: 'src/tsconfig.spec.json', - }, - }, - }, - }, - }, - }; - - let tree: UnitTestTree; - beforeEach(() => { - tree = new UnitTestTree(new EmptyTree()); - const compilerOptions = { module: 'es2020', moduleResolution: 'node' }; - const configWithExtends = { extends: './tsconfig.json', compilerOptions }; - - // Workspace - createJsonFile(tree, 'angular.json', angularConfig); - createJsonFile(tree, 'tsconfig.json', { compilerOptions }); - - // Application - createJsonFile(tree, 'src/tsconfig.app.json', configWithExtends); - createJsonFile(tree, 'src/tsconfig.app.prod.json', configWithExtends); - createJsonFile(tree, 'src/tsconfig.spec.json', { compilerOptions }); - }); - - it(`should update moduleResolution to 'bundler' in workspace 'tsconfig.json'`, async () => { - const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); - const compilerOptions = getCompilerOptionsValue(newTree, 'tsconfig.json'); - expect(compilerOptions).toEqual( - jasmine.objectContaining({ - moduleResolution: 'bundler', - }), - ); - }); - - it(`should update moduleResolution to 'bundler' in builder tsconfig`, async () => { - const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); - const compilerOptions = getCompilerOptionsValue(newTree, 'src/tsconfig.spec.json'); - expect(compilerOptions).toEqual( - jasmine.objectContaining({ - moduleResolution: 'bundler', - }), - ); - }); - - it('should not update moduleResolution when module is preserve', async () => { - createJsonFile(tree, 'tsconfig.json', { - compilerOptions: { module: 'preserve', moduleResolution: 'node' }, - }); - - const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); - const compilerOptions = getCompilerOptionsValue(newTree, 'tsconfig.json'); - expect(compilerOptions).toEqual({ module: 'preserve', moduleResolution: 'node' }); - }); -});