Saltearse al contenido

Contribuir con un Generador

Vamos a crear un nuevo generador para contribuir a @aws/nx-plugin. Nuestro objetivo será generar un nuevo procedimiento para una API tRPC.

Primero, clonemos el plugin:

Ventana de terminal
git clone git@github.com:awslabs/nx-plugin-for-aws.git

Luego, instalar y construir:

Ventana de terminal
cd nx-plugin-for-aws
pnpm i
pnpm nx run-many --target build --all

Creemos el nuevo generador en packages/nx-plugin/src/trpc/procedure.

¡Proveemos un generador para crear nuevos generadores para que puedas estructurar rápidamente el tuyo! Puedes ejecutar este generador así:

  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
    • pluginProject: @aws/nx-plugin
    • name: ts#trpc-api#procedure
    • directory: trpc/procedure
    • description: Adds a procedure to a tRPC API
  6. Haga clic en Generate

Notarás que se han generado los siguientes archivos:

  • Directorypackages/nx-plugin/src/trpc/procedure
    • schema.json Define las entradas del generador
    • schema.d.ts Interfaz TypeScript que coincide con el schema
    • generator.ts Función que ejecuta Nx como generador
    • generator.spec.ts Pruebas para el generador
  • Directorydocs/src/content/docs/guides/
    • trpc-procedure.mdx Documentación del generador
  • packages/nx-plugin/generators.json Actualizado para incluir el generador

Actualicemos el schema para añadir las propiedades necesarias:

{
"$schema": "https://json-schema.org/schema",
"$id": "tRPCProcedure",
"title": "Adds a procedure to a tRPC API",
"type": "object",
"properties": {
"project": {
"type": "string",
"description": "tRPC API project",
"x-prompt": "Select the tRPC API project to add the procedure to",
"x-dropdown": "projects",
"x-priority": "important"
},
"procedure": {
"description": "The name of the new procedure",
"type": "string",
"x-prompt": "What would you like to call your new procedure?",
"x-priority": "important",
},
"type": {
"description": "The type of procedure to generate",
"type": "string",
"x-prompt": "What type of procedure would you like to generate?",
"x-priority": "important",
"default": "query",
"enum": ["query", "mutation"]
}
},
"required": ["project", "procedure"]
}

Notarás que el generador ya está configurado en packages/nx-plugin/generators.json:

...
"generators": {
...
"ts#trpc-api#procedure": {
"factory": "./src/trpc/procedure/generator",
"schema": "./src/trpc/procedure/schema.json",
"description": "Adds a procedure to a tRPC API"
}
},
...

Para añadir un procedimiento a una API tRPC, necesitamos hacer dos cosas:

  1. Crear un archivo TypeScript para el nuevo procedimiento
  2. Añadir el procedimiento al enrutador

Para crear el archivo TypeScript, usaremos una utilidad llamada generateFiles. Con esta, definimos una plantilla EJS que podemos renderizar en nuestro generador con variables basadas en las opciones del usuario.

Primero, definamos la plantilla en packages/nx-plugin/src/trpc/procedure/files/procedures/__procedureNameKebabCase__.ts.template:

files/procedures/__procedureNameKebabCase__.ts.template
import { publicProcedure } from '../init.js';
import { z } from 'zod/v4';
export const <%- procedureNameCamelCase %> = publicProcedure
.input(z.object({
// TODO: define input
}))
.output(z.object({
// TODO: define output
}))
.<%- procedureType %>(async ({ input, ctx }) => {
// TODO: implement!
return {};
});

En la plantilla, usamos tres variables:

  • procedureNameCamelCase
  • procedureNameKebabCase
  • procedureType

Debemos asegurarnos de pasarlas a generateFiles, junto con el directorio destino (el sourceRoot del proyecto seleccionado), que podemos extraer de la configuración del proyecto.

Actualicemos el generador:

