Gerador de Gerador Nx
Adiciona um Nx Generator a um projeto TypeScript, para ajudá-lo a automatizar tarefas repetitivas, como scaffolding de componentes ou aplicação de estruturas de projeto específicas.
Gerar um Gerador
Seção intitulada “Gerar um Gerador”Você pode gerar um gerador de duas maneiras:
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- 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
| 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>) |
| preferInstallDependencies | boolean | true | Se deve preferir instalar dependências após a execução do gerador. Defina como false para adiar a instalação ao executar múltiplos geradores em lote (uma instalação ainda é executada se necessário para que os geradores subsequentes possam calcular o grafo de projetos Nx); instale uma vez no final. |
Saída do Gerador
Seção intitulada “Saída do Gerador”O gerador criará os seguintes arquivos de projeto dentro do project fornecido:
Directorysrc/<name>/
- schema.json Schema para entrada do seu gerador
- schema.d.ts Tipos TypeScript para seu schema
- generator.ts Implementação stub do gerador
- generator.spec.ts Testes para seu gerador
- README.md Documentação para seu gerador
- generators.json Configuração Nx para definir seus geradores
- package.json Criado ou atualizado para adicionar uma entrada “generators”
- tsconfig.json Atualizado para usar CommonJS
Modificação do Projeto
Este gerador atualizará o project selecionado para usar CommonJS, pois os Nx Generators atualmente suportam apenas CommonJS (consulte este issue do GitHub para suporte ESM).
Geradores Locais
Seção intitulada “Geradores Locais”Selecione seu projeto nx-plugin local ao executar o gerador ts#nx-generator, e especifique um nome e opcionalmente um diretório e descrição.
Definindo o Schema
Seção intitulada “Definindo o Schema”O arquivo schema.json define as opções que seu gerador 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": { // Your generator options go here }, "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 gerador 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, você pode usar 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
Seção intitulada “Seleções Dropdown”Para opções com um conjunto fixo de escolhas, use enum para que os usuários possam selecionar 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
Seção intitulada “Dropdown de Seleção de Projeto”Um padrão comum é permitir que os usuários selecionem 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" diz ao Nx para preencher o dropdown com todos os projetos no workspace.
Argumentos Posicionais
Seção intitulada “Argumentos Posicionais”Você pode configurar opções para serem passadas como argumentos posicionais ao executar o gerador a partir da linha de comando:
"name": { "type": "string", "description": "Component name", "x-priority": "important", "$default": { "$source": "argv", "index": 0 }}Isso permite que os usuários executem seu gerador 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 quais opções são mais importantes:
"name": { "type": "string", "description": "Component name", "x-priority": "important"}As opções podem ter prioridades de "important" ou "internal". Isso ajuda o Nx a ordenar propriedades na extensão Nx VSCode e no Nx CLI.
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 schemas, consulte a documentação de Opções de Gerador Nx.
Tipos TypeScript com schema.d.ts
Seção intitulada “Tipos TypeScript com schema.d.ts”Junto com schema.json, o gerador cria um arquivo schema.d.ts que fornece tipos TypeScript para as opções do seu gerador:
export interface YourGeneratorSchema { name: string; directory?: string; withTests?: boolean;}Esta interface é usada na implementação do seu gerador para fornecer segurança de tipo e autocompletar:
import { YourGeneratorSchema } from './schema';
export default async function (tree: Tree, options: YourGeneratorSchema) { // TypeScript knows the types of all your options const { name, directory = 'src/components', withTests = true } = options; // ...}Implementando um Gerador
Seção intitulada “Implementando um Gerador”Após criar o novo gerador como acima, você pode escrever sua implementação em generator.ts.
Um gerador é uma função que modifica um sistema de arquivos virtual (a Tree), lendo e escrevendo arquivos para fazer as alterações desejadas. As alterações da Tree só são gravadas no disco quando o gerador termina de executar, a menos que seja executado no modo “dry-run”. Um gerador vazio se parece com o seguinte:
export const myGenerator = async (tree: Tree, options: MyGeneratorSchema) => { // Use the tree to apply changes};
export default myGenerator;Aqui estão algumas operações comuns que você pode querer realizar no seu gerador:
Lendo e Escrevendo Arquivos
Seção intitulada “Lendo e Escrevendo Arquivos”// Read a fileconst content = tree.read('path/to/file.ts', 'utf-8');
// Write a filetree.write('path/to/new-file.ts', 'export const hello = "world";');
// Check if a file existsif (tree.exists('path/to/file.ts')) { // Do something}Gerando Arquivos a partir de Templates
Seção intitulada “Gerando Arquivos a partir de Templates”Você pode gerar arquivos com o utilitário generateFiles do @nx/devkit. Isso permite que você defina templates na sintaxe EJS e substitua variáveis.
import { generateFiles, joinPathFragments } from '@nx/devkit';
// Generate files from templatesgenerateFiles( tree, joinPathFragments(import.meta.dirname, 'files'), // Template directory 'path/to/output', // Output directory { // Variables to replace in templates name: options.name, nameCamelCase: camelCase(options.name), nameKebabCase: kebabCase(options.name), // Add more variables as needed },);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 geradores. GritQL suporta múltiplas linguagens incluindo TypeScript, JavaScript, Python, HCL (Terraform) e mais — então você pode usar a mesma sintaxe de padrão em toda a 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 foram feitas alteraçõesmatchGritQL(tree, filePath, pattern)— verifica se um padrão GritQL corresponde em algum lugar em um arquivo e retornaPromise<boolean>
import { applyGritQL, matchGritQL } from '@aws/nx-plugin/sdk/utils/ast';
// Replace a function callawait applyGritQL( tree, 'src/app.ts', '`console.log($msg)` => `logger.info($msg)`',);
// Add an element to an array only if not already presentawait applyGritQL( tree, 'src/plugins.ts', '`plugins: [$items]` => `plugins: [$items, myPlugin()]` where { $items <: not contains `myPlugin` }',);
// Check if a pattern exists before making changesif (!(await matchGritQL(tree, filePath, '`import { Auth } from "./auth"`'))) { // Add the import}Padrões GritQL também funcionam em arquivos não-TypeScript. Prefixe seu padrão com language <name> para direcionar outras linguagens:
// Python: replace print statements with logging callsawait applyGritQL( tree, 'src/handler.py', 'language python\n`print($msg)` => `logger.info($msg)`',);Padrões GritQL usam snippets de código delimitados por backtick 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';
// Add dependencies to 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';
// Format all files that were modifiedawait formatFilesInSubtree(tree, 'optional/path/to/format');Lendo e Atualizando Arquivos JSON
Seção intitulada “Lendo e Atualizando Arquivos JSON”import { readJson, updateJson } from '@nx/devkit';
// Read a JSON fileconst packageJson = readJson(tree, 'package.json');
// Update a JSON fileupdateJson(tree, 'tsconfig.json', (json) => { json.compilerOptions = { ...json.compilerOptions, strict: true, }; return json;});Estendendo um Gerador do Nx Plugin for AWS
Seção intitulada “Estendendo um Gerador do Nx Plugin for AWS”Você pode importar geradores do Nx Plugin for AWS e estendê-los ou compô-los como desejar, por exemplo, você pode querer criar um gerador que se baseia em um projeto TypeScript:
import { tsProjectGenerator } from '@aws/nx-plugin/sdk/ts';
export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => { const callback = await tsProjectGenerator(tree, { ... });
// Extend the TypeScript project generator here
// Return the callback to ensure dependencies are installed. // You can wrap the callback if you wish to perform additional operations in the generator callback. return callback;};Geradores OpenAPI
Seção intitulada “Geradores OpenAPI”Você pode usar e estender os geradores que usamos para clientes e hooks TypeScript de maneira similar ao acima:
import { openApiTsClientGenerator } from '@aws/nx-plugin/sdk/open-api';
export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => { await openApiTsClientGenerator(tree, { ... });
// Add additional files here};Também expomos um método que permite construir uma estrutura de dados que pode ser usada para iterar sobre operações em uma especificação OpenAPI e, portanto, instrumentar sua própria geração de código, por exemplo:
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(import.meta.dirname, 'files'), // Template directory 'path/to/output', // Output directory data, );};O que então permite que você escreva templates como:
export const myOperationNames = [<%_ allOperations.forEach((op) => { _%> '<%- op.name %>',<%_ }); _%>];Consulte o código-fonte no GitHub para exemplos de templates mais complexos.
Executando Seu Gerador
Seção intitulada “Executando Seu Gerador”Você pode executar seu gerador de duas maneiras:
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-run- 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
Testando Seu Gerador
Seção intitulada “Testando Seu Gerador”Testes unitários para geradores são diretos de implementar. Aqui está um padrão típico:
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';import { yourGenerator } from './generator.js';
describe('your generator', () => { let tree;
beforeEach(() => { // Create an empty workspace tree tree = createTreeWithEmptyWorkspace();
// Add any files that should already exist in the tree 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 () => { // Run the generator await yourGenerator(tree, { name: 'test', // Add other required options });
// Check that files were created expect(tree.exists('src/test/file.ts')).toBeTruthy();
// Check file content const content = tree.read('src/test/file.ts', 'utf-8'); expect(content).toContain('export const test');
// You can also use snapshots expect(tree.read('src/test/file.ts', 'utf-8')).toMatchSnapshot(); });
it('should update existing files', async () => { // Run the generator await yourGenerator(tree, { name: 'test', // Add other required options });
// Check that existing files were updated const content = tree.read('src/existing-file.ts', 'utf-8'); expect(content).toContain('import { test } from'); });
it('should handle errors', async () => { // Expect the generator to throw an error in certain conditions await expect( yourGenerator(tree, { name: 'invalid', // Add options that should cause an error }), ).rejects.toThrow('Expected error message'); });});Pontos-chave para testar geradores:
- Use
createTreeWithEmptyWorkspace()para criar um sistema de arquivos virtual - Configure quaisquer arquivos pré-requisitos antes de executar o gerador
- 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 que seu gerador falhe graciosamente
Contribuindo Geradores para @aws/nx-plugin
Seção intitulada “Contribuindo Geradores para @aws/nx-plugin”Você também pode usar ts#nx-generator para fazer scaffold de um gerador dentro de @aws/nx-plugin.
Quando este gerador é executado em nosso repositório, ele gerará os seguintes arquivos para você:
Directorypackages/nx-plugin/src/<name>/
- schema.json Schema para entrada do seu gerador
- schema.d.ts Tipos TypeScript para seu schema
- generator.ts Implementação do gerador
- generator.spec.ts Testes para seu gerador
Directorydocs/src/content/docs/guides/
- <name>.mdx Página de documentação para seu gerador
- packages/nx-plugin/generators.json Atualizado para incluir seu gerador
- packages/nx-plugin/sdk/<prefix>.ts Atualizado para expor seu gerador do SDK (para geradores
ts#epy#)
Você pode então começar a implementar seu gerador.