Customizing generator options
Adding a TypeScript schema
To create a TypeScript schema to use in your generator function, define a TypeScript file next to your schema.json named schema.ts. Inside the schema.ts, define an interface to match the properties in your schema.json file, and whether they are required.
1export interface GeneratorOptions {
2 name: string;
3 type?: string;
4}
5Import the TypeScript schema into your generator file and replace the any in your generator function with the interface.
1import { Tree, formatFiles, installPackagesTask } from '@nrwl/devkit';
2import { libraryGenerator } from '@nrwl/workspace/generators';
3
4export default async function (tree: Tree, schema: GeneratorOptions) {
5 await libraryGenerator(tree, { name: `${schema.name}-${schema.type || ''}` });
6 await formatFiles(tree);
7 return () => {
8 installPackagesTask(tree);
9 };
10}
11Adding static options
Static options for a generator don't prompt the user for input. To add a static option, define a key in the schema.json file with the option name, and define an object with its type, description, and optional default value.
1{
2 "$schema": "http://json-schema.org/schema",
3 "id": "my-generator",
4 "type": "object",
5 "properties": {
6 "name": {
7 "type": "string",
8 "description": "Library name",
9 "$default": {
10 "$source": "argv",
11 "index": 0
12 }
13 },
14 "type": {
15 "type": "string",
16 "description": "Provide the library type, such as 'data-access' or 'state'"
17 }
18 },
19 "required": ["name"]
20}
21If you run the generator without providing a value for the type, it is not included in the generated name of the library.
Adding dynamic prompts
Dynamic options can prompt the user to select from a list of options. To define a prompt, add a x-prompt property to the option object, set the type to list, and define an items array for the choices.
1{
2 "$schema": "http://json-schema.org/schema",
3 "id": "my-generator",
4 "type": "object",
5 "properties": {
6 "name": {
7 "type": "string",
8 "description": "Library name",
9 "$default": {
10 "$source": "argv",
11 "index": 0
12 }
13 },
14 "type": {
15 "type": "string",
16 "description": "Provide the library type",
17 "x-prompt": {
18 "message": "Which type of library would you like to generate?",
19 "type": "list",
20 "items": [
21 {
22 "value": "data-access",
23 "label": "Data Access"
24 },
25 {
26 "value": "feature",
27 "label": "Feature"
28 },
29 {
30 "value": "state",
31 "label": "State Management"
32 }
33 ]
34 }
35 }
36 },
37 "required": ["name"]
38}
39Running the generator without providing a value for the type will prompt the user to make a selection.
All configurable schema options
Properties tagged with ⚠️ are required. Others are optional.
Schema
1{
2 "properties": {
3 "name": {} // see Properties
4 },
5 "required": [],
6 "description": "",
7 "definitions": {}, // same as "properties"
8 "additionalProperties": false
9}
10⚠️ properties
The properties of a generator. Properties are listed by name:
1{
2 "properties_name": {
3 // properties configuration
4 }
5}
6The available options of the properties' configuration can be seen in the Properties section.
required
The property keys that are required. Example:
1{
2 "properties": {
3 "name": {
4 "type": "string"
5 },
6 "type": {
7 "type": "string"
8 }
9 },
10 "required": ["name"]
11}
12In this example, the property name is required, while the property type is optional. You can define your TypeScript schema like this:
1interface Schema {
2 name: string; // required
3 type?: string; // optional
4}
5description
The description of your schema for users to understand what they can do with the generator.
Example: A exception class generator.
definitions
Define an auxiliary schema in order to be reused and combined later on. Examples:
1{
2 "$id": "https://example.com/schemas/customer",
3 "$schema": "https://json-schema.org/draft/2020-12/schema",
4
5 "type": "object",
6 "properties": {
7 "first_name": { "type": "string" },
8 "last_name": { "type": "string" },
9 "shipping_address": { "$ref": "/schemas/address" },
10 "billing_address": { "$ref": "/schemas/address" }
11 },
12 "required": [
13 "first_name",
14 "last_name",
15 "shipping_address",
16 "billing_address"
17 ],
18
19 "$defs": {
20 "address": {
21 "$id": "/schemas/address",
22 "$schema": "http://json-schema.org/draft-07/schema#",
23
24 "type": "object",
25 "properties": {
26 "street_address": { "type": "string" },
27 "city": { "type": "string" },
28 "state": { "$ref": "#/definitions/state" }
29 },
30 "required": ["street_address", "city", "state"],
31
32 "definitions": {
33 "state": { "enum": ["CA", "NY", "... etc ..."] }
34 }
35 }
36 }
37}
38In this example, we defined the state in the definitions and reference it later by $ref.
Reference 1: JSON Schema > Definitions & References
Reference 2: Understanding JSON Schema > Extending Recursive Schemas
additionalProperties
Specify whether the additional properties in the input are allowed. Example:
1{
2 "type": "object",
3 "properties": {
4 "number": { "type": "number" },
5 "street_name": { "type": "string" },
6 "street_type": { "enum": ["Street", "Avenue", "Boulevard"] }
7 },
8 "additionalProperties": false
9}
10In this example, this schema only accepts the properties that are explicitly defined in the properties object such like:
1{ "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue" }
2Any additional properties will be considered invalid.
1{
2 "number": 1600,
3 "street_name": "Pennsylvania",
4 "street_type": "Avenue",
5 "direction": "NW"
6}
7The above examples are from Understanding JSON schema > Additional Properties. There are more details in that tutorial.
Properties
1{
2 "type": "",
3 "required": [],
4 "enum": [],
5 "properties": {},
6 "oneOf": [],
7 "anyOf": [],
8 "allOf": [],
9 "items": [],
10 "alias": "",
11 "aliases": [],
12 "description": "",
13 "format": "",
14 "visible": false,
15 "default": "",
16 "$ref": "",
17 "$default": {
18 "$source": "argv",
19 "index": 0
20 },
21 "additionalProperties": false,
22 "x-prompt": {
23 "message": "",
24 "type": "",
25 "items": [],
26 "multiselect": false
27 },
28 "x-deprecated": false
29}
30Options available in number type:
1{
2 "multipleOf": 5,
3 "minimum": 5,
4 "exclusiveMinimum": 4,
5 "maximum": 200,
6 "exclusiveMaximum": 201
7}
8Options available in string type:
1{
2 "pattern": "\\d+",
3 "minLength": 10,
4 "maxLength": 100
5}
6type
The type of the input. Can be one of string, number, bigint, boolean, object or array.
Example:
1{
2 "type": "string",
3 "minLength": "10"
4}
5required
The property keys that are required. Example:
1{
2 "properties": {
3 "a": {
4 "type": "boolean"
5 },
6 "b": {
7 "type": "boolean"
8 }
9 },
10 "required": ["a"]
11}
12In this example, the property a is required, while the property b is optional.
enum
Make sure that the value is in the enumeration. Example:
1{
2 "type": "string",
3 "enum": ["foo", "bar"]
4
5 // valid case: `foo`, `bar`
6 // invalid case: any other string like `hello`
7}
8properties
The sub-properties of a property. Example:
1{
2 "index": {
3 "description": "Configures the generation of the application's HTML index.",
4 "type": "object",
5 "description": "",
6 "properties": {
7 "input": {
8 "type": "string",
9 "minLength": 1,
10 "description": "The path of a file to use for the application's generated HTML index."
11 },
12 "output": {
13 "type": "string",
14 "minLength": 1,
15 "default": "index.html",
16 "description": "The output path of the application's generated HTML index file. The full provided path will be used and will be considered relative to the application's configured output path."
17 }
18 },
19 "required": ["input"]
20 }
21}
22In this example, the property index is a object, which accepts two properties: input and output.
oneOf
Only accepts a value that matches one of the condition properties. Example:
1{
2 "sourceMap": {
3 "description": "Output sourcemaps. Use 'hidden' for use with error reporting tools without generating sourcemap comment.",
4 "default": true,
5 "oneOf": [
6 {
7 "type": "boolean"
8 },
9 {
10 "type": "string"
11 }
12 ]
13 }
14}
15In this example, sourceMap accepts a value whose type is either boolean or string. Another example:
1{
2 "optimization": {
3 "description": "Enables optimization of the build output.",
4 "oneOf": [
5 {
6 "type": "object",
7 "properties": {
8 "scripts": {
9 "type": "boolean",
10 "description": "Enables optimization of the scripts output.",
11 "default": true
12 },
13 "styles": {
14 "type": "boolean",
15 "description": "Enables optimization of the styles output.",
16 "default": true
17 }
18 },
19 "additionalProperties": false
20 },
21 {
22 "type": "boolean"
23 }
24 ]
25 }
26}
27optimization accepts either an object that includes scripts and styles properties, or a boolean that switches the optimization on or off.
anyOf
Only accepts a value that matches one of the condition properties. Example:
1{
2 "format": {
3 "type": "string",
4 "description": "ESLint Output formatter (https://eslint.org/docs/user-guide/formatters).",
5 "default": "stylish",
6 "anyOf": [
7 {
8 "enum": [
9 "stylish",
10 "compact",
11 "codeframe",
12 "unix",
13 "visualstudio",
14 "table",
15 "checkstyle",
16 "html",
17 "jslint-xml",
18 "json",
19 "json-with-metadata",
20 "junit",
21 "tap"
22 ]
23 },
24 { "minLength": 1 }
25 ]
26 }
27}
28In this example, format accepts a string listed in the enum property, and/or a string whose minimum length is larger than 1.
allOf
Only accepts a value that matches all the condition properties. Example:
1{
2 "a": {
3 "type": "number",
4 "allOf": [{ "multipleOf": 5 }, { "multipleOf": 3 }]
5 }
6}
7In this example, a only accepts a value that can be divided by 5 and 3.
alias
The alias of this property. Example:
1{
2 "tags": {
3 "type": "string",
4 "description": "Add tags to the project (used for linting)",
5 "alias": "t"
6 },
7 "directory": {
8 "type": "string",
9 "description": "A directory where the project is placed",
10 "alias": "d"
11 }
12}
13You can pass either --tags or -t to provide the value of the property tag; either --directory or -d to provide the value of the property directory.
aliases
Mostly same as alias, but it can accept multiple aliases. Example:
1{
2 "directory": {
3 "description": "Directory where the generated files are placed.",
4 "type": "string",
5 "aliases": ["dir", "path"]
6 }
7}
8You can pass either --dir, --path or even --directory to provide the value of the property directory.
description
The description for users of your property. Example:
1{
2 "flat": {
3 "description": "Flag to indicate if a directory is created.",
4 "type": "boolean",
5 "default": false
6 }
7}
8format
The format of this property. Available options are: path, html-selector, etc. Example:
1{
2 "prefix": {
3 "type": "string",
4 "format": "html-selector",
5 "description": "The prefix to apply to generated selectors.",
6 "alias": "p"
7 }
8}
9In this example, the value provided for prefix should be formatted using the html-selector schema.
visible
Indicate whether the property should be visible in the configuration UI. Example:
1{
2 "path": {
3 "format": "path",
4 "visible": false
5 }
6}
7In this example, the path won't be visible in the configuration UI, and will apply a default value.
default
The default value of this property. Example:
1{
2 "linter": {
3 "description": "The tool to use for running lint checks.",
4 "type": "string",
5 "enum": ["eslint", "tslint"],
6 "default": "eslint"
7 }
8}
9In this example, linter will pick eslint when users do not provide the value explicitly.
$ref
Reference to a schema. Examples can be seen in the definitions section.
$default
The default source of this property. The full declaration of $default is:
1// with ? - optional
2// without ? - required
3// | - or
4$default?: { $source: 'argv'; index: number } | { $source: 'projectName' };
5Example of $source: argv:
1{
2 "name": {
3 "type": "string",
4 "description": "Library name",
5 "$default": {
6 "$source": "argv",
7 "index": 0
8 },
9 "x-prompt": "What name would you like to use for the library?",
10 "pattern": "^[a-zA-Z].*$"
11 }
12}
13name will pick the first argument of the command line as the default value.
Example of $source: projectName:
1{
2 "project": {
3 "type": "string",
4 "description": "The name of the project.",
5 "alias": "p",
6 "$default": {
7 "$source": "projectName"
8 },
9 "x-prompt": "What is the name of the project for the migration?"
10 }
11}
12project will pick the default project name as the default value.
additionalProperties
See the above additionalProperties section.
x-prompt
Prompt and help user to input the value of the property. It can be a string or a object. The full declaration is:
1// with ? - optional
2// without ? - required
3// | - or
4'x-prompt'?:
5 | string
6 | { message: string; type: string; items: any[]; multiselect?: boolean };
7The string x-prompt example:
1{
2 "name": {
3 "type": "string",
4 "description": "Library name",
5 "$default": {
6 "$source": "argv",
7 "index": 0
8 },
9 "x-prompt": "What is your desired library name?"
10 }
11}
12The object example can be seen at Adding dynamic prompts.
⚠️ x-prompt > message
The prompt message.
Example: Which type of library would you like to generate?
⚠️ x-prompt > type
The type of the prompt.
⚠️ x-prompt > items
The choice of the prompt. The x-prompt.type must be list. The declaration of items is:
1// with ? - optional
2// without ? - required
3// | - or
4items?: (string | { name: string; message: string })[];
5Example that contains value and label:
1{
2 "style": {
3 "description": "The file extension to be used for style files.",
4 "type": "string",
5 "default": "css",
6 "enum": ["css", "scss", "sass", "less"],
7 "x-prompt": {
8 "message": "Which stylesheet format would you like to use?",
9 "type": "list",
10 "items": [
11 {
12 "value": "css",
13 "label": "CSS"
14 },
15 {
16 "value": "scss",
17 "label": "SASS(.scss) [ http://sass-lang.com ]"
18 },
19 {
20 "value": "sass",
21 "label": "SASS(.sass) [ http://sass-lang.com ]"
22 },
23 {
24 "value": "less",
25 "label": "LESS [ http://lesscss.org ]"
26 }
27 ]
28 }
29 }
30}
31x-prompt > multiselect
Allow to multi-select in the prompt.
x-deprecated
Indicate whether the property is deprecated. Can be a boolean or a string. The boolean example:
1{
2 "setupFile": {
3 "description": "The name of a setup file used by Jest. (use Jest config file https://jestjs.io/docs/en/configuration#setupfilesafterenv-array)",
4 "type": "string",
5 "x-deprecated": true
6 }
7}
8This indicates that the property setupFile is deprecated without a reason. The string example:
1{
2 "tsSpecConfig": {
3 "type": "string",
4 "description": "The tsconfig file for specs.",
5 "x-deprecated": "Use the `tsconfig` property for `ts-jest` in the e2e project `jest.config.js` file. It will be removed in the next major release."
6 }
7}
8This indicates that users should use the tsconfig property rather than specify this property.
number specific: multipleOf
Make sure that the number can be divided by the specified number. Example:
1{
2 "a": {
3 "type": "number",
4 "multipleOf": 5
5 }
6}
7In this example, a only accepts the value that can be divided by 5.
number specific: minimum
Make sure that the number is greater than or equal to the specified number.
1{
2 "value": {
3 "type": "number",
4 "minimum": 5
5 }
6}
7In this example, value only accepts a value that is greater than or equal to 5 (value >= 5).
You can read more at Understanding JSON schema.
number specific: exclusiveMinimum
Make sure that the number is greater than the specified number.
1{
2 "value": {
3 "type": "number",
4 "exclusiveMinimum": 4
5 }
6}
7In this example, value only accepts a value that is greater than 4 (value > 4).
You can read more at Understanding JSON schema.
number specific: maximum
Make sure that the number is less than or equal to the specified number.
1{
2 "value": {
3 "type": "number",
4 "maximum": 200
5 }
6}
7In this example, value only accepts a value that is less than or equal to 200 (value <= 200).
You can read more at Understanding JSON schema.
number specific: exclusiveMaximum
Make sure that the number is less than the specified number.
1{
2 "value": {
3 "type": "number",
4 "maximum": 201
5 }
6}
7In this example, value only accepts a value that is less than 201 (value < 201).
You can read more at Understanding JSON schema.
string specific: pattern
Make sure that the string matches the Regexp pattern.
1{
2 "value": {
3 "type": "string",
4 "pattern": "^\\d+$"
5 }
6}
7In this example, value requires the value to match the ^\\d+$ pattern, which is a regular expression that matches a string that contains only digits.
string specific: minLength
Make sure that the string length is greater than or equal to the specified value.
1{
2 "value": {
3 "type": "string",
4 "minLength": 10
5 }
6}
7In this example, value requires the value to be at least 10 characters long.
string specific: maxLength
Make sure that the string length is less than or equal to the specified value.
1{
2 "value": {
3 "type": "string",
4 "maxLength": 10
5 }
6}
7In this example, value requires the value to be at most 10 characters long.
More information
The current configurable options (and its parse method) can be found here. You would need a basic knowledge of TypeScript to read this.
Most examples are referenced from the codebase of Nx. Thanks to everyone who have ever contributed to Nx!