Saltearse al contenido

Generador de Generadores de Nx

Agrega un Nx Generator a un proyecto TypeScript, para ayudarte a automatizar tareas repetitivas como la creación de componentes o la aplicación de estructuras de proyecto específicas.

Uso

Generar un Generator

Puedes generar un generator de dos formas:

  1. Instale el Nx Console VSCode Plugin si aún no lo ha hecho
  2. Abra la consola Nx en VSCode
  3. Haga clic en Generate (UI) en la sección "Common Nx Commands"
  4. Busque @aws/nx-plugin - ts#nx-generator
  5. Complete los parámetros requeridos
    • Haga clic en Generate

    Opciones

    Parámetro Tipo Predeterminado Descripción
    pluginProject Requerido string - TypeScript project to add the generator to. We recommend creating a ts#project in a top-level 'tools' directory.
    name Requerido 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>)

    Salida del Generator

    El generator creará los siguientes archivos en el proyecto pluginProject seleccionado:

    • Directorysrc/<name>/
      • schema.json Esquema para la entrada del generator
      • schema.d.ts Tipos TypeScript para el esquema
      • generator.ts Implementación base del generator
      • generator.spec.ts Pruebas para el generator
    • generators.json Configuración de Nx para definir tus generators
    • package.json Creado o actualizado para agregar entrada “generators”
    • tsconfig.json Actualizado para usar CommonJS

    Este generator actualizará el pluginProject seleccionado para usar CommonJS, ya que Nx Generators actualmente solo soporta CommonJS (consulta este issue de GitHub para soporte ESM).

    Generadores Locales

    Selecciona tu proyecto local nx-plugin al ejecutar el generator ts#nx-generator, y especifica un nombre junto con un directorio y descripción opcionales.

    Definiendo el Esquema

    El archivo schema.json define las opciones que acepta tu generator. Sigue el formato JSON Schema con extensiones específicas de Nx.

    Estructura Básica

    Un archivo schema.json tiene la siguiente estructura básica:

    {
    "$schema": "https://json-schema.org/schema",
    "$id": "YourGeneratorName",
    "title": "Your Generator Title",
    "description": "Description of what your generator does",
    "type": "object",
    "properties": {
    // Tus opciones del generator van aquí
    },
    "required": ["requiredOption1", "requiredOption2"]
    }

    Ejemplo Simple

    Aquí un ejemplo simple con algunas opciones 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 Interactivos (CLI)

    Puedes personalizar los prompts mostrados al ejecutar tu generator desde la CLI agregando la propiedad x-prompt:

    "name": {
    "type": "string",
    "description": "Component name",
    "x-prompt": "What is the name of your component?"
    }

    Para opciones booleanas, puedes usar un prompt sí/no:

    "withTests": {
    "type": "boolean",
    "description": "Whether to generate test files",
    "x-prompt": "Would you like to generate test files?"
    }

    Selecciones en Dropdown

    Para opciones con un conjunto fijo de opciones, usa enum para que los usuarios puedan seleccionar:

    "style": {
    "type": "string",
    "description": "The styling approach to use",
    "enum": ["css", "scss", "styled-components", "none"],
    "default": "css"
    }

    Un patrón común es permitir a los usuarios seleccionar entre proyectos existentes:

    "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"
    }

    La propiedad x-dropdown: "projects" indica a Nx que llene el dropdown con todos los proyectos del workspace.

    Argumentos Posicionales

    Puedes configurar opciones para pasarse como argumentos posicionales al ejecutar el generator desde CLI:

    "name": {
    "type": "string",
    "description": "Component name",
    "x-priority": "important",
    "$default": {
    "$source": "argv",
    "index": 0
    }
    }

    Esto permite ejecutar el generator como nx g your-generator my-component en lugar de nx g your-generator --name=my-component.

    Estableciendo Prioridades

    Usa la propiedad x-priority para indicar opciones importantes:

    "name": {
    "type": "string",
    "description": "Component name",
    "x-priority": "important"
    }

    Las prioridades pueden ser "important" o "internal". Esto ayuda a Nx a ordenar propiedades en la extensión VSCode y CLI.

    Valores Predeterminados

    Puedes proveer valores predeterminados:

    "directory": {
    "type": "string",
    "description": "Directory where the component will be created",
    "default": "src/components"
    }

    Más Información

    Para más detalles sobre esquemas, consulta la documentación de Nx Generator Options.

    Tipos TypeScript con schema.d.ts

    Junto con schema.json, el generator crea un archivo schema.d.ts con tipos TypeScript para las opciones:

    export interface YourGeneratorSchema {
    name: string;
    directory?: string;
    withTests?: boolean;
    }

    Esta interfaz se usa en la implementación del generator para seguridad de tipos:

    import { YourGeneratorSchema } from './schema';
    export default async function (tree: Tree, options: YourGeneratorSchema) {
    // TypeScript conoce los tipos de las opciones
    const { name, directory = 'src/components', withTests = true } = options;
    // ...
    }

    Implementando un Generator

    Tras crear el generator, puedes escribir su implementación en generator.ts.

    Un generator es una función que modifica un sistema de archivos virtual (Tree), leyendo y escribiendo archivos. Los cambios se escriben al disco solo al finalizar, a menos que se ejecute en modo “dry-run”.

    Operaciones comunes en un generator:

    Lectura y Escritura de Archivos

    // Leer archivo
    const content = tree.read('path/to/file.ts', 'utf-8');
    // Escribir archivo
    tree.write('path/to/new-file.ts', 'export const hello = "world";');
    // Verificar existencia
    if (tree.exists('path/to/file.ts')) {
    // Hacer algo
    }

    Generar Archivos desde Plantillas

    Puedes generar archivos con generateFiles de @nx/devkit, usando plantillas EJS:

    import { generateFiles, joinPathFragments } from '@nx/devkit';
    // Generar archivos desde plantillas
    generateFiles(
    tree,
    joinPathFragments(__dirname, 'files'), // Directorio de plantillas
    'path/to/output', // Directorio de salida
    {
    // Variables para sustituir
    name: options.name,
    nameCamelCase: camelCase(options.name),
    nameKebabCase: kebabCase(options.name),
    },
    );

    Manipulación de AST TypeScript

    Puedes usar tsAstReplace del Nx Plugin para AWS para modificar ASTs:

    import { tsAstReplace } from '@aws/nx-plugin/sdk/utils/ast';
    import * as ts from 'typescript';
    // Ejemplo: Incrementar versión
    tsAstReplace(
    tree,
    'path/to/version.ts',
    'VariableDeclaration:has(Identifier[name="VERSION"]) NumericLiteral',
    (node: ts.NumericLiteral) =>
    ts.factory.createNumericLiteral(Number(node.text) + 1));

    Agregar Dependencias

    import { addDependenciesToPackageJson } from '@nx/devkit';
    // Agregar dependencias a package.json
    addDependenciesToPackageJson(
    tree,
    {
    'new-dependency': '^1.0.0',
    },
    {
    'new-dev-dependency': '^2.0.0',
    },
    );

    Formatear Archivos Generados

    import { formatFilesInSubtree } from '@aws/nx-plugin/sdk/utils/format';
    // Formatear archivos modificados
    await formatFilesInSubtree(tree, 'optional/path/to/format');

    Leer y Actualizar JSON

    import { readJson, updateJson } from '@nx/devkit';
    // Leer JSON
    const packageJson = readJson(tree, 'package.json');
    // Actualizar JSON
    updateJson(tree, 'tsconfig.json', (json) => {
    json.compilerOptions = {
    ...json.compilerOptions,
    strict: true,
    };
    return json;
    });

    Extender Generators del Nx Plugin para AWS

    Puedes importar y extender generators existentes:

    import { tsProjectGenerator } from '@aws/nx-plugin/sdk/ts';
    export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => {
    const callback = await tsProjectGenerator(tree, { ... });
    // Extender el generator de proyecto TypeScript aquí
    return callback;
    };

    Generadores OpenAPI

    Puedes usar generators para clientes TypeScript:

    import { openApiTsClientGenerator } from '@aws/nx-plugin/sdk/open-api';
    export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => {
    await openApiTsClientGenerator(tree, { ... });
    // Agregar archivos adicionales
    };

    También puedes generar datos para iterar sobre operaciones 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,
    );
    };

    Ejemplo de plantilla EJS:

    files/my-operations.ts.template
    export const myOperationNames = [
    <%_ allOperations.forEach((op) => { _%>
    '<%- op.name %>',
    <%_ }); _%>
    ];

    Consulta el repositorio en GitHub para ejemplos más complejos.

    Ejecutar tu Generator

    Puedes ejecutar tu generator de dos formas:

    1. Instale el Nx Console VSCode Plugin si aún no lo ha hecho
    2. Abra la consola Nx en VSCode
    3. Haga clic en Generate (UI) en la sección "Common Nx Commands"
    4. Busque @my-project/nx-plugin - my-generator
    5. Complete los parámetros requeridos
      • Haga clic en Generate

      Probar tu Generator

      Las pruebas unitarias para generators son sencillas:

      import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
      import { yourGenerator } from './generator';
      describe('your generator', () => {
      let tree;
      beforeEach(() => {
      tree = createTreeWithEmptyWorkspace();
      tree.write('src/existing-file.ts', 'export const existing = true;');
      });
      it('should generate expected files', async () => {
      await yourGenerator(tree, { name: 'test' });
      expect(tree.exists('src/test/file.ts')).toBeTruthy();
      const content = tree.read('src/test/file.ts', 'utf-8');
      expect(content).toContain('export const test');
      });
      it('should handle errors', async () => {
      await expect(
      yourGenerator(tree, { name: 'invalid' })
      ).rejects.toThrow('Expected error message');
      });
      });

      Puntos clave para pruebas:

      • Usar createTreeWithEmptyWorkspace()
      • Configurar archivos preexistentes
      • Verificar creación y modificación de archivos
      • Usar snapshots para contenido complejo
      • Probar condiciones de error

      Contribuir Generators a @aws/nx-plugin

      Puedes usar ts#nx-generator para crear generators dentro de @aws/nx-plugin.

      Al ejecutarlo en nuestro repositorio, generará:

      • 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 Actualizado