angularangular-cliangular-schematicsangular-devkit

ClassOptions Schema - Angular Schematics


In the @angular-devkit/schematics readme, I am confused on what the ClassOptions is doing.

If you add the code to a project, it will show an error because this file does not exist.

Thoughts on what this is used for + an example?

import { strings } from '@angular-devkit/core';
import {
  Rule, SchematicContext, SchematicsException, Tree,
  apply, branchAndMerge, mergeWith, template, url,
} from '@angular-devkit/schematics';
import { Schema as ClassOptions } from './schema';

export default function (options: ClassOptions): Rule {
  return (tree: Tree, context: SchematicContext) => {
    if (!options.name) {
      throw new SchematicsException('Option (name) is required.');
    }

    const templateSource = apply(
      url('./files'),
      [
        template({
          ...strings,
          ...options,
        }),
      ]
    );

    return branchAndMerge(mergeWith(templateSource));
  };
} 

Solution

  • The schema file in the example is a typescript file generated with this function during a build process in angular-cli. It's a pattern used in angular-cli and the example won't work as it is. You can see a complete example of the source for a schematic like this in one of the official angular schematics like service.

    However keep in mind ClassOptions is just an object that specifies the options for the Angular Schematic. It can come from anywhere and is decoupled from the schematic library. It is the responsibility of the tooling to provide the options to the schematics library.

    Here's a similar example using the reference cli.

    Generate a simple schematic:

    schematics blank --name=test
    

    Add a path to schema file to collection.json:

    {
      "$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
      "schematics": {
        "test": {
          "description": "A blank schematic.",
          "factory": "./test/index#test",
          "schema": "./test/schema.json"
        }
      }
    }
    

    Create a schema.json:

    {
        "$schema": "http://json-schema.org/schema",
        "id": "MySchema",
        "title": "My Schema",
        "type": "object",
        "properties": {
            "name": {
                "type": "string",
                "default": "cactus"
            }
        }
    }
    

    The factory in index.ts will now get passed the default options from the schema.json file.

    import { Rule, SchematicContext, Tree } from "@angular-devkit/schematics";
    
    // You don't have to export the function as default. You can also have more than one rule factory
    // per file.
    export function test(_options: any): Rule {
        return (tree: Tree, _context: SchematicContext) => {
            tree.create(_options.name || "hello", "world");
            return tree;
        };
    }
    

    Run the cli with defaults from schema.json:

    schematics .:test --dry-run=false
    ...
    CREATE /cactus (5 bytes)
    

    run the cli with user defined options:

    schematics .:test --name=bean--dry-run=false
    ...
    CREATE /bean (5 bytes)