Gerador de Gerador do Nx
Adiciona um Nx Generator a um projeto TypeScript para ajudar a automatizar tarefas repetitivas como scaffolding de componentes ou imposição de estruturas de projeto específicas.
Utilização
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 projeto pluginProject
especificado:
Directorysrc/<name>/
- schema.json Esquema para entrada do generator
- schema.d.ts Tipos TypeScript para o esquema
- generator.ts Implementação inicial do generator
- generator.spec.ts Testes para o generator
- generators.json Configuração Nx para definir seus generators
- package.json Criado ou atualizado com 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 esta issue do GitHub sobre suporte a ESM).
Generators Locais
Selecione seu projeto local nx-plugin
ao executar o generator ts#nx-generator
, e especifique um nome, diretório opcional e descrição.
Definindo o Esquema
O arquivo schema.json
define as opções aceitas pelo seu generator. 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": "What is the name of your component?"}
Para opções booleanas, use um prompt sim/não:
"withTests": { "type": "boolean", "description": "Whether to generate test files", "x-prompt": "Would you like to generate test files?"}
Seleções Dropdown
Para opções com um conjunto fixo de escolhas, use enum
para permitir seleção entre as 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 seleção entre projetos existentes no workspace:
"project": { "type": "string", "description": "The project to add the component to", "x-prompt": "Which project would you like to add the component to?", "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 via linha de comando:
"name": { "type": "string", "description": "Component name", "x-priority": "important", "$default": { "$source": "argv", "index": 0 }}
Isso permite executar o generator como nx g your-generator my-component
ao invés de nx g your-generator --name=my-component
.
Definindo Prioridades
Use a propriedade x-priority
para indicar opções 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 e 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 Nx Generator.
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:
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 as opções const { name, directory = 'src/components', withTests = true } = options; // ...}
Implementando um Generator
Após criar o generator como acima, você pode escrever sua implementação em generator.ts
.
Um generator é uma função que modula um sistema de arquivos virtual (Tree
), lendo e escrevendo arquivos para fazer as alterações desejadas. As mudanças no Tree
só são escritas em disco quando o generator termina, exceto em modo “dry-run”.
Aqui estão operações comuns que você pode realizar no 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
Você pode gerar arquivos com o utilitário generateFiles
do @nx/devkit
. Isso permite definir templates em sintaxe EJS e substituir variáveis.
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
Você pode usar o método tsAstReplace
exposto pelo Nx Plugin for AWS para substituir partes de uma AST TypeScript.
import { tsAstReplace } from '@aws/nx-plugin/sdk/utils/ast';import * as ts from 'typescript';
// Exemplo: Incrementar número de versão em um arquivotsAstReplace( tree, 'path/to/version.ts', 'VariableDeclaration:has(Identifier[name="VERSION"]) NumericLiteral', (node: ts.NumericLiteral) => ts.factory.createNumericLiteral(Number(node.text) + 1));
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 { formatFilesInSubtree } from '@aws/nx-plugin/sdk/utils/format';
// Formatar todos os arquivos modificadosawait formatFilesInSubtree(tree, 'optional/path/to/format');
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;});
Estendendo um Generator do Nx Plugin for AWS
Você pode importar generators do Nx Plugin for AWS e estendê-los ou compô-los conforme desejar. Por exemplo, criar um generator que estende um projeto TypeScript:
import { tsProjectGenerator } from '@aws/nx-plugin/sdk/ts';
export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => { const callback = await tsProjectGenerator(tree, { ... });
// Estenda o generator de projeto TypeScript aqui
// Retorne o callback para garantir instalação de dependências // Você pode encapsular o callback para operações adicionais return callback;};
Generators OpenAPI
Você pode usar e estender os generators que usamos para clients e hooks TypeScript de forma similar:
import { openApiTsClientGenerator } from '@aws/nx-plugin/sdk/open-api';
export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => { await openApiTsClientGenerator(tree, { ... });
// Adicione arquivos adicionais aqui};
Também expomos um método para construir estruturas de dados que permitem iterar sobre operações em especificações OpenAPI e instrumentar sua própria geração de código:
import { buildOpenApiCodeGenerationData } from '@aws/nx-plugin/sdk/open-api.js';
export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => { const data = await buildOpenApiCodeGenerationData(tree, 'path/to/spec.json');
generateFiles( tree, joinPathFragments(__dirname, 'files'), // Diretório de templates 'path/to/output', // Diretório de saída data, );};
Isso permite escrever templates como:
export const myOperationNames = [<%_ allOperations.forEach((op) => { _%> '<%- op.name %>',<%_ }); _%>];
Consulte o repositório no GitHub para exemplos mais complexos.
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('your generator', () => { let tree;
beforeEach(() => { // Criar workspace vazio tree = createTreeWithEmptyWorkspace();
// Adicionar arquivos pré-existentes tree.write( 'project.json', JSON.stringify({ name: 'test-project', sourceRoot: 'src', }), );
tree.write('src/existing-file.ts', 'export const existing = true;'); });
it('should generate expected files', async () => { // Executar o generator await yourGenerator(tree, { name: 'test', // Adicionar outras opções necessárias });
// Verificar criação de arquivos expect(tree.exists('src/test/file.ts')).toBeTruthy();
// Verificar conteúdo const content = tree.read('src/test/file.ts', 'utf-8'); expect(content).toContain('export const test');
// Snapshots também podem ser usados expect(tree.read('src/test/file.ts', 'utf-8')).toMatchSnapshot(); });
it('should update existing files', async () => { await yourGenerator(tree, { name: 'test', // Adicionar outras opções necessárias });
const content = tree.read('src/existing-file.ts', 'utf-8'); expect(content).toContain('import { test } from'); });
it('should handle errors', async () => { await expect( yourGenerator(tree, { name: 'invalid', // Opções que devem causar erro }), ).rejects.toThrow('Mensagem de erro esperada'); });});
Pontos-chave para testar generators:
- Use
createTreeWithEmptyWorkspace()
para criar sistema de arquivos virtual - Configure arquivos pré-requisitos antes de executar o generator
- Teste criação de novos arquivos e atualizações de existentes
- Use snapshots para conteúdo complexo
- Teste condições de erro para garantir falha controlada
Contribuindo com Generators para @aws/nx-plugin
Você também pode usar ts#nx-generator
para estruturar um generator dentro de @aws/nx-plugin
.
Quando executado em nosso repositório, este generator criará os seguintes arquivos:
Directorypackages/nx-plugin/src/<name>/
- schema.json Esquema para entrada do generator
- schema.d.ts Tipos TypeScript para o esquema
- generator.ts Implementação do generator
- generator.spec.ts Testes para o generator
Directorydocs/src/content/docs/guides/
- <name>.mdx Página de documentação do generator
- packages/nx-plugin/generators.json Atualizado para incluir seu generator
Você pode então começar a implementar seu generator.