Gerador de Gerador do Nx
Adiciona um Nx Generator a um projeto TypeScript para ajudar a automatizar tarefas repetitivas como criação de componentes ou imposição de estruturas de projeto específicas.
Uso
Gerar um Generator
Você pode gerar um generator de duas formas:
- Instale o Nx Console VSCode Plugin se ainda não o fez
- Abra o console Nx no VSCode
- Clique em
Generate (UI)
na seção "Common Nx Commands" - Procure por
@aws/nx-plugin - ts#nx-generator
- Preencha os parâmetros obrigatórios
- Clique em
Generate
pnpm nx g @aws/nx-plugin:ts#nx-generator
yarn nx g @aws/nx-plugin:ts#nx-generator
npx nx g @aws/nx-plugin:ts#nx-generator
bunx nx g @aws/nx-plugin:ts#nx-generator
Você também pode realizar uma execução simulada para ver quais arquivos seriam alterados
pnpm nx g @aws/nx-plugin:ts#nx-generator --dry-run
yarn nx g @aws/nx-plugin:ts#nx-generator --dry-run
npx nx g @aws/nx-plugin:ts#nx-generator --dry-run
bunx nx g @aws/nx-plugin:ts#nx-generator --dry-run
Opções
Parâmetro | Tipo | Padrão | Descrição |
---|---|---|---|
pluginProject Obrigatório | string | - | TypeScript project to add the generator to. We recommend creating a ts#project in a top-level 'tools' directory. |
name Obrigatório | string | - | Generator name |
description | string | - | A description of your generator |
directory | string | - | The directory within the plugin project's source folder to add the generator to (default: <name>) |
Saída do Generator
O generator criará os seguintes arquivos no pluginProject
selecionado:
Directorysrc/<name>/
- schema.json Esquema para entrada do generator
- schema.d.ts Tipos TypeScript para seu esquema
- generator.ts Implementação inicial do generator
- generator.spec.ts Testes para seu generator
- generators.json Configuração Nx para definir seus generators
- package.json Criado ou atualizado para adicionar entrada “generators”
- tsconfig.json Atualizado para usar CommonJS
Este generator atualizará o pluginProject
selecionado para usar CommonJS, pois os Nx Generators atualmente só suportam CommonJS (consulte este problema no GitHub para suporte a ESM).
Generators Locais
Selecione seu projeto local nx-plugin
ao executar o generator ts#nx-generator
, e especifique um nome com diretório e descrição opcionais.
Definindo o Esquema
O arquivo schema.json
define as opções que seu generator aceita. Ele segue o formato JSON Schema com extensões específicas do Nx.
Estrutura Básica
Um arquivo schema.json possui a seguinte estrutura básica:
{ "$schema": "https://json-schema.org/schema", "$id": "YourGeneratorName", "title": "Your Generator Title", "description": "Description of what your generator does", "type": "object", "properties": { // Your generator options go here }, "required": ["requiredOption1", "requiredOption2"]}
Exemplo Simples
Aqui está um exemplo simples com algumas opções básicas:
{ "$schema": "https://json-schema.org/schema", "$id": "ComponentGenerator", "title": "Create a Component", "description": "Creates a new React component", "type": "object", "properties": { "name": { "type": "string", "description": "Component name", "x-priority": "important" }, "directory": { "type": "string", "description": "Directory where the component will be created", "default": "src/components" }, "withTests": { "type": "boolean", "description": "Whether to generate test files", "default": true } }, "required": ["name"]}
Prompts Interativos (CLI)
Você pode personalizar os prompts exibidos ao executar seu generator via CLI adicionando a propriedade x-prompt
:
"name": { "type": "string", "description": "Component name", "x-prompt": "Qual é o nome do seu componente?"}
Para opções booleanas, use um prompt sim/não:
"withTests": { "type": "boolean", "description": "Whether to generate test files", "x-prompt": "Deseja gerar arquivos de teste?"}
Seleções em Dropdown
Para opções com um conjunto fixo de escolhas, use enum
para permitir que usuários selecionem uma das opções:
"style": { "type": "string", "description": "The styling approach to use", "enum": ["css", "scss", "styled-components", "none"], "default": "css"}
Dropdown de Seleção de Projeto
Um padrão comum é permitir que usuários selecionem entre projetos existentes no workspace:
"project": { "type": "string", "description": "The project to add the component to", "x-prompt": "Em qual projeto você deseja adicionar o componente?", "x-dropdown": "projects"}
A propriedade x-dropdown: "projects"
instrui o Nx a preencher o dropdown com todos os projetos do workspace.
Argumentos Posicionais
Você pode configurar opções para serem passadas como argumentos posicionais ao executar o generator pela linha de comando:
"name": { "type": "string", "description": "Component name", "x-priority": "important", "$default": { "$source": "argv", "index": 0 }}
Isso permite que usuários executem seu generator como nx g your-generator meu-componente
em vez de nx g your-generator --name=meu-componente
.
Definindo Prioridades
Use a propriedade x-priority
para indicar quais opções são mais importantes:
"name": { "type": "string", "description": "Component name", "x-priority": "important"}
Opções podem ter prioridades "important"
ou "internal"
. Isso ajuda o Nx a ordenar propriedades na extensão VSCode do NX e na CLI do Nx.
Valores Padrão
Você pode fornecer valores padrão para opções:
"directory": { "type": "string", "description": "Directory where the component will be created", "default": "src/components"}
Mais Informações
Para mais detalhes sobre esquemas, consulte a documentação de Opções do Generator Nx.
Tipos TypeScript com schema.d.ts
Junto com schema.json
, o generator cria um arquivo schema.d.ts
que fornece tipos TypeScript para as opções do generator:
export interface YourGeneratorSchema { name: string; directory?: string; withTests?: boolean;}
Esta interface é usada na implementação do generator para fornecer segurança de tipos e autocompletar:
import { YourGeneratorSchema } from './schema';
export default async function (tree: Tree, options: YourGeneratorSchema) { // TypeScript conhece os tipos de todas suas opções const { name, directory = 'src/components', withTests = true } = options; // ...}
Implementando um Generator
Após criar o novo generator como acima, você pode escrever sua implementação em generator.ts
.
Um generator é uma função que modifica um sistema de arquivos virtual (a Tree
), lendo e escrevendo arquivos para fazer as alterações desejadas. As mudanças na Tree
só são escritas no disco quando o generator termina de executar, a menos que seja executado em modo “dry-run”.
Aqui estão algumas operações comuns que você pode querer realizar em seu generator:
Lendo e Escrevendo Arquivos
// Ler um arquivoconst content = tree.read('path/to/file.ts', 'utf-8');
// Escrever um arquivotree.write('path/to/new-file.ts', 'export const hello = "world";');
// Verificar se um arquivo existeif (tree.exists('path/to/file.ts')) { // Fazer algo}
Gerando Arquivos de Templates
import { generateFiles, joinPathFragments } from '@nx/devkit';
// Gerar arquivos de templatesgenerateFiles( tree, joinPathFragments(__dirname, 'files'), // Diretório do template 'path/to/output', // Diretório de saída { // Variáveis para substituir nos templates name: options.name, nameCamelCase: camelCase(options.name), nameKebabCase: kebabCase(options.name), // Adicione mais variáveis conforme necessário },);
Manipulação de AST (Abstract Syntax Tree) TypeScript
Recomendamos instalar TSQuery para ajudar na manipulação de AST.
import { tsquery } from '@phenomnomnominal/tsquery';import * as ts from 'typescript';
// Exemplo: Incrementar número de versão em um arquivo
// Parsear o conteúdo do arquivo em uma AST TypeScriptconst sourceFile = tsquery.ast(tree.read('path/to/version.ts', 'utf-8'));
// Encontrar nós correspondentes ao seletorconst nodes = tsquery.query( sourceFile, 'VariableDeclaration:has(Identifier[name="VERSION"]) NumericLiteral',);
if (nodes.length > 0) { // Obter o nó do literal numérico const numericNode = nodes[0] as ts.NumericLiteral;
// Obter o número da versão atual e incrementá-lo const currentVersion = Number(numericNode.text); const newVersion = currentVersion + 1;
// Substituir o nó na AST const result = tsquery.replace( sourceFile, 'VariableDeclaration:has(Identifier[name="VERSION"]) NumericLiteral', () => ts.factory.createNumericLiteral(newVersion), );
// Escrever o conteúdo atualizado de volta na tree tree.write( 'path/to/version.ts', ts .createPrinter({ newLine: ts.NewLineKind.LineFeed, }) .printNode(ts.EmitHint.Unspecified, result, sourceFile), );}
Adicionando Dependências
import { addDependenciesToPackageJson } from '@nx/devkit';
// Adicionar dependências ao package.jsonaddDependenciesToPackageJson( tree, { 'new-dependency': '^1.0.0', }, { 'new-dev-dependency': '^2.0.0', },);
Formatando Arquivos Gerados
import { formatFiles } from '@nx/devkit';
// Formatando todos os arquivos modificadosawait formatFiles(tree);
Lendo e Atualizando Arquivos JSON
import { readJson, updateJson } from '@nx/devkit';
// Ler um arquivo JSONconst packageJson = readJson(tree, 'package.json');
// Atualizar um arquivo JSONupdateJson(tree, 'tsconfig.json', (json) => { json.compilerOptions = { ...json.compilerOptions, strict: true, }; return json;});
Executando Seu Generator
Você pode executar seu generator de duas formas:
- Instale o Nx Console VSCode Plugin se ainda não o fez
- Abra o console Nx no VSCode
- Clique em
Generate (UI)
na seção "Common Nx Commands" - Procure por
@my-project/nx-plugin - my-generator
- Preencha os parâmetros obrigatórios
- Clique em
Generate
pnpm nx g @my-project/nx-plugin:my-generator
yarn nx g @my-project/nx-plugin:my-generator
npx nx g @my-project/nx-plugin:my-generator
bunx nx g @my-project/nx-plugin:my-generator
Você também pode realizar uma execução simulada para ver quais arquivos seriam alterados
pnpm nx g @my-project/nx-plugin:my-generator --dry-run
yarn nx g @my-project/nx-plugin:my-generator --dry-run
npx nx g @my-project/nx-plugin:my-generator --dry-run
bunx nx g @my-project/nx-plugin:my-generator --dry-run
Testando Seu Generator
Testes unitários para generators são simples de implementar. Aqui está um padrão típico:
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';import { yourGenerator } from './generator';
describe('seu generator', () => { let tree;
beforeEach(() => { // Criar uma workspace tree vazia tree = createTreeWithEmptyWorkspace();
// Adicionar arquivos que devem existir previamente na tree tree.write( 'project.json', JSON.stringify({ name: 'test-project', sourceRoot: 'src', }), );
tree.write('src/existing-file.ts', 'export const existing = true;'); });
it('deve gerar os arquivos esperados', async () => { // Executar o generator await yourGenerator(tree, { name: 'test', // Adicionar outras opções requeridas });
// Verificar se arquivos foram criados expect(tree.exists('src/test/file.ts')).toBeTruthy();
// Verificar conteúdo do arquivo const content = tree.read('src/test/file.ts', 'utf-8'); expect(content).toContain('export const test');
// Você também pode usar snapshots expect(tree.read('src/test/file.ts', 'utf-8')).toMatchSnapshot(); });
it('deve atualizar arquivos existentes', async () => { // Executar o generator await yourGenerator(tree, { name: 'test', // Adicionar outras opções requeridas });
// Verificar se arquivos existentes foram atualizados const content = tree.read('src/existing-file.ts', 'utf-8'); expect(content).toContain('import { test } from'); });
it('deve lidar com erros', async () => { // Esperar que o generator lance um erro em certas condições await expect( yourGenerator(tree, { name: 'invalid', // Adicionar opções que devem causar um erro }), ).rejects.toThrow('Mensagem de erro esperada'); });});
Pontos-chave para testar generators:
- Use
createTreeWithEmptyWorkspace()
para criar um sistema de arquivos virtual - Configure quaisquer arquivos pré-requisitos antes de executar o generator
- Teste tanto a criação de novos arquivos quanto atualizações em arquivos existentes
- Use snapshots para conteúdo de arquivo complexo
- Teste condições de erro para garantir falha graciosa
Contribuindo com Generators para o @aws/nx-plugin
Você também pode usar ts#nx-generator
para criar um generator dentro do @aws/nx-plugin
.
Quando este generator é executado em nosso repositório, ele gerará os seguintes arquivos para você:
Directorypackages/nx-plugin/src/<name>/
- schema.json Esquema para entrada do generator
- schema.d.ts Tipos TypeScript para seu esquema
- generator.ts Implementação do generator
- generator.spec.ts Testes para seu generator
Directorydocs/src/content/docs/guides/
- <name>.mdx Página de documentação para seu generator
- packages/nx-plugin/generators.json Atualizado para incluir seu generator
Você pode então começar a implementar seu generator.