diff --git a/libs/components/packages/src/schematics/migrations/migration-collection.json b/libs/components/packages/src/schematics/migrations/migration-collection.json index 8fb3507c91..a475bd8d78 100644 --- a/libs/components/packages/src/schematics/migrations/migration-collection.json +++ b/libs/components/packages/src/schematics/migrations/migration-collection.json @@ -5,40 +5,15 @@ "factory": "./noop/noop.schematic", "description": "Update all SKY UX component packages" }, - "update-angular-tree-component": { - "version": "9.0.0-0", - "factory": "./update-9/update-angular-tree-component/update-angular-tree-component.schematic", - "description": "Update the Angular tree component package to point to the Blackbaud forked version" - }, - "add-forms-popovers-peer-dependency": { - "version": "9.0.0-0", - "factory": "./update-9/add-forms-popovers-peer-dependency/add-forms-popovers-peer-dependency.schematic", - "description": "Add @skyux/popovers peer dependency for @skyux/forms" - }, "add-compat-stylesheets": { - "version": "9.0.0-0", - "factory": "./update-9/add-compat-stylesheets/add-compat-stylesheet.schematic", - "description": "Add a backwards-compatible stylesheet with styles that have been removed from components in SKY UX 9." - }, - "ag-grid-29": { - "version": "9.0.0-0", - "factory": "./update-9/ag-grid-29/ag-grid-29.schematic", - "description": "Apply changes to support AG Grid 29" - }, - "legacy-services": { - "version": "9.0.0-0", - "factory": "./update-9/legacy-services/legacy-services.schematic", - "description": "Modal and flyout services were previously provided in 'any' but are now provided in 'root'. Replace with a 'legacy' version for backward compatibility." + "version": "10.0.0-0", + "factory": "./update-10/add-compat-stylesheets/add-compat-stylesheet.schematic", + "description": "Add a backwards-compatible stylesheet with styles that have been removed from components in SKY UX 10." }, "i18n-resources-module": { - "version": "9.0.0-0", - "factory": "./update-9/i18n-resources-module/i18n-resources-module.schematic", + "version": "10.0.0-0", + "factory": "./update-10/i18n-resources-module/i18n-resources-module.schematic", "description": "Regenerate i18n resources modules for libraries." - }, - "move-page-component": { - "version": "9.0.0-0", - "factory": "./update-9/move-page-component/move-page-component.schematic", - "description": "Move SkyPageComponent from @skyux/layout to @skyux/pages." } } } diff --git a/libs/components/packages/src/schematics/migrations/update-9/add-compat-stylesheets/__snapshots__/add-compat-stylesheet.schematic.spec.ts.snap b/libs/components/packages/src/schematics/migrations/update-10/add-compat-stylesheets/__snapshots__/add-compat-stylesheet.schematic.spec.ts.snap similarity index 54% rename from libs/components/packages/src/schematics/migrations/update-9/add-compat-stylesheets/__snapshots__/add-compat-stylesheet.schematic.spec.ts.snap rename to libs/components/packages/src/schematics/migrations/update-10/add-compat-stylesheets/__snapshots__/add-compat-stylesheet.schematic.spec.ts.snap index 4d4acf76fe..023ca9405e 100644 --- a/libs/components/packages/src/schematics/migrations/update-9/add-compat-stylesheets/__snapshots__/add-compat-stylesheet.schematic.spec.ts.snap +++ b/libs/components/packages/src/schematics/migrations/update-10/add-compat-stylesheets/__snapshots__/add-compat-stylesheet.schematic.spec.ts.snap @@ -13,34 +13,16 @@ exports[`Migrations > Add compat stylesheets should add a compat stylesheet for * angular.json file. *******************************************************************************/ -/******************************************************************************* - * COMPONENT: INPUT BOX - *******************************************************************************/ - -/******************************************************************************* - * The bottom margin has been removed from the \`sky-input-box\`. To address - * this, remove this block of CSS and use \`stacked="true"\` to automatically - * have the latest vertical spacing added. - *******************************************************************************/ - -:root { - --sky-compat-sky-form-group-margin-bottom: 10px -} - /******************************************************************************* * COMPONENT: STYLES *******************************************************************************/ /******************************************************************************* - * The bottom margin has been removed from \`sky-form-group\` style class. To - * address this, remove this block of css and change \`sky-form-group\` to - * \`sky-margin-stacked-sm\` or other appropriate spacing classes. See - * https://developer.blackbaud.com/skyux/design/styles/spacing for a list of - * supported spacing classes. + * This is an example and should be removed. *******************************************************************************/ :root { - --sky-compat-sky-form-group-margin-bottom: 10px + --sky-compat-example: 0; } " `; @@ -58,34 +40,16 @@ exports[`Migrations > Add compat stylesheets should add a compat stylesheet for * angular.json file. *******************************************************************************/ -/******************************************************************************* - * COMPONENT: INPUT BOX - *******************************************************************************/ - -/******************************************************************************* - * The bottom margin has been removed from the \`sky-input-box\`. To address - * this, remove this block of CSS and use \`stacked="true"\` to automatically - * have the latest vertical spacing added. - *******************************************************************************/ - -:root { - --sky-compat-sky-form-group-margin-bottom: 10px -} - /******************************************************************************* * COMPONENT: STYLES *******************************************************************************/ /******************************************************************************* - * The bottom margin has been removed from \`sky-form-group\` style class. To - * address this, remove this block of css and change \`sky-form-group\` to - * \`sky-margin-stacked-sm\` or other appropriate spacing classes. See - * https://developer.blackbaud.com/skyux/design/styles/spacing for a list of - * supported spacing classes. + * This is an example and should be removed. *******************************************************************************/ :root { - --sky-compat-sky-form-group-margin-bottom: 10px + --sky-compat-example: 0; } " `; @@ -103,34 +67,16 @@ exports[`Migrations > Add compat stylesheets should handle missing styles array * angular.json file. *******************************************************************************/ -/******************************************************************************* - * COMPONENT: INPUT BOX - *******************************************************************************/ - -/******************************************************************************* - * The bottom margin has been removed from the \`sky-input-box\`. To address - * this, remove this block of CSS and use \`stacked="true"\` to automatically - * have the latest vertical spacing added. - *******************************************************************************/ - -:root { - --sky-compat-sky-form-group-margin-bottom: 10px -} - /******************************************************************************* * COMPONENT: STYLES *******************************************************************************/ /******************************************************************************* - * The bottom margin has been removed from \`sky-form-group\` style class. To - * address this, remove this block of css and change \`sky-form-group\` to - * \`sky-margin-stacked-sm\` or other appropriate spacing classes. See - * https://developer.blackbaud.com/skyux/design/styles/spacing for a list of - * supported spacing classes. + * This is an example and should be removed. *******************************************************************************/ :root { - --sky-compat-sky-form-group-margin-bottom: 10px + --sky-compat-example: 0; } " `; @@ -148,34 +94,16 @@ exports[`Migrations > Add compat stylesheets should overwrite an existing compat * angular.json file. *******************************************************************************/ -/******************************************************************************* - * COMPONENT: INPUT BOX - *******************************************************************************/ - -/******************************************************************************* - * The bottom margin has been removed from the \`sky-input-box\`. To address - * this, remove this block of CSS and use \`stacked="true"\` to automatically - * have the latest vertical spacing added. - *******************************************************************************/ - -:root { - --sky-compat-sky-form-group-margin-bottom: 10px -} - /******************************************************************************* * COMPONENT: STYLES *******************************************************************************/ /******************************************************************************* - * The bottom margin has been removed from \`sky-form-group\` style class. To - * address this, remove this block of css and change \`sky-form-group\` to - * \`sky-margin-stacked-sm\` or other appropriate spacing classes. See - * https://developer.blackbaud.com/skyux/design/styles/spacing for a list of - * supported spacing classes. + * This is an example and should be removed. *******************************************************************************/ :root { - --sky-compat-sky-form-group-margin-bottom: 10px + --sky-compat-example: 0; } " `; diff --git a/libs/components/packages/src/schematics/migrations/update-9/add-compat-stylesheets/add-compat-stylesheet.schematic.spec.ts b/libs/components/packages/src/schematics/migrations/update-10/add-compat-stylesheets/add-compat-stylesheet.schematic.spec.ts similarity index 97% rename from libs/components/packages/src/schematics/migrations/update-9/add-compat-stylesheets/add-compat-stylesheet.schematic.spec.ts rename to libs/components/packages/src/schematics/migrations/update-10/add-compat-stylesheets/add-compat-stylesheet.schematic.spec.ts index 559ce6dc6d..5baa816bf4 100644 --- a/libs/components/packages/src/schematics/migrations/update-9/add-compat-stylesheets/add-compat-stylesheet.schematic.spec.ts +++ b/libs/components/packages/src/schematics/migrations/update-10/add-compat-stylesheets/add-compat-stylesheet.schematic.spec.ts @@ -5,7 +5,7 @@ import { join } from 'path'; import { createTestApp, createTestLibrary } from '../../../testing/scaffold'; describe('Migrations > Add compat stylesheets', () => { - const compatStylesheetPath = 'src/app/skyux9-compat.css'; + const compatStylesheetPath = 'src/app/skyux10-compat.css'; const runner = new SchematicTestRunner( 'migrations', @@ -155,7 +155,7 @@ describe('Migrations > Add compat stylesheets', () => { ); const libShowcaseCompatStylesheetPath = - 'projects/my-lib-showcase/src/app/skyux9-compat.css'; + 'projects/my-lib-showcase/src/app/skyux10-compat.css'; angularJson = JSON.parse(updatedTree.readContent('/angular.json')); diff --git a/libs/components/packages/src/schematics/migrations/update-9/add-compat-stylesheets/add-compat-stylesheet.schematic.ts b/libs/components/packages/src/schematics/migrations/update-10/add-compat-stylesheets/add-compat-stylesheet.schematic.ts similarity index 82% rename from libs/components/packages/src/schematics/migrations/update-9/add-compat-stylesheets/add-compat-stylesheet.schematic.ts rename to libs/components/packages/src/schematics/migrations/update-10/add-compat-stylesheets/add-compat-stylesheet.schematic.ts index dc5ca7a8b1..75997a4e84 100644 --- a/libs/components/packages/src/schematics/migrations/update-9/add-compat-stylesheets/add-compat-stylesheet.schematic.ts +++ b/libs/components/packages/src/schematics/migrations/update-10/add-compat-stylesheets/add-compat-stylesheet.schematic.ts @@ -4,29 +4,20 @@ import { Rule, Tree, chain } from '@angular-devkit/schematics'; import { readRequiredFile } from '../../../utility/tree'; import { getWorkspace, updateWorkspace } from '../../../utility/workspace'; -const COMPAT_CSS_FILE_NAME = 'skyux9-compat.css'; +const COMPAT_CSS_FILE_NAME = 'skyux10-compat.css'; + +type CompatStyle = { + libraries: { + name: string; + components: { + name: string; + styles: { css: string; instructions: string }[]; + }[]; + }[]; +}; -const compatStyles = { +const compatStyles: CompatStyle = { libraries: [ - { - name: '@skyux/forms', - components: [ - { - name: 'input box', - styles: [ - { - css: ` -:root { - --sky-compat-sky-form-group-margin-bottom: 10px -} -`, - instructions: ` -The bottom margin has been removed from the \`sky-input-box\`. To address this, remove this block of CSS and use \`stacked="true"\` to automatically have the latest vertical spacing added.`, - }, - ], - }, - ], - }, { name: '@skyux/theme', components: [ @@ -36,11 +27,11 @@ The bottom margin has been removed from the \`sky-input-box\`. To address this, { css: ` :root { - --sky-compat-sky-form-group-margin-bottom: 10px + --sky-compat-example: 0; } `, instructions: ` -The bottom margin has been removed from \`sky-form-group\` style class. To address this, remove this block of css and change \`sky-form-group\` to \`sky-margin-stacked-sm\` or other appropriate spacing classes. See https://developer.blackbaud.com/skyux/design/styles/spacing for a list of supported spacing classes.`, +This is an example and should be removed.`, }, ], }, diff --git a/libs/components/packages/src/schematics/migrations/update-9/i18n-resources-module/i18n-resources-module.schematic.spec.ts b/libs/components/packages/src/schematics/migrations/update-10/i18n-resources-module/i18n-resources-module.schematic.spec.ts similarity index 100% rename from libs/components/packages/src/schematics/migrations/update-9/i18n-resources-module/i18n-resources-module.schematic.spec.ts rename to libs/components/packages/src/schematics/migrations/update-10/i18n-resources-module/i18n-resources-module.schematic.spec.ts diff --git a/libs/components/packages/src/schematics/migrations/update-9/i18n-resources-module/i18n-resources-module.schematic.ts b/libs/components/packages/src/schematics/migrations/update-10/i18n-resources-module/i18n-resources-module.schematic.ts similarity index 100% rename from libs/components/packages/src/schematics/migrations/update-9/i18n-resources-module/i18n-resources-module.schematic.ts rename to libs/components/packages/src/schematics/migrations/update-10/i18n-resources-module/i18n-resources-module.schematic.ts diff --git a/libs/components/packages/src/schematics/migrations/update-9/add-forms-popovers-peer-dependency/add-forms-popovers-peer-dependency.schematic.spec.ts b/libs/components/packages/src/schematics/migrations/update-9/add-forms-popovers-peer-dependency/add-forms-popovers-peer-dependency.schematic.spec.ts deleted file mode 100644 index 8efc89b329..0000000000 --- a/libs/components/packages/src/schematics/migrations/update-9/add-forms-popovers-peer-dependency/add-forms-popovers-peer-dependency.schematic.spec.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; - -import { join } from 'path'; - -import { createTestApp } from '../../../testing/scaffold'; - -describe('Migrations > add forms/popover peer dependency', () => { - const runner = new SchematicTestRunner( - 'migrations', - join(__dirname, '../../migration-collection.json'), - ); - - async function setupTest() { - const tree = await createTestApp(runner, { - projectName: 'my-app', - }); - - return { - runSchematic: () => - runner.runSchematic('add-forms-popovers-peer-dependency', {}, tree), - tree, - }; - } - - it('should add @skyux/popovers if @skyux/forms is installed in dependencies', async () => { - const { runSchematic, tree } = await setupTest(); - - tree.overwrite( - '/package.json', - '{"dependencies": {"@skyux/forms": "9.0.0-alpha.1"}}', - ); - - await runSchematic(); - - expect(tree.readJson('/package.json')).toEqual({ - dependencies: { - '@skyux/forms': '9.0.0-alpha.1', - '@skyux/popovers': '9.0.0-alpha.1', - }, - }); - }); - - it('should add @skyux/popovers if @skyux/forms is installed in devDependencies', async () => { - const { runSchematic, tree } = await setupTest(); - - tree.overwrite( - '/package.json', - '{"devDependencies": {"@skyux/forms": "9.0.0-alpha.1"}}', - ); - - await runSchematic(); - - expect(tree.readJson('/package.json')).toEqual({ - dependencies: { - '@skyux/popovers': '9.0.0-alpha.1', - }, - devDependencies: { - '@skyux/forms': '9.0.0-alpha.1', - }, - }); - }); - - it('should not add @skyux/popovers if @skyux/forms is not installed', async () => { - const { runSchematic, tree } = await setupTest(); - - tree.overwrite('/package.json', '{"dependencies": {}}'); - - await runSchematic(); - - expect(tree.readJson('/package.json')).toEqual({ - dependencies: {}, - }); - }); -}); diff --git a/libs/components/packages/src/schematics/migrations/update-9/add-forms-popovers-peer-dependency/add-forms-popovers-peer-dependency.schematic.ts b/libs/components/packages/src/schematics/migrations/update-9/add-forms-popovers-peer-dependency/add-forms-popovers-peer-dependency.schematic.ts deleted file mode 100644 index 42aecd04dc..0000000000 --- a/libs/components/packages/src/schematics/migrations/update-9/add-forms-popovers-peer-dependency/add-forms-popovers-peer-dependency.schematic.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Rule } from '@angular-devkit/schematics'; -import { NodeDependencyType } from '@schematics/angular/utility/dependencies'; - -import { ensurePeersInstalled } from '../../../rules/ensure-peers-installed'; - -export default function (): Rule { - return ensurePeersInstalled('@skyux/forms', [ - { - matchVersion: true, - name: '@skyux/popovers', - type: NodeDependencyType.Default, - }, - ]); -} diff --git a/libs/components/packages/src/schematics/migrations/update-9/ag-grid-29/ag-grid-29.schematic.spec.ts b/libs/components/packages/src/schematics/migrations/update-9/ag-grid-29/ag-grid-29.schematic.spec.ts deleted file mode 100644 index cc31382488..0000000000 --- a/libs/components/packages/src/schematics/migrations/update-9/ag-grid-29/ag-grid-29.schematic.spec.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { Tree } from '@angular-devkit/schematics'; -import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; -import { JSONFile } from '@schematics/angular/utility/json-file'; - -import { createTestApp, createTestLibrary } from '../../../testing/scaffold'; - -describe('ag-grid-29.schematic', () => { - const runner = new SchematicTestRunner( - 'schematics', - require.resolve('../../migration-collection.json'), - ); - - async function setupTest( - packageJson: { dependencies?: Record } = {}, - build: { options?: { styles: string[] } } = {}, - appOrLib: 'application' | 'library' = 'application', - ): Promise<{ tree: Tree }> { - let tree: Tree; - if (appOrLib === 'application') { - tree = await createTestApp(runner, { projectName: 'test' }); - } else { - tree = await createTestLibrary(runner, { projectName: 'test' }); - } - if (packageJson['dependencies']) { - const packageJsonFile = new JSONFile(tree, 'package.json'); - packageJsonFile.modify(['dependencies'], { - ...(packageJsonFile.get(['dependencies']) || {}), - ...packageJson['dependencies'], - }); - } - if (build['options']) { - const angularJsonFile = new JSONFile(tree, 'angular.json'); - angularJsonFile.modify( - ['projects', 'test', 'architect', 'build', 'options'], - build['options'], - ); - } - return { - tree, - }; - } - - it('should verify css config', async () => { - expect.assertions(1); - const { tree } = await setupTest( - { - dependencies: { - 'ag-grid-community': '0.0.0', - 'ag-grid-angular': '0.0.0', - 'ag-grid-enterprise': '0.0.0', - }, - }, - { - options: { - styles: [ - '@skyux/theme/css/sky.css', - 'ag-grid-community/dist/styles/ag-theme-alpine.css', - ], - }, - }, - ); - const updatedTree = await runner.runSchematic('ag-grid-29', {}, tree); - const workspace = new JSONFile(updatedTree, '/angular.json'); - expect( - workspace.get([ - 'projects', - 'test', - 'architect', - 'build', - 'options', - 'styles', - ]), - ).toEqual([ - '@skyux/theme/css/sky.css', - '@skyux/ag-grid/css/sky-ag-grid.css', - ]); - }); - - it('should do nothing if AG Grid is not installed', async () => { - expect.assertions(1); - const { tree } = await setupTest({ - dependencies: { - other: '27.1.1', - }, - }); - const updatedTree = await runner.runSchematic('ag-grid-29', {}, tree); - const packageJson = new JSONFile(updatedTree, '/package.json'); - expect(packageJson.get(['dependencies', 'other'])).toEqual('27.1.1'); - }); - - it('should do nothing on library build configuration', async () => { - expect.assertions(1); - const { tree } = await setupTest( - { - dependencies: { - 'ag-grid-community': '0.0.0', - 'ag-grid-angular': '0.0.0', - }, - }, - {}, - 'library', - ); - const angularJson = new JSONFile(tree, '/angular.json'); - const beforeConfig = angularJson.get(['projects', 'test', 'architect']); - const updatedTree = await runner.runSchematic('ag-grid-29', {}, tree); - const updatedAngularJson = new JSONFile(updatedTree, '/angular.json'); - expect(updatedAngularJson.get(['projects', 'test', 'architect'])).toEqual( - beforeConfig, - ); - }); - - it('should update selectThisNode', async () => { - const { tree } = await setupTest({ - dependencies: { - 'ag-grid-community': '0.0.0', - 'ag-grid-angular': '0.0.0', - }, - }); - tree.overwrite( - 'src/app/app.component.ts', - ` - export class AppComponent { - public updateCheckbox(column: Column, selected: boolean) { - if (!column.isLockVisible()) { - return this.#row.selectThisNode(selected); - } - } - }`, - ); - tree.create( - 'src/app/no-change.component.ts', - `export class NoChangeComponent {}`, - ); - const updatedTree = await runner.runSchematic('ag-grid-29', {}, tree); - expect(updatedTree.readText('src/app/app.component.ts')) - .toMatchInlineSnapshot(` - " - export class AppComponent { - public updateCheckbox(column: Column, selected: boolean) { - if (!column.getColDef().lockVisible) { - return this.#row.setSelected(selected); - } - } - }" - `); - }); - - it('should update RowNode to use interface', async () => { - const { tree } = await setupTest({ - dependencies: { - 'ag-grid-community': '0.0.0', - 'ag-grid-angular': '0.0.0', - }, - }); - tree.overwrite( - 'src/app/app.component.ts', - ` - import { RowNode } from 'ag-grid-community'; - - export class AppComponent { - public updateRow(row: RowNode) { - const options = { - event: RowNode.EVENT_CELL_CHANGED, - }; - row.addEventListener(RowNode.EVENT_CELL_CHANGED, () => undefined) - } - }`, - ); - tree.create( - 'src/app/no-change.component.ts', - `export class NoChangeComponent {}`, - ); - - // The spec says sourceRoot is optional, so testing a case without it. - const angularJson = new JSONFile(tree, '/angular.json'); - angularJson.remove(['projects', 'test', 'sourceRoot']); - - const updatedTree = await runner.runSchematic('ag-grid-29', {}, tree); - expect(updatedTree.readText('src/app/app.component.ts')) - .toMatchInlineSnapshot(` - " - import { RowNode, IRowNode } from 'ag-grid-community'; - - export class AppComponent { - public updateRow(row: IRowNode) { - const options = { - event: RowNode.EVENT_CELL_CHANGED, - }; - row.addEventListener(RowNode.EVENT_CELL_CHANGED, () => undefined) - } - }" - `); - }); -}); diff --git a/libs/components/packages/src/schematics/migrations/update-9/ag-grid-29/ag-grid-29.schematic.ts b/libs/components/packages/src/schematics/migrations/update-9/ag-grid-29/ag-grid-29.schematic.ts deleted file mode 100644 index ae26dfd023..0000000000 --- a/libs/components/packages/src/schematics/migrations/update-9/ag-grid-29/ag-grid-29.schematic.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { Path } from '@angular-devkit/core'; -import { Rule, Tree, chain } from '@angular-devkit/schematics'; -import ts from '@schematics/angular/third_party/github.com/Microsoft/TypeScript/lib/typescript'; -import { readWorkspace, writeWorkspace } from '@schematics/angular/utility'; -import { - insertImport, - isImported, -} from '@schematics/angular/utility/ast-utils'; -import { - Change, - ReplaceChange, - applyToUpdateRecorder, -} from '@schematics/angular/utility/change'; -import { getPackageJsonDependency } from '@schematics/angular/utility/dependencies'; - -import { visitProjectFiles } from '../../../utility/visit-project-files'; - -const AG_GRID = 'ag-grid-community'; -const AG_GRID_ENT = 'ag-grid-enterprise'; - -/** - * Check package.json for AG Grid dependencies. - */ -function readDependencies(tree: Tree) { - const agGridDependency = getPackageJsonDependency(tree, AG_GRID); - const agGridDependencyEnt = getPackageJsonDependency(tree, AG_GRID_ENT); - return { - agGridDependency, - agGridDependencyEnt, - }; -} - -/** - * Do not import AG Grid themes in angular.json. - */ -function removeAgGridCssFiles(): Rule { - return async (tree: Tree): Promise => { - const workspace = await readWorkspace(tree); - workspace.projects.forEach((project, projectName) => { - ['build', 'test'].forEach((targetName) => { - if ( - targetName === 'build' && - project.extensions['projectType'] === 'library' - ) { - return; - } - const targetDefinition = project.targets.get(targetName); - if ( - targetDefinition?.['options']?.['styles'] && - Array.isArray(targetDefinition.options['styles']) && - targetDefinition.options['styles'].includes( - '@skyux/theme/css/sky.css', - ) - ) { - targetDefinition['options']['styles'] = ( - targetDefinition.options['styles'] as string[] - ).filter( - (cssFile) => !cssFile.startsWith('ag-grid-community/dist/styles/'), - ); - if ( - !targetDefinition.options['styles'].includes( - '@skyux/ag-grid/css/sky-ag-grid.css', - ) && - !targetDefinition.options['styles'].includes( - 'node_modules/@skyux/ag-grid/css/sky-ag-grid.css', - ) - ) { - targetDefinition.options['styles'].push( - '@skyux/ag-grid/css/sky-ag-grid.css', - ); - } - project.targets.set(targetName, targetDefinition); - } - }); - workspace.projects.set(projectName, project); - }); - await writeWorkspace(tree, workspace); - }; -} - -function switchToRenamedMethods( - filePath: Path, - content: string, - changes: Change[], -) { - const renames = new Map([ - ['selectThisNode', 'setSelected'], - ['columnApi.setColumnState', 'columnApi.applyColumnState'], - ['column.isLockVisible()', 'column.getColDef().lockVisible'], - ]); - renames.forEach((toText, fromText) => { - let pos = content.indexOf(fromText); - while (pos > -1) { - changes.push(new ReplaceChange(filePath, pos, fromText, toText)); - pos = content.indexOf(fromText, pos + 1); - } - }); -} - -function switchToRowNodeInterface( - filePath: Path, - content: string, - changes: Change[], -) { - let pos = content.indexOf(': RowNode'); - if (pos > -1) { - const source = ts.createSourceFile( - filePath, - content, - ts.ScriptTarget.Latest, - true, - ts.ScriptKind.TS, - ); - if (!isImported(source, 'IRowNode', 'ag-grid-community')) { - changes.push( - insertImport(source, content, 'IRowNode', 'ag-grid-community'), - ); - } - while (pos > -1) { - // Not accessing a RowNode static property. - if (content.charAt(pos + 9) !== '.') { - changes.push( - new ReplaceChange(filePath, pos, ': RowNode', ': IRowNode'), - ); - } - pos = content.indexOf(': RowNode', pos + 1); - } - } -} - -/** - * Visit all files and apply the changes. - */ -function updateSourceFiles(): Rule { - return async (tree: Tree): Promise => { - const workspace = await readWorkspace(tree); - workspace.projects.forEach((project) => { - visitProjectFiles( - tree, - project.sourceRoot || project.root, - (filePath) => { - // If the file is not a TypeScript file, we can skip it. - if (!filePath.endsWith('.ts')) { - return; - } - const content = tree.readText(filePath); - const changes: Change[] = []; - - switchToRenamedMethods(filePath, content, changes); - switchToRowNodeInterface(filePath, content, changes); - - const recorder = tree.beginUpdate(filePath); - applyToUpdateRecorder(recorder, changes); - tree.commitUpdate(recorder); - }, - ); - }); - }; -} - -/** - * Upgrade to AG Grid 29 and address breaking changes: - * - * - Introduce IRowNode in some cases replacing RowNode - * - Replace `selectThisNode` with `setSelected` - * - Replace `columnApi.setColumnState` with `columnApi.applyColumnState` - * - Replace `column.isLockVisible()` with `column.getColDef().lockVisible` - * - Do not import AG Grid theme CSS files in angular.json - * - */ -export default function (): Rule { - return async (tree: Tree): Promise => { - const { agGridDependency, agGridDependencyEnt } = readDependencies(tree); - - // AG Grid is not installed, so we don't need to do anything. - if (!agGridDependency && !agGridDependencyEnt) { - return; - } - - return chain([updateSourceFiles(), removeAgGridCssFiles()]); - }; -} diff --git a/libs/components/packages/src/schematics/migrations/update-9/legacy-services/legacy-services.schematic.spec.ts b/libs/components/packages/src/schematics/migrations/update-9/legacy-services/legacy-services.schematic.spec.ts deleted file mode 100644 index dcc3d9ddd1..0000000000 --- a/libs/components/packages/src/schematics/migrations/update-9/legacy-services/legacy-services.schematic.spec.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; - -import { createTestApp } from '../../../testing/scaffold'; - -describe('legacy-services.schematic', () => { - const runner = new SchematicTestRunner( - 'schematics', - require.resolve('../../migration-collection.json'), - ); - - async function setupTest(options: { textContent: string }) { - const tree = await createTestApp(runner, { - projectName: 'my-app', - }); - - tree.overwrite('./src/app/app.component.ts', options.textContent); - - return { - runSchematic: () => runner.runSchematic('legacy-services', {}, tree), - tree, - }; - } - - it('should replace services with legacy versions', async () => { - const { runSchematic } = await setupTest({ - textContent: `import { SkyModalService, SkyModalConfiguration } from '@skyux/modals'; -import { SkyModalService as FoobarService } from '@skyux/modals'; -import { SkyModalService as ExternalModalService } from '@external/module'; -import { SkyModalService as UnusedService } from 'unused'; -import { SkyDynamicComponentService } from '@skyux/core'; -import {SkyFlyoutService} from '@skyux/flyout'; -import { - SkyToastService -} from '@skyux/toast'; - -@Component() -export class AppComponent { - #modalSvc = inject(SkyModalService); - #foobarSvc = inject(FoobarService); - #externalSvc = inject(ExternalModalService); - - constructor(private toastSvc: SkyToastService) {} -} - -describe('', () => { - let dynamicComponentServiceSpy: Spy; - let modalService: SkyModalService; - let flyoutService: SkyFlyoutService; - - beforeEach(() => { - dynamicComponentServiceSpy = createSpyFromClass( - SkyDynamicComponentService - ); - modalService = new SkyModalService(dynamicComponentServiceSpy); - flyoutService = new SkyFlyoutService(); - - TestBed.configureTestingModule({ - providers: [ - { provide: SkyModalService, useValue: modalService }, - { provide: SkyFlyoutService, useValue: flyoutService }, - ] - }); - }); -}); -`, - }); - - const updatedTree = await runSchematic(); - - expect(updatedTree.readContent('./src/app/app.component.ts')).toEqual( - `import { SkyModalLegacyService, SkyModalConfiguration } from '@skyux/modals'; -import { SkyModalLegacyService as FoobarService } from '@skyux/modals'; -import { SkyModalService as ExternalModalService } from '@external/module'; -import { SkyModalService as UnusedService } from 'unused'; -import { SkyDynamicComponentLegacyService } from '@skyux/core'; -import {SkyFlyoutLegacyService} from '@skyux/flyout'; -import { - SkyToastLegacyService -} from '@skyux/toast'; - -@Component() -export class AppComponent { - #modalSvc = inject(SkyModalLegacyService); - #foobarSvc = inject(FoobarService); - #externalSvc = inject(ExternalModalService); - - constructor(private toastSvc: SkyToastLegacyService) {} -} - -describe('', () => { - let dynamicComponentServiceSpy: Spy; - let modalService: SkyModalLegacyService; - let flyoutService: SkyFlyoutLegacyService; - - beforeEach(() => { - dynamicComponentServiceSpy = createSpyFromClass( - SkyDynamicComponentLegacyService - ); - modalService = new SkyModalLegacyService(dynamicComponentServiceSpy); - flyoutService = new SkyFlyoutLegacyService(); - - TestBed.configureTestingModule({ - providers: [ - { provide: SkyModalLegacyService, useValue: modalService }, - { provide: SkyFlyoutLegacyService, useValue: flyoutService }, - ] - }); - }); -}); -`, - ); - }); - - it('should not replace similarly named services from external packages', async () => { - const { runSchematic } = await setupTest({ - textContent: `import {SkyModalService} from '@not-skyux/library'; -const svc = new SkyModalService(); -`, - }); - - const updatedTree = await runSchematic(); - - expect(updatedTree.readContent('./src/app/app.component.ts')).toEqual( - `import {SkyModalService} from '@not-skyux/library'; -const svc = new SkyModalService(); -`, - ); - }); -}); diff --git a/libs/components/packages/src/schematics/migrations/update-9/legacy-services/legacy-services.schematic.ts b/libs/components/packages/src/schematics/migrations/update-9/legacy-services/legacy-services.schematic.ts deleted file mode 100644 index 8360a1c10f..0000000000 --- a/libs/components/packages/src/schematics/migrations/update-9/legacy-services/legacy-services.schematic.ts +++ /dev/null @@ -1,106 +0,0 @@ -/** - * The contents of this file are heavily inspired by Angular's "untyped forms" migration. - * @see https://github.com/angular/angular/blob/14.3.x/packages/core/schematics/migrations/typed-forms/index.ts - */ -import { Rule, Tree, UpdateRecorder } from '@angular-devkit/schematics'; - -import { readRequiredFile } from '../../../utility/tree'; -import { getImports, getUsages } from '../../../utility/typescript/imports'; -import { createSourceFile } from '../../../utility/typescript/source-file'; -import { visitProjectFiles } from '../../../utility/visit-project-files'; -import { getWorkspace } from '../../../utility/workspace'; - -type RewriteFn = (startPos: number, origLength: number, text: string) => void; - -// A collection of services (and their packages) that should be replaced with "legacy" versions. -const packages = new Map([ - ['@skyux/core', ['SkyDynamicComponentService', 'SkyOverlayService']], - ['@skyux/flyout', ['SkyFlyoutService']], - ['@skyux/modals', ['SkyModalService']], - ['@skyux/toast', ['SkyToastService']], -]); - -function runLegacyServicesMigration(tree: Tree, filePath: string): void { - const sourceFile = createSourceFile( - filePath, - readRequiredFile(tree, filePath), - ); - - let update: UpdateRecorder | null = null; - - const rewriter: RewriteFn = ( - startPos: number, - origLength: number, - text: string, - ) => { - if (update === null) { - // Lazily initialize update, because most files will not require migration. - update = tree.beginUpdate(sourceFile.fileName); - } - - update.remove(startPos, origLength); - update.insertLeft(startPos, text); - }; - - const imports = getImports(sourceFile, packages); - - // If no relevant classes are imported, we can exit early. - if (imports.length === 0) { - return; - } - - // For each control class, migrate all of its uses. - for (const imp of imports) { - const usages = getUsages(sourceFile, imp); - - for (const usage of usages) { - const newName = getLegacyVersionOfName(imp.getText(sourceFile)); - - if (newName) { - rewriter( - usage.node.getStart(sourceFile), - usage.node.getWidth(sourceFile), - newName, - ); - } - } - } - - // For each imported control class, migrate to the corresponding legacy import. - for (const imp of imports) { - // If the import specifier has a property name, use that instead (for example, `import {PropertyName as Foo}`). - const item = imp.propertyName ?? imp; - - rewriter( - item.getStart(sourceFile), - item.getWidth(sourceFile), - getLegacyVersionOfName(item.getText(sourceFile)), - ); - } - - if (update) { - tree.commitUpdate(update); - } -} - -function getLegacyVersionOfName(name: string): string { - return name.replace(/(?:Service)$/, 'LegacyService'); -} - -/** - * Replaces certain SKY UX services with their "legacy" equivalents. - * For example, `SkyModalService` becomes `SkyModalLegacyService`. - */ -export default function (): Rule { - return async (tree) => { - const { workspace } = await getWorkspace(tree); - - workspace.projects.forEach((project) => { - visitProjectFiles(tree, project.root, (filePath) => { - if (filePath.endsWith('.ts')) { - runLegacyServicesMigration(tree, filePath); - } - }); - }); - }; -} diff --git a/libs/components/packages/src/schematics/migrations/update-9/move-page-component/move-page-component.schematic.spec.ts b/libs/components/packages/src/schematics/migrations/update-9/move-page-component/move-page-component.schematic.spec.ts deleted file mode 100644 index 9cbc7c6cd8..0000000000 --- a/libs/components/packages/src/schematics/migrations/update-9/move-page-component/move-page-component.schematic.spec.ts +++ /dev/null @@ -1,377 +0,0 @@ -import { stripIndents } from '@angular-devkit/core/src/utils/literals'; -import { ProjectDefinition } from '@angular-devkit/core/src/workspace'; -import { - SchematicTestRunner, - UnitTestTree, -} from '@angular-devkit/schematics/testing'; -import { - NodeDependencyType, - addPackageJsonDependency, -} from '@schematics/angular/utility/dependencies'; - -import { firstValueFrom } from 'rxjs'; - -import { createTestLibrary } from '../../../testing/scaffold'; -import { - getRequiredProject, - updateWorkspace, -} from '../../../utility/workspace'; - -type PackageJson = { - dependencies: Record; -}; - -describe('MovePageComponentSchematic', () => { - const runner = new SchematicTestRunner( - 'schematics', - require.resolve('../../migration-collection.json'), - ); - - async function setupTest(): Promise<{ - tree: UnitTestTree; - project: ProjectDefinition; - runner: SchematicTestRunner; - }> { - const tree = await createTestLibrary(runner, { - projectName: 'test-lib', - }); - const { project } = await getRequiredProject(tree, 'test-lib'); - - return { - tree, - project, - runner, - }; - } - - it('should run successfully', async () => { - const { tree, runner } = await setupTest(); - expect(() => - runner.runSchematic('move-page-component', {}, tree), - ).not.toThrow(); - }); - - it('should update single import', async () => { - const { tree, project, runner } = await setupTest(); - addPackageJsonDependency(tree, { - type: NodeDependencyType.Default, - name: '@skyux/layout', - version: '0.0.0', - }); - tree.create( - `${project.sourceRoot}/app/custom.module.ts`, - stripIndents` - import { NgModule } from '@angular/core'; - import { SkyPageModule } from '@skyux/layout'; - - @NgModule({ - imports: [SkyPageModule], - }) - export class CustomModule {} - `, - ); - const result = await runner.runSchematic('move-page-component', {}, tree); - expect(result.readContent(`${project.sourceRoot}/app/custom.module.ts`)) - .toMatchInlineSnapshot(` - "import { NgModule } from '@angular/core'; - import { SkyPageModule } from '@skyux/pages'; - - @NgModule({ - imports: [SkyPageModule], - }) - export class CustomModule {}" - `); - expect( - (result.readJson('package.json') as PackageJson).dependencies[ - '@skyux/pages' - ], - ).toEqual('0.0.0'); - }); - - it('should update import among multiple import blocks', async () => { - const { tree, project, runner } = await setupTest(); - addPackageJsonDependency(tree, { - type: NodeDependencyType.Default, - name: '@skyux/layout', - version: '0.0.0', - }); - tree.create( - `${project.sourceRoot}/app/custom.module.ts`, - `import { SkyIdModule, SkyNumericModule } from '@skyux/core'; - import { - SkyDataManagerModule, - SkyDataManagerService, - } from '@skyux/data-manager'; - import { SkyDateRangePickerModule } from '@skyux/datetime'; - import { SkyCheckboxModule, SkyInputBoxModule } from '@skyux/forms'; - import { - SkyIconModule, - SkyKeyInfoModule, - SkyTokensModule, - SkyWaitModule, - } from '@skyux/indicators'; - import { - SkyDescriptionListModule, - SkyPageSummaryModule, - SkyToolbarModule, - } from '@skyux/layout'; - import { SkyPagingModule } from '@skyux/lists'; - import { SkySearchModule, SkyLookupModule } from '@skyux/lookup'; - import { SkyModalModule } from '@skyux/modals'; - import { SkyPageHeaderModule } from '@skyux/pages'; - import { SkyPageModule } from '@skyux/layout'; - import { AgGridModule } from 'ag-grid-angular';`, - ); - const result = await runner.runSchematic('move-page-component', {}, tree); - expect(result.readContent(`${project.sourceRoot}/app/custom.module.ts`)) - .toMatchInlineSnapshot(` - "import { SkyIdModule, SkyNumericModule } from '@skyux/core'; - import { - SkyDataManagerModule, - SkyDataManagerService, - } from '@skyux/data-manager'; - import { SkyDateRangePickerModule } from '@skyux/datetime'; - import { SkyCheckboxModule, SkyInputBoxModule } from '@skyux/forms'; - import { - SkyIconModule, - SkyKeyInfoModule, - SkyTokensModule, - SkyWaitModule, - } from '@skyux/indicators'; - import { - SkyDescriptionListModule, - SkyPageSummaryModule, - SkyToolbarModule, - } from '@skyux/layout'; - import { SkyPagingModule } from '@skyux/lists'; - import { SkySearchModule, SkyLookupModule } from '@skyux/lookup'; - import { SkyModalModule } from '@skyux/modals'; - import { SkyPageHeaderModule, SkyPageModule } from '@skyux/pages'; - import { AgGridModule } from 'ag-grid-angular';" - `); - expect( - (result.readJson('package.json') as PackageJson).dependencies[ - '@skyux/pages' - ], - ).toEqual('0.0.0'); - }); - - it('should update multiple import', async () => { - const { tree, project, runner } = await setupTest(); - addPackageJsonDependency(tree, { - type: NodeDependencyType.Default, - name: '@skyux/layout', - version: '0.0.0', - }); - tree.create( - `${project.sourceRoot}/app/custom.module.ts`, - stripIndents` - import { NgModule } from '@angular/core'; - import { SkyActionButtonPermalink, SkyPageModule } from '@skyux/layout'; - - @NgModule({ - imports: [SkyPageModule], - }) - export class CustomModule {} - `, - ); - const result = await runner.runSchematic('move-page-component', {}, tree); - expect(result.readContent(`${project.sourceRoot}/app/custom.module.ts`)) - .toMatchInlineSnapshot(` - "import { NgModule } from '@angular/core'; - import { SkyActionButtonPermalink } from '@skyux/layout'; - import { SkyPageModule } from '@skyux/pages'; - - @NgModule({ - imports: [SkyPageModule], - }) - export class CustomModule {}" - `); - }); - - it('should update multiple import, first item', async () => { - const { tree, project, runner } = await setupTest(); - addPackageJsonDependency(tree, { - type: NodeDependencyType.Default, - name: '@skyux/layout', - version: '0.0.0', - }); - tree.create( - `${project.sourceRoot}/app/custom.module.ts`, - stripIndents` - import { NgModule } from '@angular/core'; - import { SkyPageModule, SkyTextExpandRepeaterListStyleType } from '@skyux/layout'; - - @NgModule({ - imports: [SkyPageModule], - }) - export class CustomModule {} - `, - ); - - // One update where sourceRoot is undefined. - const workspaceUpdate = updateWorkspace((workspace) => { - workspace.projects.set('test-lib', { - ...(workspace.projects.get('test-lib') as ProjectDefinition), - sourceRoot: undefined, - }); - }); - const updatedTree = await firstValueFrom( - runner.callRule(workspaceUpdate, tree), - ); - - const result = await runner.runSchematic( - 'move-page-component', - {}, - updatedTree, - ); - expect(result.readContent(`${project.sourceRoot}/app/custom.module.ts`)) - .toMatchInlineSnapshot(` - "import { NgModule } from '@angular/core'; - import { SkyTextExpandRepeaterListStyleType } from '@skyux/layout'; - import { SkyPageModule } from '@skyux/pages'; - - @NgModule({ - imports: [SkyPageModule], - }) - export class CustomModule {}" - `); - }); - - it('should update multiple import, multi-line', async () => { - const { tree, project, runner } = await setupTest(); - addPackageJsonDependency(tree, { - type: NodeDependencyType.Default, - name: '@skyux/layout', - version: '0.0.0', - }); - tree.create( - `${project.sourceRoot}/app/custom.module.ts`, - stripIndents` - import { NgModule } from '@angular/core'; - import { - SkyActionButtonPermalink, - SkyPageModule, - SkyTextExpandRepeaterListStyleType, - } from '@skyux/layout'; - - @NgModule({ - imports: [SkyPageModule], - }) - export class CustomModule {} - `, - ); - - // One update where sourceRoot is undefined. - const workspaceUpdate = updateWorkspace((workspace) => { - workspace.projects.set('test-lib', { - ...(workspace.projects.get('test-lib') as ProjectDefinition), - sourceRoot: undefined, - }); - }); - const updatedTree = await firstValueFrom( - runner.callRule(workspaceUpdate, tree), - ); - - const result = await runner.runSchematic( - 'move-page-component', - {}, - updatedTree, - ); - expect(result.readContent(`${project.sourceRoot}/app/custom.module.ts`)) - .toMatchInlineSnapshot(` - "import { NgModule } from '@angular/core'; - import { SkyActionButtonPermalink, SkyTextExpandRepeaterListStyleType } from '@skyux/layout'; - import { SkyPageModule } from '@skyux/pages'; - - @NgModule({ - imports: [SkyPageModule], - }) - export class CustomModule {}" - `); - }); - - it('should update existing import', async () => { - const { tree, project, runner } = await setupTest(); - addPackageJsonDependency(tree, { - type: NodeDependencyType.Default, - name: '@skyux/layout', - version: '0.0.0', - }); - addPackageJsonDependency(tree, { - type: NodeDependencyType.Default, - name: '@skyux/pages', - version: '0.0.0', - }); - tree.create( - `${project.sourceRoot}/app/custom.module.ts`, - stripIndents` - import { NgModule } from '@angular/core'; - import { SkyPageModule } from '@skyux/layout'; - import { SkyPageLink } from '@skyux/pages'; - - @NgModule({ - imports: [SkyPageModule], - }) - export class CustomModule {} - `, - ); - const result = await runner.runSchematic('move-page-component', {}, tree); - expect(result.readContent(`${project.sourceRoot}/app/custom.module.ts`)) - .toMatchInlineSnapshot(` - "import { NgModule } from '@angular/core'; - import { SkyPageLink, SkyPageModule } from '@skyux/pages'; - - @NgModule({ - imports: [SkyPageModule], - }) - export class CustomModule {}" - `); - }); - - it('should update ', async () => { - const { tree, project, runner } = await setupTest(); - tree.create( - `${project.sourceRoot}/app/custom.component.html`, - stripIndents` - - - Example... - - - `, - ); - const result = await runner.runSchematic('move-page-component', {}, tree); - expect(result.readText(`${project.sourceRoot}/app/custom.component.html`)) - .toMatchInlineSnapshot(` - " - - Example... - - " - `); - }); - - it('should not update other ', async () => { - const { tree, project, runner } = await setupTest(); - tree.create( - `${project.sourceRoot}/app/custom.component.html`, - stripIndents` - - - Example... - - - `, - ); - const result = await runner.runSchematic('move-page-component', {}, tree); - expect(result.readText(`${project.sourceRoot}/app/custom.component.html`)) - .toMatchInlineSnapshot(` - " - - Example... - - " - `); - }); -}); diff --git a/libs/components/packages/src/schematics/migrations/update-9/move-page-component/move-page-component.schematic.ts b/libs/components/packages/src/schematics/migrations/update-9/move-page-component/move-page-component.schematic.ts deleted file mode 100644 index 891dd6ec9f..0000000000 --- a/libs/components/packages/src/schematics/migrations/update-9/move-page-component/move-page-component.schematic.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics'; -import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks'; -import ts from '@schematics/angular/third_party/github.com/Microsoft/TypeScript/lib/typescript'; -import { findNodes, insertImport } from '@schematics/angular/utility/ast-utils'; -import { InsertChange } from '@schematics/angular/utility/change'; -import { - NodeDependencyType, - addPackageJsonDependency, - getPackageJsonDependency, -} from '@schematics/angular/utility/dependencies'; - -import { visitProjectFiles } from '../../../utility/visit-project-files'; -import { getWorkspace } from '../../../utility/workspace'; - -function getImportNames(importDeclaration: ts.ImportDeclaration): string[] { - return ( - importDeclaration.importClause?.namedBindings as ts.NamedImports - ).elements - .map((element) => element.name.getText()) - .sort(); -} - -export default function movePageComponent(): Rule { - return async (tree: Tree, context: SchematicContext) => { - const { workspace } = await getWorkspace(tree); - let addDependency = false; - workspace.projects.forEach((project) => { - const source = project.sourceRoot || `${project.root}/src`; - - // Visit all TypeScript files in each project. - visitProjectFiles(tree, source, (path) => { - if (path.endsWith('.ts')) { - // Parse the TypeScript file. - const source = ts.createSourceFile( - path, - tree.readText(path), - ts.ScriptTarget.Latest, - true, - ); - - // Find all imports of SkyPageLayoutType and SkyPageModule from @skyux/layout. - const importsToMove = ['SkyPageLayoutType', 'SkyPageModule']; - const pageImports = findNodes( - source, - (node): node is ts.ImportDeclaration => { - return ( - ts.isImportDeclaration(node) && - ts.isStringLiteral(node.moduleSpecifier) && - node.moduleSpecifier.text.startsWith('@skyux/layout') && - !!node.importClause?.namedBindings && - ts.isNamedImports(node.importClause.namedBindings) && - node.importClause.namedBindings.elements.some((element) => - importsToMove.includes(element.name.getText()), - ) - ); - }, - ); - - // Found one. - if (pageImports.length > 0) { - // We'll need to add the dependency to @skyux/pages. - addDependency = true; - - // Angular uses a change recorder and the magic string library. - const updateRecorder = tree.beginUpdate(path); - const importsToAdd = pageImports - .map((pageImport) => - getImportNames(pageImport).filter((importName) => - importsToMove.includes(importName), - ), - ) - .flat(); - - pageImports.forEach((importToUpdate: ts.ImportDeclaration) => { - const otherImports = getImportNames(importToUpdate).filter( - (importName) => !importsToMove.includes(importName), - ); - // Is anything else imported from @skyux/layout? - if ( - otherImports.length > 0 && - importToUpdate.importClause?.namedBindings - ) { - // Yes. Update the import. - updateRecorder.remove( - importToUpdate.importClause.namedBindings.getStart(), - importToUpdate.importClause.namedBindings.getWidth(), - ); - updateRecorder.insertLeft( - importToUpdate.importClause.namedBindings.getStart(), - `{ ${otherImports.join(', ')} }`, - ); - } else { - // No. Remove the whole import declaration. - updateRecorder.remove( - importToUpdate.getFullStart(), - importToUpdate.getFullWidth(), - ); - } - }); - - // Commit the update and parse the file again. - tree.commitUpdate(updateRecorder); - - // Add the new import. - const updatedSource = ts.createSourceFile( - path, - tree.readText(path), - ts.ScriptTarget.Latest, - true, - ); - const recorder = tree.beginUpdate(path); - const change = insertImport( - updatedSource, - path, - importsToAdd.join(', '), - '@skyux/pages', - ) as InsertChange; - recorder.insertLeft(change.pos, change.toAdd); - tree.commitUpdate(recorder); - } - } else if (path.endsWith('.component.html')) { - // Update to remove the layout attribute. - const content = tree.readText(path); - // Based on code search, any use of `layout="auto"` matches this pattern. - const search = ' -1) { - const recorder = tree.beginUpdate(path); - // Remove ' layout="auto"'. - recorder.remove(skyPageIndex + 9, 14); - tree.commitUpdate(recorder); - } - } - }); - }); - - // Add the dependency to @skyux/pages. - if (addDependency) { - const pages = getPackageJsonDependency(tree, '@skyux/pages'); - if (!pages) { - const layout = getPackageJsonDependency(tree, '@skyux/layout'); - if (layout) { - addPackageJsonDependency(tree, { - type: NodeDependencyType.Default, - name: '@skyux/pages', - version: layout.version, - }); - context.addTask(new NodePackageInstallTask()); - } - } - } - }; -} diff --git a/libs/components/packages/src/schematics/migrations/update-9/update-angular-tree-component/update-angular-tree-component.schematic.spec.ts b/libs/components/packages/src/schematics/migrations/update-9/update-angular-tree-component/update-angular-tree-component.schematic.spec.ts deleted file mode 100644 index 86ff5a7b71..0000000000 --- a/libs/components/packages/src/schematics/migrations/update-9/update-angular-tree-component/update-angular-tree-component.schematic.spec.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; - -import { join } from 'path'; - -import { createTestApp } from '../../../testing/scaffold'; - -describe('Migrations > Update angular-tree-component dependency', () => { - const runner = new SchematicTestRunner( - 'migrations', - join(__dirname, '../../migration-collection.json'), - ); - - async function setupTest() { - const tree = await createTestApp(runner, { - projectName: 'my-app', - }); - - return { - runSchematic: () => - runner.runSchematic('update-angular-tree-component', {}, tree), - tree, - }; - } - - it('should update the dependency if @skyux/angular-tree-component and @circlon/angular-tree-component installed', async () => { - const { runSchematic, tree } = await setupTest(); - - tree.overwrite( - '/package.json', - '{"dependencies": {"@skyux/angular-tree-component": "8.0.0", "@circlon/angular-tree-component": "11.0.4"}}', - ); - - await runSchematic(); - - expect(tree.readJson('/package.json')).toEqual({ - dependencies: { - '@skyux/angular-tree-component': '8.0.0', - '@blackbaud/angular-tree-component': '1.0.0-alpha.0', - }, - }); - }); - - it('should not update the dependency if @skyux/angular-tree-component is not installed', async () => { - const { runSchematic, tree } = await setupTest(); - - tree.overwrite( - '/package.json', - '{"dependencies": {"@circlon/angular-tree-component": "11.0.4"}}', - ); - - await runSchematic(); - - expect(tree.readJson('/package.json')).toEqual({ - dependencies: { - '@circlon/angular-tree-component': '11.0.4', - }, - }); - }); - - it('should add @blackbaud/angular-tree-component if @skyux/angular-tree-component is not installed', async () => { - const { runSchematic, tree } = await setupTest(); - - tree.overwrite('/package.json', '{}'); - - await runSchematic(); - - expect(tree.readJson('/package.json')).toEqual({}); - }); - - it('should replace @circlon/angular-tree-component import paths', async () => { - const { runSchematic, tree } = await setupTest(); - - tree.overwrite( - '/src/app/app.component.ts', - ` - import { Foobar } from '@circlon/angular-tree-component'; - import { FooBarBaz } from '@circlon/angular-tree-component/foo/bar/baz'; - import { - FooService, - BarService - } from '@circlon/angular-tree-component'; - import * as angularTreeComponent from '@circlon/angular-tree-component'; - `, - ); - tree.create( - '/src/app/app.component.css', - `@import 'node_modules/@circlon/angular-tree-component/css/angular-tree-component';`, - ); - - await runSchematic(); - - expect(tree.readText('/src/app/app.component.ts')).toEqual(` - import { Foobar } from '@blackbaud/angular-tree-component'; - import { FooBarBaz } from '@blackbaud/angular-tree-component/foo/bar/baz'; - import { - FooService, - BarService - } from '@blackbaud/angular-tree-component'; - import * as angularTreeComponent from '@blackbaud/angular-tree-component'; - `); - expect(tree.readText('/src/app/app.component.css')).toEqual( - `@import 'node_modules/@blackbaud/angular-tree-component/css/angular-tree-component';`, - ); - }); -}); diff --git a/libs/components/packages/src/schematics/migrations/update-9/update-angular-tree-component/update-angular-tree-component.schematic.ts b/libs/components/packages/src/schematics/migrations/update-9/update-angular-tree-component/update-angular-tree-component.schematic.ts deleted file mode 100644 index 674585f68b..0000000000 --- a/libs/components/packages/src/schematics/migrations/update-9/update-angular-tree-component/update-angular-tree-component.schematic.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { Rule, Tree, chain } from '@angular-devkit/schematics'; -import * as ts from '@schematics/angular/third_party/github.com/Microsoft/TypeScript/lib/typescript'; -import { findNodes } from '@schematics/angular/utility/ast-utils'; -import { NodeDependencyType } from '@schematics/angular/utility/dependencies'; -import { getWorkspace } from '@schematics/angular/utility/workspace'; - -import { ensurePeersInstalled } from '../../../rules/ensure-peers-installed'; -import { visitProjectFiles } from '../../../utility/visit-project-files'; - -const OLD_PACKAGE = '@circlon/angular-tree-component'; -const NEW_PACKAGE = '@blackbaud/angular-tree-component'; - -function renameTypeScriptImportPaths(): Rule { - return async (tree: Tree) => { - const workspace = await getWorkspace(tree); - - for (const [, projectDefinition] of workspace.projects.entries()) { - visitProjectFiles(tree, projectDefinition.root, (filePath) => { - if (filePath.match(/\.ts$/)) { - const source = ts.createSourceFile( - filePath, - tree.readText(filePath), - ts.ScriptTarget.Latest, - true, - ); - const oldImports = findNodes( - source, - (node): node is ts.ImportDeclaration => - ts.isImportDeclaration(node) && - ts.isStringLiteral(node.moduleSpecifier) && - node.moduleSpecifier.text.startsWith(OLD_PACKAGE), - ); - if (oldImports.length > 0) { - const recorder = tree.beginUpdate(filePath); - oldImports.forEach((node) => { - const moduleSpecifier = node.moduleSpecifier as ts.StringLiteral; - recorder.remove( - moduleSpecifier.getStart() + 1, - OLD_PACKAGE.length, - ); - recorder.insertLeft(moduleSpecifier.getStart() + 1, NEW_PACKAGE); - }); - tree.commitUpdate(recorder); - } - } else if (filePath.match(/\.s?css$/)) { - const content = tree.readText(filePath); - let pos = content.indexOf(OLD_PACKAGE); - if (pos > -1) { - const recorder = tree.beginUpdate(filePath); - do { - recorder.remove(pos, OLD_PACKAGE.length); - recorder.insertLeft(pos, NEW_PACKAGE); - pos = content.indexOf(OLD_PACKAGE, pos + 1); - } while (pos > -1); - tree.commitUpdate(recorder); - } - } - }); - } - }; -} - -export default function (): Rule { - return chain([ - renameTypeScriptImportPaths(), - ensurePeersInstalled( - '@skyux/angular-tree-component', - [ - { - name: '@blackbaud/angular-tree-component', - version: '1.0.0-alpha.0', - type: NodeDependencyType.Default, - }, - ], - [ - { - name: '@circlon/angular-tree-component', - }, - ], - ), - ]); -}