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} 5

Import the TypeScript schema into your generator file and replace the any in your generator function with the interface.

1import { Tree, formatFiles, installPackagesTask } from '@nx/devkit'; 2import { libraryGenerator } from '@nx/js'; 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} 11

Adding 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": "https://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} 21

If 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": "https://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} 39

Running the generator without providing a value for the type will prompt the user to make a selection.

Selecting a project

There's a special dynamic option property that populates a selection list with your workspace's projects. Add "x-dropdown": "projects" to your object to provide the prompt.

1{ 2 "$schema": "https://json-schema.org/schema", 3 "id": "my-generator", 4 "type": "object", 5 "properties": { 6 "name": { 7 "type": "string", 8 "description": "Component name", 9 "$default": { 10 "$source": "argv", 11 "index": 0 12 } 13 }, 14 "project": { 15 "type": "string", 16 "description": "The project where the component will be located.", 17 "x-prompt": "Which project will this component be located in?", 18 "x-dropdown": "projects" 19 } 20 }, 21 "required": ["name", "project"] 22} 23

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} 6

The 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} 12

In 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} 5

description

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} 38

In 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} 10

In 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" } 2

Any additional properties will be considered invalid.

1{ 2 "number": 1600, 3 "street_name": "Pennsylvania", 4 "street_type": "Avenue", 5 "direction": "NW" 6} 7

The 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 "x-priority": "important", 30 "x-dropdown": "projects" 31} 32

Options available in number type:

1{ 2 "multipleOf": 5, 3 "minimum": 5, 4 "exclusiveMinimum": 4, 5 "maximum": 200, 6 "exclusiveMaximum": 201 7} 8

Options available in string type:

1{ 2 "pattern": "\\d+", 3 "minLength": 10, 4 "maxLength": 100 5} 6

type

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} 5

required

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} 12

In 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} 8

properties

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 "properties": { 6 "input": { 7 "type": "string", 8 "minLength": 1, 9 "description": "The path of a file to use for the application's generated HTML index." 10 }, 11 "output": { 12 "type": "string", 13 "minLength": 1, 14 "default": "index.html", 15 "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." 16 } 17 }, 18 "required": ["input"] 19 } 20} 21

In 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} 15

In 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} 27

optimization 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} 28

In 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} 7

In 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} 13

You 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} 8

You 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} 8

format

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} 9

In 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} 7

In 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"], 6 "default": "eslint" 7 } 8} 9

In 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' }; 5

Example 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} 13

name 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} 12

project 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 }; 7

The 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} 12

The 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 })[]; 5

Example 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) [ https://sass-lang.com ]" 18 }, 19 { 20 "value": "sass", 21 "label": "SASS(.sass) [ https://sass-lang.com ]" 22 }, 23 { 24 "value": "less", 25 "label": "LESS [ https://lesscss.org ]" 26 } 27 ] 28 } 29 } 30} 31
x-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} 8

This 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} 8

This indicates that users should use the tsconfig property rather than specify this property.

x-priority

Indicates the priority of a property. Can either be important or internal. This will be used to sort the properties on nx.dev, in Nx Console and when calling a generator with --help. important properties are displayed right after required ones while internal properties are shown at the end or hidden.

1{ 2 "directory": { 3 "description": "The directory of the new application.", 4 "type": "string", 5 "x-priority": "important" 6 } 7} 8

x-dropdown

Populates the list of projects in your workspace to a selection prompt.

1{ 2 "project": { 3 "description": "The project where the component will be located.", 4 "type": "string", 5 "x-prompt": "Which project will this component be located in?", 6 "x-dropdown": "projects" 7 } 8} 9

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} 7

In 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} 7

In 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} 7

In 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} 7

In 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 "exclusiveMaximum": 201 5 } 6} 7

In 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} 7

In 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} 7

In 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} 7

In 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!