Skip to content

Commit

Permalink
feat: add support ng update ng-alain
Browse files Browse the repository at this point in the history
  • Loading branch information
cipchk committed Oct 21, 2023
1 parent 3a6f622 commit 29baafb
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 1 deletion.
5 changes: 5 additions & 0 deletions schematics/migration.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
"description": "Updates NG-ALAIN to v16 [https://github.com/ng-alain/ng-alain/issues/2390]",
"factory": "./ng-update/index#updateToV16"
},
"migration-v17": {
"version": "17",
"description": "Updates NG-ALAIN to v17 [https://github.com/ng-alain/ng-alain/issues/2390]",
"factory": "./ng-update/index#updateToV17"
},
"ng-post-update": {
"description": "Performs cleanup after ng-update.",
"factory": "./ng-update/index#postUpdate",
Expand Down
6 changes: 6 additions & 0 deletions schematics/ng-update/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ import { chain, Rule, SchematicContext } from '@angular-devkit/schematics';

import { ruleUpgradeData } from './upgrade-data';
import { v16Rule } from './upgrade-rules/v16';
import { v17Rule } from './upgrade-rules/v17';

const migrations: NullableDevkitMigration[] = [];

export function updateToV16(): Rule {
return chain([v16Rule(), createMigrationSchematicRule(TargetVersion.V16, migrations, ruleUpgradeData, postUpdate)]);
}

export function updateToV17(): Rule {
// , createMigrationSchematicRule(TargetVersion.V17, migrations, ruleUpgradeData, postUpdate)
return chain([v17Rule()]);
}

/** Post-update schematic to be called when update is finished. */
export function postUpdate(context: SchematicContext, targetVersion: TargetVersion, hasFailures: boolean): void {
context.logger.info('');
Expand Down
52 changes: 52 additions & 0 deletions schematics/ng-update/upgrade-rules/v17/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';

import { createAlainApp, migrationCollection } from '../../../utils/testing';

describe('Schematic: ng-update: v17Rule', () => {
let runner: SchematicTestRunner;
let tree: UnitTestTree;
const logs: string[] = [];
const jsonSchemaModulePath = '/projects/foo/src/app/shared/json-schema/json-schema.module.ts';

beforeEach(async () => {
({ runner, tree } = await createAlainApp());
if (!tree.exists(jsonSchemaModulePath)) {
tree.create(
jsonSchemaModulePath,
`import { NgModule } from '@angular/core';
import { DelonFormModule, WidgetRegistry } from '@delon/form';
import { TestWidget } from './test/test.widget';
import { SharedModule } from '../shared.module';
export const SCHEMA_THIRDS_COMPONENTS = [TestWidget];
@NgModule({
declarations: SCHEMA_THIRDS_COMPONENTS,
imports: [SharedModule, DelonFormModule.forRoot()],
exports: SCHEMA_THIRDS_COMPONENTS
})
export class JsonSchemaModule {
constructor(widgetRegistry: WidgetRegistry) {
widgetRegistry.register(TestWidget.KEY, TestWidget);
}
}
`
);
}
});

async function runMigration(): Promise<void> {
logs.length = 0;
runner = new SchematicTestRunner('schematics', migrationCollection);
runner.logger.subscribe(e => logs.push(e.message));
await runner.runSchematic('migration-v17', {}, tree);
}

it('should be working', async () => {
await runMigration();
const content = tree.readContent(jsonSchemaModulePath);
expect(content).toContain(`import { UploadWidgetModule } from '@delon/form/widgets/upload';`);
expect(content).toContain(`, UploadWidgetModule`);
});
});
79 changes: 79 additions & 0 deletions schematics/ng-update/upgrade-rules/v17/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { chain, Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
import { insertImport, addSymbolToNgModuleMetadata } from '@schematics/angular/utility/ast-utils';
import { Change, InsertChange } from '@schematics/angular/utility/change';
import * as colors from 'ansi-colors';

import { DEFAULT_WORKSPACE_PATH, getSourceFile, logStart, readJSON, applyChanges } from '../../../utils';
import { UpgradeMainVersions } from '../../../utils/versions';

function qr(): Rule {
return (_: Tree, context: SchematicContext) => {
context.logger.info(
colors.yellow(
` [qr] Will be removed in 18.0.0, please use [nz-qrcode](https://ng.ant.design/components/qr-code) instead.`
)
);
};
}

function autoRegisterFormWidgets(): Rule {
return (tree: Tree, context: SchematicContext) => {
const angularJson = readJSON(tree, DEFAULT_WORKSPACE_PATH);
const projectNames = Object.keys(angularJson.projects);
for (const name of projectNames) {
autoRegisterFormWidgetsRun(tree, name, angularJson.projects[name].sourceRoot, context);
}
};
}

function autoRegisterFormWidgetsRun(tree: Tree, name: string, sourceRoot: string, context: SchematicContext): void {
const modulePath = `${sourceRoot}/app/shared/json-schema/json-schema.module.ts`;
if (!tree.exists(modulePath)) return;

const list = [
{ symbolName: 'AutoCompleteWidgetModule', fileName: '@delon/form/widgets/autocomplete' },
{ symbolName: 'CascaderWidgetModule', fileName: '@delon/form/widgets/cascader' },
{ symbolName: 'MentionWidgetModule', fileName: '@delon/form/widgets/mention' },
{ symbolName: 'RateWidgetModule', fileName: '@delon/form/widgets/rate' },
{ symbolName: 'SliderWidgetModule', fileName: '@delon/form/widgets/slider' },
{ symbolName: 'TagWidgetModule', fileName: '@delon/form/widgets/tag' },
{ symbolName: 'TimeWidgetModule', fileName: '@delon/form/widgets/time' },
{ symbolName: 'TransferWidgetModule', fileName: '@delon/form/widgets/transfer' },
{ symbolName: 'TreeSelectWidgetModule', fileName: '@delon/form/widgets/tree-select' },
{ symbolName: 'UploadWidgetModule', fileName: '@delon/form/widgets/upload' }
];
const source = getSourceFile(tree, modulePath);
const changes: Change[] = [];
for (const item of list) {
changes.push(insertImport(source, modulePath, item.symbolName, item.fileName) as InsertChange);
changes.push(...addSymbolToNgModuleMetadata(source, modulePath, 'imports', item.symbolName));
}
applyChanges(tree, modulePath, changes);

context.logger.info(
colors.yellow(
` [@delon/form] Register all widgets in ${name} project, you can reduce package size by removing unnecessary parts`
)
);
}

function finished(): Rule {
return (_tree: Tree, context: SchematicContext) => {
context.addTask(new NodePackageInstallTask());

context.logger.info(
colors.green(
` ✓ Congratulations, Abort more detail please refer to upgrade guide https://github.com/ng-alain/ng-alain/issues/2390`
)
);
};
}

export function v17Rule(): Rule {
return async (tree: Tree, context: SchematicContext) => {
logStart(context, `Upgrade @delon/* version number`);
UpgradeMainVersions(tree);
return chain([autoRegisterFormWidgets(), qr(), finished()]);
};
}
2 changes: 1 addition & 1 deletion schematics/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const Jasmine = require('jasmine');
const runner = new Jasmine({ projectBaseDir });

// const files = `schematics/**/*.spec.ts`;
const files = `schematics/ng-update/upgrade-rules/v16/index.spec.ts`;
const files = `schematics/ng-update/upgrade-rules/v17/index.spec.ts`;

const tests = glob.sync(files).map(p => relative(projectBaseDir, p));

Expand Down
11 changes: 11 additions & 0 deletions schematics/utils/ast.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { SchematicsException, Tree } from '@angular-devkit/schematics';
import { Change, InsertChange } from '@schematics/angular/utility/change';
import * as ts from 'typescript';

/** Reads file given path and returns TypeScript source file. */
Expand All @@ -10,3 +11,13 @@ export function getSourceFile(tree: Tree, path: string): ts.SourceFile {
const content = buffer.toString();
return ts.createSourceFile(path, content, ts.ScriptTarget.Latest, true);
}

export function applyChanges(tree: Tree, path: string, changes: Change[]): void {
const exportRecorder = tree.beginUpdate(path);
for (const change of changes) {
if (change instanceof InsertChange) {
exportRecorder.insertLeft(change.pos, change.toAdd);
}
}
tree.commitUpdate(exportRecorder);
}

0 comments on commit 29baafb

Please sign in to comment.