procedure/generator.ts
import {
generateFiles,
joinPathFragments,
readProjectConfiguration,
Tree,
} from '@nx/devkit';
import { TrpcProcedureSchema } from './schema';
import { formatFilesInSubtree } from '../../utils/format';
import camelCase from 'lodash.camelcase';
import kebabCase from 'lodash.kebabcase';
export const trpcProcedureGenerator = async (
tree: Tree,
options: TrpcProcedureSchema,
) => {
const projectConfig = readProjectConfiguration(tree, options.project);
const procedureNameCamelCase = camelCase(options.procedure);
const procedureNameKebabCase = kebabCase(options.procedure);
generateFiles(
tree,
joinPathFragments(__dirname, 'files'),
projectConfig.sourceRoot,
{
procedureNameCamelCase,
procedureNameKebabCase,
procedureType: options.type,
},
);
await formatFilesInSubtree(tree);
};
export default trpcProcedureGenerator;

Ahora actualizaremos el código fuente para incluir el nuevo procedimiento en el enrutador. Usamos manipulación de AST de TypeScript para esto:

procedure/generator.ts
import {
generateFiles,
joinPathFragments,
readProjectConfiguration,
Tree,
} from '@nx/devkit';
import { TrpcProcedureSchema } from './schema';
import { formatFilesInSubtree } from '../../utils/format';
import camelCase from 'lodash.camelcase';
import kebabCase from 'lodash.kebabcase';
import { destructuredImport, replace } from '../../utils/ast';
import { factory, ObjectLiteralExpression } from 'typescript';
export const trpcProcedureGenerator = async (
tree: Tree,
options: TrpcProcedureSchema,
) => {
const projectConfig = readProjectConfiguration(tree, options.project);
const procedureNameCamelCase = camelCase(options.procedure);
const procedureNameKebabCase = kebabCase(options.procedure);
generateFiles(
tree,
joinPathFragments(__dirname, 'files'),
projectConfig.sourceRoot,
{
procedureNameCamelCase,
procedureNameKebabCase,
procedureType: options.type,
},
);
const routerPath = joinPathFragments(projectConfig.sourceRoot, 'router.ts');
destructuredImport(
tree,
routerPath,
[procedureNameCamelCase],
`./procedures/${procedureNameKebabCase}.js`,
);
replace(
tree,
routerPath,
'CallExpression[expression.name="router"] > ObjectLiteralExpression',
(node) =>
factory.createObjectLiteralExpression([
...(node as ObjectLiteralExpression).properties,
factory.createShorthandPropertyAssignment(procedureNameCamelCase),
]),
);
await formatFilesInSubtree(tree);
};
export default trpcProcedureGenerator;

Compilemos el generador para probarlo:

Ventana de terminal
pnpm nx run @aws/nx-plugin:compile

Para probar, vincularemos nuestro plugin local a un proyecto existente.

En otro directorio, crea un workspace:

Terminal window
npx create-nx-workspace@~21.0.3 trpc-generator-test --pm=pnpm --preset=@aws/nx-plugin --ci=skip

Genera una API tRPC:

  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#trpc-api
  5. Complete los parámetros requeridos
    • apiName: test-api
  6. Haga clic en Generate

En tu proyecto, vincula @aws/nx-plugin:

Terminal window
cd path/to/trpc-generator-test
pnpm link path/to/nx-plugin-for-aws/dist/packages/nx-plugin

Prueba el generador:

  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#trpc-api#procedure
  5. Complete los parámetros requeridos
    • Haga clic en Generate

    Si tiene éxito, se habrá generado un nuevo procedimiento y se habrá añadido al enrutador en router.ts.

    Si llegaste hasta aquí y quieres explorar más, aquí algunas sugerencias:

    Modifica el generador para soportar enrutadores anidados:

    • Aceptar notación de puntos para procedure (ej: games.query)
    • Generar nombres basados en la notación inversa (ej: queryGames)
    • Crear/actualizar enrutadores anidados

    Añade validación para prevenir selección de proyectos no tRPC. Revisa el generador api-connection como referencia.

    Escribe pruebas unitarias que:

    1. Creen un workspace vacío con createTreeUsingTsSolutionSetup()
    2. Añadan archivos necesarios (ej: project.json, src/router.ts)
    3. Ejecuten el generador
    4. Verifiquen los cambios en el árbol

    Actualiza las pruebas existentes para incluir este nuevo generador. Actualmente hay una prueba básica que verifica que el build funciona.