# 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. ```typescript export interface GeneratorOptions { name: string; type?: string; } ``` Import the TypeScript schema into your generator file and replace the `any` in your generator function with the interface. ```typescript import { Tree, formatFiles, installPackagesTask } from '@nx/devkit'; import { libraryGenerator } from '@nx/js'; export default async function (tree: Tree, schema: GeneratorOptions) { await libraryGenerator(tree, { name: `${schema.name}-${schema.type || ''}` }); await formatFiles(tree); return () => { installPackagesTask(tree); }; } ``` ## 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. ```json { "$schema": "http://json-schema.org/schema", "id": "my-generator", "type": "object", "properties": { "name": { "type": "string", "description": "Library name", "$default": { "$source": "argv", "index": 0 } }, "type": { "type": "string", "description": "Provide the library type, such as 'data-access' or 'state'" } }, "required": ["name"] } ``` 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. ```json { "$schema": "http://json-schema.org/schema", "id": "my-generator", "type": "object", "properties": { "name": { "type": "string", "description": "Library name", "$default": { "$source": "argv", "index": 0 } }, "type": { "type": "string", "description": "Provide the library type", "x-prompt": { "message": "Which type of library would you like to generate?", "type": "list", "items": [ { "value": "data-access", "label": "Data Access" }, { "value": "feature", "label": "Feature" }, { "value": "state", "label": "State Management" } ] } } }, "required": ["name"] } ``` 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. ```json { "$schema": "http://json-schema.org/schema", "id": "my-generator", "type": "object", "properties": { "name": { "type": "string", "description": "Component name", "$default": { "$source": "argv", "index": 0 } }, "project": { "type": "string", "description": "The project where the component will be located.", "x-prompt": "Which project will this component be located in?", "x-dropdown": "projects" } }, "required": ["name", "project"] } ``` ## All configurable schema options Properties tagged with ⚠️ are required. Others are optional. ### Schema ```jsonc { "properties": { "name": {} // see Properties }, "required": [], "description": "", "definitions": {}, // same as "properties" "additionalProperties": false } ``` #### ⚠️ `properties` The properties of a generator. Properties are listed by name: ```jsonc { "properties_name": { // properties configuration } } ``` The available options of the properties' configuration can be seen in the [Properties](#properties) section. #### `required` The property keys that are required. Example: ```json { "properties": { "name": { "type": "string" }, "type": { "type": "string" } }, "required": ["name"] } ``` In this example, the property `name` is required, while the property `type` is optional. You can define your TypeScript schema like this: ```typescript interface Schema { name: string; // required type?: string; // optional } ``` #### `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: ```json { "$id": "https://example.com/schemas/customer", "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "first_name": { "type": "string" }, "last_name": { "type": "string" }, "shipping_address": { "$ref": "/schemas/address" }, "billing_address": { "$ref": "/schemas/address" } }, "required": [ "first_name", "last_name", "shipping_address", "billing_address" ], "$defs": { "address": { "$id": "/schemas/address", "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "street_address": { "type": "string" }, "city": { "type": "string" }, "state": { "$ref": "#/definitions/state" } }, "required": ["street_address", "city", "state"], "definitions": { "state": { "enum": ["CA", "NY", "... etc ..."] } } } } } ``` In this example, we defined the `state` in the `definitions` and reference it later by `$ref`. > Reference 1: [JSON Schema > Definitions & References](https://cswr.github.io/JsonSchema/spec/definitions_references/) > > Reference 2: [Understanding JSON Schema > Extending Recursive Schemas](https://json-schema.org/understanding-json-schema/structuring.html?highlight=definitions#bundling) #### `additionalProperties` Specify whether the additional properties in the input are allowed. Example: ```json { "type": "object", "properties": { "number": { "type": "number" }, "street_name": { "type": "string" }, "street_type": { "enum": ["Street", "Avenue", "Boulevard"] } }, "additionalProperties": false } ``` In this example, this schema only accepts the properties that are explicitly defined in the `properties` object such like: ```json { "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue" } ``` Any additional properties will be considered invalid. ```json { "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue", "direction": "NW" } ``` > The above examples are from [Understanding JSON schema > Additional Properties](https://json-schema.org/understanding-json-schema/reference/object.html#additional-properties). > There are more details in that tutorial. ### Properties ```json { "type": "", "required": [], "enum": [], "properties": {}, "oneOf": [], "anyOf": [], "allOf": [], "items": [], "alias": "", "aliases": [], "description": "", "format": "", "visible": false, "default": "", "$ref": "", "$default": { "$source": "argv", "index": 0 }, "additionalProperties": false, "x-prompt": { "message": "", "type": "", "items": [], "multiselect": false }, "x-deprecated": false, "x-priority": "important", "x-dropdown": "projects" } ``` Options available in `number` type: ```json { "multipleOf": 5, "minimum": 5, "exclusiveMinimum": 4, "maximum": 200, "exclusiveMaximum": 201 } ``` Options available in `string` type: ```json { "pattern": "\\d+", "minLength": 10, "maxLength": 100 } ``` #### `type` The type of the input. Can be one of `string`, `number`, `bigint`, `boolean`, `object` or `array`. Example: ```json { "type": "string", "minLength": "10" } ``` #### `required` The property keys that are required. Example: ```json { "properties": { "a": { "type": "boolean" }, "b": { "type": "boolean" } }, "required": ["a"] } ``` 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: ```jsonc { "type": "string", "enum": ["foo", "bar"] // valid case: `foo`, `bar` // invalid case: any other string like `hello` } ``` #### `properties` The sub-properties of a property. Example: ```json { "index": { "description": "Configures the generation of the application's HTML index.", "type": "object", "properties": { "input": { "type": "string", "minLength": 1, "description": "The path of a file to use for the application's generated HTML index." }, "output": { "type": "string", "minLength": 1, "default": "index.html", "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." } }, "required": ["input"] } } ``` 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: ```json { "sourceMap": { "description": "Output sourcemaps. Use 'hidden' for use with error reporting tools without generating sourcemap comment.", "default": true, "oneOf": [ { "type": "boolean" }, { "type": "string" } ] } } ``` In this example, `sourceMap` accepts a value whose type is either `boolean` or `string`. Another example: ```json { "optimization": { "description": "Enables optimization of the build output.", "oneOf": [ { "type": "object", "properties": { "scripts": { "type": "boolean", "description": "Enables optimization of the scripts output.", "default": true }, "styles": { "type": "boolean", "description": "Enables optimization of the styles output.", "default": true } }, "additionalProperties": false }, { "type": "boolean" } ] } } ``` `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: ```json { "format": { "type": "string", "description": "ESLint Output formatter (https://eslint.org/docs/user-guide/formatters).", "default": "stylish", "anyOf": [ { "enum": [ "stylish", "compact", "codeframe", "unix", "visualstudio", "table", "checkstyle", "html", "jslint-xml", "json", "json-with-metadata", "junit", "tap" ] }, { "minLength": 1 } ] } } ``` 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: ```json { "a": { "type": "number", "allOf": [{ "multipleOf": 5 }, { "multipleOf": 3 }] } } ``` In this example, `a` only accepts a value that can be divided by 5 **and** 3. #### `alias` The alias of this property. Example: ```json { "tags": { "type": "string", "description": "Add tags to the project (used for linting)", "alias": "t" }, "directory": { "type": "string", "description": "A directory where the project is placed", "alias": "d" } } ``` 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: ```json { "directory": { "description": "Directory where the generated files are placed.", "type": "string", "aliases": ["dir", "path"] } } ``` 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: ```json { "flat": { "description": "Flag to indicate if a directory is created.", "type": "boolean", "default": false } } ``` #### `format` The format of this property. Available options are: `path`, `html-selector`, etc. Example: ```json { "prefix": { "type": "string", "format": "html-selector", "description": "The prefix to apply to generated selectors.", "alias": "p" } } ``` 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: ```json { "path": { "format": "path", "visible": false } } ``` 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: ```json { "linter": { "description": "The tool to use for running lint checks.", "type": "string", "enum": ["eslint"], "default": "eslint" } } ``` 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`](#definitions) section. #### `$default` The default source of this property. The full declaration of `$default` is: ```typescript // with ? - optional // without ? - required // | - or $default?: { $source: 'argv'; index: number } | { $source: 'projectName' }; ``` Example of `$source: argv`: ```json { "name": { "type": "string", "description": "Library name", "$default": { "$source": "argv", "index": 0 }, "x-prompt": "What name would you like to use for the library?", "pattern": "^[a-zA-Z].*$" } } ``` `name` will pick the first argument of the command line as the default value. Example of `$source: projectName`: ```json { "project": { "type": "string", "description": "The name of the project.", "alias": "p", "$default": { "$source": "projectName" }, "x-prompt": "What is the name of the project for the migration?" } } ``` `project` will pick the default project name as the default value. #### `additionalProperties` See [the above `additionalProperties` section](#additionalproperties). #### `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: ```typescript // with ? - optional // without ? - required // | - or 'x-prompt'?: | string | { message: string; type: string; items: any[]; multiselect?: boolean }; ``` The string `x-prompt` example: ```json { "name": { "type": "string", "description": "Library name", "$default": { "$source": "argv", "index": 0 }, "x-prompt": "What is your desired library name?" } } ``` The object example can be seen at [Adding dynamic prompts](#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: ```typescript // with ? - optional // without ? - required // | - or items?: (string | { name: string; message: string })[]; ``` Example that contains `value` and `label`: ```json { "style": { "description": "The file extension to be used for style files.", "type": "string", "default": "css", "enum": ["css", "scss", "sass", "less"], "x-prompt": { "message": "Which stylesheet format would you like to use?", "type": "list", "items": [ { "value": "css", "label": "CSS" }, { "value": "scss", "label": "SASS(.scss) [ http://sass-lang.com ]" }, { "value": "sass", "label": "SASS(.sass) [ http://sass-lang.com ]" }, { "value": "less", "label": "LESS [ http://lesscss.org ]" } ] } } } ``` ##### `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: ```json { "setupFile": { "description": "The name of a setup file used by Jest. (use Jest config file https://jestjs.io/docs/en/configuration#setupfilesafterenv-array)", "type": "string", "x-deprecated": true } } ``` This indicates that the property `setupFile` is deprecated without a reason. The `string` example: ```json { "tsSpecConfig": { "type": "string", "description": "The tsconfig file for specs.", "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." } } ``` 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. ```json { "directory": { "description": "The directory of the new application.", "type": "string", "x-priority": "important" } } ``` #### `x-dropdown` Populates the list of projects in your workspace to a selection prompt. ```json { "project": { "description": "The project where the component will be located.", "type": "string", "x-prompt": "Which project will this component be located in?", "x-dropdown": "projects" } } ``` #### `number` specific: `multipleOf` Make sure that the number can be divided by the specified number. Example: ```json { "a": { "type": "number", "multipleOf": 5 } } ``` 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. ```json { "value": { "type": "number", "minimum": 5 } } ``` 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](https://json-schema.org/understanding-json-schema/reference/numeric.html#range). #### `number` specific: `exclusiveMinimum` Make sure that the number is greater than the specified number. ```json { "value": { "type": "number", "exclusiveMinimum": 4 } } ``` In this example, `value` **only** accepts a value that is greater than 4 (`value > 4`). You can read more at [Understanding JSON schema](https://json-schema.org/understanding-json-schema/reference/numeric.html#range). #### `number` specific: `maximum` Make sure that the number is less than or equal to the specified number. ```json { "value": { "type": "number", "maximum": 200 } } ``` 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](https://json-schema.org/understanding-json-schema/reference/numeric.html#range). #### `number` specific: `exclusiveMaximum` Make sure that the number is less than the specified number. ```json { "value": { "type": "number", "exclusiveMaximum": 201 } } ``` In this example, `value` **only** accepts a value that is less than 201 (`value < 201`). You can read more at [Understanding JSON schema](https://json-schema.org/understanding-json-schema/reference/numeric.html#range). #### `string` specific: `pattern` Make sure that the string matches the Regexp pattern. ```json { "value": { "type": "string", "pattern": "^\\d+$" } } ``` 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. ```json { "value": { "type": "string", "minLength": 10 } } ``` 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. ```json { "value": { "type": "string", "maxLength": 10 } } ``` 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](https://github.com/nrwl/nx/blob/master/packages/nx/src/utils/params.ts). 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!