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.
Utilização
Seção intitulada “Utilização”Gerar um Generator
Seção intitulada “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-generatoryarn nx g @aws/nx-plugin:ts#nx-generatornpx nx g @aws/nx-plugin:ts#nx-generatorbunx nx g @aws/nx-plugin:ts#nx-generatorVocê também pode realizar uma execução simulada para ver quais arquivos seriam alterados
pnpm nx g @aws/nx-plugin:ts#nx-generator --dry-runyarn nx g @aws/nx-plugin:ts#nx-generator --dry-runnpx nx g @aws/nx-plugin:ts#nx-generator --dry-runbunx nx g @aws/nx-plugin:ts#nx-generator --dry-run| Parâmetro | Tipo | Padrão | Descrição |
|---|---|---|---|
| project Obrigatório | string | - | Projeto TypeScript para adicionar o gerador. Recomendamos usar o gerador ts#nx-plugin para criar isso. |
| name Obrigatório | string | - | Nome do gerador |
| description | string | - | Uma descrição do seu gerador |
| directory | string | - | O diretório dentro da pasta de origem do projeto do plugin para adicionar o gerador (padrão: <name>) |
Saída do Generator
Seção intitulada “Saída do Generator”O generator criará os seguintes arquivos no project 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
- README.md Documentação do generator
- generators.json Configuração Nx para definir seus generators
- package.json Criado ou atualizado com entrada “generators”
- tsconfig.json Atualizado para usar CommonJS
Modificação do projeto
Este generator atualizará o project selecionado para usar CommonJS, pois os Nx Generators atualmente só suportam CommonJS (consulte esta issue no GitHub sobre suporte a ESM).
Generators Locais
Seção intitulada “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
Seção intitulada “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
Seção intitulada “Estrutura Básica”Um arquivo schema.json tem 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": { // Suas opções do generator aqui }, "required": ["requiredOption1", "requiredOption2"]}Exemplo Simples
Seção intitulada “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)
Seção intitulada “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 em Dropdown
Seção intitulada “Seleções em 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
Seção intitulada “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
Seção intitulada “Argumentos Posicionais”Você pode configurar opções para serem passadas como argumentos posicionais na 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 em vez de nx g your-generator --name=my-component.
Definindo Prioridades
Seção intitulada “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
Seção intitulada “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
Seção intitulada “Mais Informações”Para mais detalhes sobre esquemas, consulte a documentação de Opções do Nx Generator.
Tipos TypeScript com schema.d.ts
Seção intitulada “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 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
Seção intitulada “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 mudanças desejadas. As mudanças só são escritas no disco quando o generator termina, exceto em modo “dry-run”. Um generator vazio se parece com:
export const myGenerator = async (tree: Tree, options: MyGeneratorSchema) => { // Use a tree para aplicar mudanças};
export default myGenerator;Aqui estão algumas operações comuns em generators:
Lendo e Escrevendo Arquivos
Seção intitulada “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
Seção intitulada “Gerando Arquivos de Templates”Você pode gerar arquivos com o utilitário generateFiles do @nx/devkit, usando templates em sintaxe EJS:
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 substituição name: options.name, nameCamelCase: camelCase(options.name), nameKebabCase: kebabCase(options.name), },);Transformações de Código com GritQL
Seção intitulada “Transformações de Código com GritQL”Você pode usar GritQL para buscar e transformar código-fonte declarativamente em seus generators. GritQL suporta múltiplas linguagens incluindo TypeScript, JavaScript, Python, HCL (Terraform), e mais — então você pode usar a mesma sintaxe de padrões em toda sua stack.
O Nx Plugin for AWS expõe dois helpers:
applyGritQL(tree, filePath, pattern)— aplica um padrão de reescrita GritQL a um arquivo e retornaPromise<boolean>indicando se mudanças foram feitasmatchGritQL(tree, filePath, pattern)— verifica se um padrão GritQL corresponde em algum lugar de um arquivo e retornaPromise<boolean>
import { applyGritQL, matchGritQL } from '@aws/nx-plugin/sdk/utils/ast';
// Substituir uma chamada de funçãoawait applyGritQL( tree, 'src/app.ts', '`console.log($msg)` => `logger.info($msg)`',);
// Adicionar um elemento a um array apenas se não estiver presenteawait applyGritQL( tree, 'src/plugins.ts', '`plugins: [$items]` => `plugins: [$items, myPlugin()]` where { $items <: not contains `myPlugin` }',);
// Verificar se um padrão existe antes de fazer mudançasif (!(await matchGritQL(tree, filePath, '`import { Auth } from "./auth"`'))) { // Adicionar o import}Padrões GritQL também funcionam em arquivos não-TypeScript. Prefixe seu padrão com language <name> para atingir outras linguagens:
// Python: substituir declarações print por chamadas de loggingawait applyGritQL( tree, 'src/handler.py', 'language python\n`print($msg)` => `logger.info($msg)`',);Padrões GritQL usam trechos de código delimitados por crases com $metavariables como curingas. Use => para reescritas e cláusulas where para condições.
Adicionando Dependências
Seção intitulada “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
Seção intitulada “Formatando Arquivos Gerados”import { formatFilesInSubtree } from '@aws/nx-plugin/sdk/utils/format';
// Formatar arquivos modificadosawait formatFilesInSubtree(tree, 'optional/path/to/format');Lendo e Atualizando JSON
Seção intitulada “Lendo e Atualizando JSON”import { readJson, updateJson } from '@nx/devkit';
// Ler JSONconst packageJson = readJson(tree, 'package.json');
// Atualizar JSONupdateJson(tree, 'tsconfig.json', (json) => { json.compilerOptions = { ...json.compilerOptions, strict: true, }; return json;});Estendendo Generators do Nx Plugin for AWS
Seção intitulada “Estendendo Generators do Nx Plugin for AWS”Você pode importar e estender generators existentes:
import { tsProjectGenerator } from '@aws/nx-plugin/sdk/ts';
export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => { const callback = await tsProjectGenerator(tree, { ... });
// Estender o generator aqui
return callback;};Generators OpenAPI
Seção intitulada “Generators OpenAPI”Você pode usar generators para clientes TypeScript e hooks:
import { openApiTsClientGenerator } from '@aws/nx-plugin/sdk/open-api';
export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => { await openApiTsClientGenerator(tree, { ... });
// Adicionar arquivos extras};Também expomos métodos para iterar sobre operações OpenAPI:
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'), 'path/to/output', data, );};Exemplo de template EJS:
export const myOperationNames = [<%_ allOperations.forEach((op) => { _%> '<%- op.name %>',<%_ }); _%>];Consulte o repositório no GitHub para exemplos complexos.
Executando Seu Generator
Seção intitulada “Executando Seu Generator”Execute 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-generatoryarn nx g @my-project/nx-plugin:my-generatornpx nx g @my-project/nx-plugin:my-generatorbunx nx g @my-project/nx-plugin:my-generatorVocê também pode realizar uma execução simulada para ver quais arquivos seriam alterados
pnpm nx g @my-project/nx-plugin:my-generator --dry-runyarn nx g @my-project/nx-plugin:my-generator --dry-runnpx nx g @my-project/nx-plugin:my-generator --dry-runbunx nx g @my-project/nx-plugin:my-generator --dry-runTestando Seu Generator
Seção intitulada “Testando Seu Generator”Testes unitários seguem este padrão:
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';import { yourGenerator } from './generator';
describe('your generator', () => { let tree;
beforeEach(() => { tree = createTreeWithEmptyWorkspace(); tree.write('project.json', JSON.stringify({ name: 'test-project' })); });
it('should generate files', async () => { await yourGenerator(tree, { name: 'test' }); expect(tree.exists('src/test/file.ts')).toBeTruthy(); });});Pontos-chave para testes:
- Use
createTreeWithEmptyWorkspace()para sistema de arquivos virtual - Teste criação e atualização de arquivos
- Use snapshots para conteúdo complexo
- Teste condições de erro
Contribuindo com Generators para @aws/nx-plugin
Seção intitulada “Contribuindo com Generators para @aws/nx-plugin”Use ts#nx-generator para criar generators dentro de @aws/nx-plugin. No nosso repositório, ele gera:
Directorypackages/nx-plugin/src/<name>/
- schema.json
- schema.d.ts
- generator.ts
- generator.spec.ts
Directorydocs/src/content/docs/guides/
- <name>.mdx
- packages/nx-plugin/generators.json Atualizado