Skip to content

Update Migrations

Damyan Petev edited this page Sep 20, 2018 · 10 revisions

Update Migrations

Angular CLI provides a way to hook into the ng update process for the package by exposing a collection of migration schematics.

Besides the schematics setup, the repo migration has a base UpdateChanges class implementation that word with simple JSON config files and offers built-in functionality for:

  • Typescript
    • Rename a Class
  • HTML Templates (all can be either renamed or removed)
    • Selectors
      • Directive
      • Component
    • Bindings
      • Bound input property
      • Output event binding

Jump to:

How it's all tied up

The project package.json has the following entry:

"ng-update": {
  "migrations": "./migrations/migration-collection.json"
}

This is a special case of a collection definition (usually provided as root "schematics" property) used by the update+migrate schematic commands. The schema for this JSON is fairly standard with the exception of additional version property:

{
  "schematics": {
  "migration-01": {
    "version": "6.0.0",
    "description": "Updates Ignite UI for Angular from v5 to v6",
    "factory": "./update-6"
  }
  //...

The factory is a relative path that should lead to a module index.ts that exports a function as default that returns a Rule transformation. This is where manipulations on the source Tree are performed, including using UpdateChanges.

Schematic(s) that match the updated package version (and any intermediate versions) will be run as part of ng update igniteui-angular, so each schematic should only migrate changes made in that specific version.

Because the migrations are valid schematics they can also be executed directly (useful for testing) via ng generate:

ng g igniteui-angular/migrations/migration-collection.json:migration-XX

Where migration-XX is the specific migration from the collection json to be run.

Further reading:

Schematics — An Introduction, @angular-devkit/schematics Readme, Update Command Spec

Add a new migration

  1. Start by adding a new entry to the migration-collection.json schematics - set the upcoming version, description and factory path.

    {
      "schematics": {
        "migration-01": { ... },
        "migration-02": { ... },
        //...
        "migration-07": {
          "version": "6.3.0",
          "description": "This is the new update for 6.3.0",
          "factory": "./update-6_3"
        }
      }
    }
  2. Create a folder matching the defined factory path, in this case update-6_3

  3. In the new folder create index.ts. Here's a boilerplate of the default export looks like this:

    export default function(): Rule {
      return (host: Tree, context: SchematicContext) => {
        // apply changes to host tree
      };
    }
  4. [optional] Setup and use UpdateChanges. See next section for more.

Using the UpdateChanges class

The class reads a local 'changes' folder to read configurations for various transformations, thus keeping the actual API fairly minimal. To use, instantiate with the current directory and Rule arguments and then call .applyChanges(). So the updated migration index.ts should look like:

export default function(): Rule {
    return (host: Tree, context: SchematicContext) => {
      // apply changes to host tree
      const update = new UpdateChanges(__dirname, host, context);
      update.applyChanges();
    };
}

To create configurations:

  1. [optional] Create the 'changes' folder under the migration factory path if it doesn't exists yet.

  2. [optional] Create config JSON files in the 'changes' folder as needed:

    File Schema Use for
    classes.json ../../common/schema/class.schema.json TS Classes
    selectors.json ../../common/schema/selector.schema.json Component/Directive selectors
    outputs.json ../../common/schema/binding.schema.json Event Emitters
    inputs.json ../../common/schema/binding.schema.json Property bindings

    Open and empty object in the file and assign it's $schema to the respective value from above. This will enable auto-completion (ctrl/cmd + space) and validation for the file.

  3. Add to the changes array. Following the API (ctrl/cmd + space) is probably the best approach, but in general all change objects describe in a similar manner - with a name or selector property to find the element in question and either a replaceWith value or remove flag to specify the change action.

    Component/Directive will have a type to specify them and input/output bindings have an owner property with both selector and type.

  4. Verify there are no schema errors - make sure your editor has JSON Schema support (VS Code supports by default).

Config JSON auto-complete in VS Code

Notes

Class rename

Uses Typescript's AST to find only actual ts.SyntaxKind.Identifier to avoid replacing property names or string content.

Directive removal

Removing a directive will also match and remove its value if bound in the template, e.g. removing igxRemoveDirective will remove the entire [igxRemoveDirective]='value' string from a template.

Bindings

Just like directives, bindings will also be removed with their respective value. Additionally, at the moment bindings are only matched with the punctuation syntax (not prefixes) like (igxOutput)="value()" and [igxIntput]="value".

Clone this wiki locally