Generación de tipos
Cada schematic mantiene un tipo Input en schema.generated.ts, derivado de su
schema.json. pbuilder-codegen — un binario incluido en @pbuilder/sdk — escribe ese
archivo. Cuando cambias schemas en varias colecciones, una sola ejecución los regenera a
todos a partir de lo que registra project-builder.json; no hay una segunda lista de
directorios que mantener sincronizada.
pbuilder-codegen es un script de Node.js, así que sirve cualquier ejecutor de paquetes:
npx, pnpm exec, yarn o bunx. Los ejemplos usan bunx, como el resto de esta
documentación.
Elige un modo
Sección titulada «Elige un modo»| Quieres regenerar… | Ejecuta | Qué selecciona |
|---|---|---|
| Todos los schematics registrados del proyecto en el que estás | bunx pbuilder-codegen |
El project-builder.json más cercano, subiendo desde el directorio actual |
| Todos los schematics registrados de un proyecto concreto | bunx pbuilder-codegen --project <directory> |
Exactamente el project-builder.json de ese directorio, desde cualquier directorio de trabajo — sin búsqueda hacia arriba |
| Un solo schematic | bunx pbuilder-codegen <schematic-directory> |
Solo ese directorio |
Usa los modos de proyecto después de editar varios schemas, en CI o como tu script
generate:types. Usa el modo de un directorio mientras iteras sobre un schematic — es lo
que enseña Tu primer schematic, y lo que
builder new schematic ejecuta por ti automáticamente.
Los modos de proyecto procesan todas las colecciones, no solo default.
Ejemplo completo: dos colecciones
Sección titulada «Ejemplo completo: dos colecciones»Un workspace registra un schematic por directorio y una segunda colección mediante un manifiesto cuya factory es un módulo compilado:
workspace/├── package.json├── project-builder.json└── schematics/ ├── collection.json ├── hello/ │ ├── factory.ts │ └── schema.json └── dist/ ├── widget.js └── schema.json{ "collections": { "local": { "hello": { "path": "./schematics/hello" } }, "shared": { "path": "./schematics/collection.json" } }}{ "schematics": { "widget": { "factory": "./dist/widget.js#createWidget" } }}{ "properties": { "name": { "type": "string", "label": "Service name", "required": true } }}{ "properties": { "label": { "type": "string", "label": "Widget label", "required": true } }}-
Ejecuta el codegen desde cualquier lugar dentro del workspace — aquí, desde la carpeta de un schematic:
Terminal window cd schematics/hellobunx pbuilder-codegenpbuilder-codegen: generated 2, failed 0, duplicates 0El código de salida es
0. -
Revisa las salidas. Cada schema recibe un
schema.generated.tsa su lado — para la entrada del manifiesto, junto aldist/widget.jscompilado que nombra el puntero:schematics/├── dist/│ ├── schema.generated.ts ← new│ ├── schema.json│ └── widget.js└── hello/├── factory.ts├── schema.generated.ts ← new└── schema.jsonschematics/dist/schema.generated.ts // AUTO-GENERATED by pbuilder-codegen — do not edit. Regenerate: pbuilder-codegen <package-dir>// @schema-digest sha256:…export type Input = {/** Widget label */label: string;}; -
O apunta al proyecto desde fuera, por ejemplo desde la raíz de un monorepo o un script de CI:
Terminal window bunx pbuilder-codegen --project ./workspaceEl resultado es el mismo.
Qué proyecto se selecciona
Sección titulada «Qué proyecto se selecciona»- Sin argumentos, la búsqueda sube desde el directorio actual, y el primer
project-builder.jsonencontrado es el que manda. Si ese archivo está mal formado, no se puede leer, es un directorio o es un enlace roto, la ejecución falla — nunca recurre a un archivo válido más arriba. - Con
--project <directory>, se usa exactamente ese directorio. Pasa un directorio, no la ruta al archivo de configuración. - Una configuración ausente o mal formada falla antes de generar nada. Una configuración sin
collections, o concollectionsvacío, termina con éxito sin trabajo. - El directorio del proyecto seleccionado es el límite de escritura. Si
project-builder.jsones un enlace simbólico, el directorio de su destino no obtiene permiso de escritura.
Dónde está instalado el SDK no influye en la selección: el directorio de trabajo y
--project deciden qué proyecto se ejecuta.
Qué se genera
Sección titulada «Qué se genera»Dos formas de registro tienen archivos que generar:
| Registro | Ejemplo | Reglas |
|---|---|---|
| Directorio del schematic | "hello": { "path": "./schematics/hello" } |
El directorio debe contener exactamente un factory.ts o factory.js regular — ninguno o ambos es un error. El schema es el schema.json de ese directorio. |
| Manifiesto de colección | "shared": { "path": "./schematics/collection.json" } |
Cada puntero de factory necesita un export explícito: module#export, dividido en el último #, con un módulo no vacío y un export con forma de identificador (default es válido). La ruta del módulo es relativa al manifiesto y debe ser un archivo real. El schema es el schema.json junto a ese módulo. |
Ambos valores de path se resuelven contra el directorio del proyecto seleccionado; se
aceptan rutas absolutas siempre que el resultado quede dentro del proyecto. Las factories
nunca se importan ni se ejecutan — el codegen solo lee archivos. Se aceptan archivos JSON con
una marca de orden de bytes (BOM) inicial.
No soportado:
- Registros inline — schematics embebidos en
project-builder.json, como los que creabuilder new schematic --inline— no tienen archivo que escribir. Cada uno cuenta como un fallo. Un nombre registrado a la vez inline y como directorio también falla. - Búsqueda de paquetes, inferencia de extensiones, herencia, rutas codificadas como URL y schematics que están en disco pero no registrados. El codegen no recorre carpetas.
Lee el resultado
Sección titulada «Lee el resultado»Toda ejecución de proyecto termina con una línea de resumen en stdout:
pbuilder-codegen: generated G, failed F, duplicates DLas advertencias sobre entradas individuales van a stderr. El código de salida es 1 si
alguna entrada falló, y 0 en caso contrario — incluida una ejecución sin trabajo.
Una ejecución continúa después de que falla una entrada. En este ejemplo, drafts/broken
tiene una propiedad sin label, y legacy/broken-copy vuelve a registrar el mismo
directorio:
{ "collections": { "local": { "hello": { "path": "./schematics/hello" } }, "drafts": { "broken": { "path": "./schematics/broken" } }, "legacy": { "broken-copy": { "path": "./schematics/broken" } } }}$ bunx pbuilder-codegenpbuilder-codegen: "drafts/broken" ("<workspace>/schematics/broken"): "pbuilder-codegen: <workspace>/schematics/broken/schema.json: property \"title\" is missing a label"pbuilder-codegen: generated 1, failed 1, duplicates 1$ echo $?1Cómo se cuentan las entradas:
- Duplicados — los registros que resuelven a un destino ya intentado en esta ejecución
cuentan una vez en
duplicates, aunque el primer intento haya fallado; no suman otro fallo. Los alias mediante enlaces simbólicos de directorio se reconocen como el mismo destino. Los archivos distintos unidos por hard links, no. - Fallos — cada registro que no se puede resolver, es inválido o es rechazado cuenta por separado.
- No es una transacción — los archivos generados con éxito quedan escritos aunque otra
entrada falle. Una entrada que no pasa la validación conserva su
schema.generated.tsanterior.
Corrige el schema o el registro reportado y vuelve a ejecutar. Nunca edites
schema.generated.ts a mano.
Deja que el código de salida haga fallar el job. Que los archivos estén en disco no prueba que toda la ejecución haya tenido éxito:
bunx pbuilder-codegenSi encadenas la salida con un pipe, conserva el código de salida — por ejemplo con
set -o pipefail en Bash. Para detectar además schemas cambiados sin regenerar, busca
diferencias después:
bunx pbuilder-codegengit diff --exit-code -- '*schema.generated.ts'Cuando el SDK viene de sdk.root
Sección titulada «Cuando el SDK viene de sdk.root»Con sdk.root, node_modules/@pbuilder/sdk es un enlace que creó la CLI, no un paquete que instaló tu gestor de paquetes — así que no hay shim node_modules/.bin/pbuilder-codegen. Los ejecutores de paquetes fallan entonces de una de estas formas:
bunx pbuilder-codegenynpx pbuilder-codegenreportan que falta el binario, aunque el SDK está presente ybuilder executefunciona.- Si además hay un SDK instalado globalmente,
npxpuede ejecutar esa copia global sin avisarte — posiblemente una versión distinta de la que indicasdk.root. - Las versiones recientes de pnpm ejecutan una instalación antes de
pnpm exec. Eso hace que el comando funcione, pero escribe unpnpm-lock.yamly un shim en tu proyecto — justo el tipo de cambio quesdk.rootexiste para evitar.
El script generate:types que agrega builder init llama a pbuilder-codegen por nombre, así que también se ve afectado.
Ejecuta el script directamente con Node. Acepta las mismas formas — sin argumento, --project <directory> o un directorio de schematic:
node node_modules/@pbuilder/sdk/dist/bin/pbuilder-codegen.jsnode node_modules/@pbuilder/sdk/dist/bin/pbuilder-codegen.js schematics/helloEl enlace existe una vez que corrió un builder execute con commit. Antes de eso, usa la raíz configurada: node <sdk.root>/dist/bin/pbuilder-codegen.js.
Lo mismo aplica cuando el enlace se creó con --sdk-root o BUILDER_SDK_ROOT en lugar de sdk.root. Antes de que exista el enlace, ejecuta el script desde ese valor: node $BUILDER_SDK_ROOT/dist/bin/pbuilder-codegen.js.
builder new schematic no necesita nada de esto con sdk.root: resuelve la raíz configurada por su cuenta y regenera los tipos del nuevo schematic. No lee BUILDER_SDK_ROOT: cuando la variable es tu única fuente de SDK, advierte que no encontró @pbuilder/sdk y omite schema.generated.ts — ejecuta el script como se indica arriba.
Archivos de salida y límites de escritura
Sección titulada «Archivos de salida y límites de escritura»El codegen solo escribe donde la ejecución tiene permitido hacerlo:
| Modo | Límite de escritura |
|---|---|
Proyecto (pbuilder-codegen, --project) |
El directorio del proyecto seleccionado |
Un directorio (pbuilder-codegen <dir>) |
El ancestro más cercano del directorio de trabajo que tenga un package.json, o el propio directorio de trabajo si no hay ninguno |
Tanto el directorio del schematic como el archivo de salida — una vez resueltos los enlaces
simbólicos — deben quedar dentro de ese límite. Un destino fuera de él no se escribe: en una
ejecución de proyecto se reporta como refusing to write outside the selected project root y
cuenta como fallo. Corrige el registro o ejecuta el codegen desde el proyecto al que pertenece
el schematic.
Salidas que son enlaces simbólicos
Sección titulada «Salidas que son enlaces simbólicos»En Linux y macOS, schema.generated.ts debe no existir o ser un archivo regular. Una salida
que es un enlace simbólico se rechaza — aunque su destino esté dentro del proyecto — y lo
mismo ocurre con cualquier otra entrada no regular:
$ bunx pbuilder-codegen schematics/hellopbuilder-codegen: schematics/hello/schema.generated.ts: refusing symbolic-link outputEn una ejecución de proyecto, la misma entrada reporta
cannot write a regular, non-symbolic-link output. builder new schematic lo muestra como
new_codegen_failed. Reinstalar el SDK no ayuda — la causa es la disposición de los archivos.
Para migrar:
-
Confirma que la entrada es un enlace y anota a dónde apunta:
Terminal window ls -l schematics/hello/schema.generated.ts -
Elimina solo el enlace. No toques su destino:
Terminal window rm schematics/hello/schema.generated.ts -
Regenera un archivo normal en su lugar:
Terminal window bunx pbuilder-codegen schematics/hello
Los enlaces de directorio son distintos: un directorio de schematic al que se llega mediante un enlace simbólico sigue funcionando, siempre que el directorio resuelto y su salida queden dentro del límite de escritura. Crear una salida que falta y reemplazar una regular existente — incluso con contenido más corto — funciona como siempre.
Las comprobaciones de salidas que son enlaces simbólicos o entradas no regulares aplican en Linux y macOS. Las demás plataformas mantienen el escritor habitual y la comprobación del límite de escritura; Windows nativo no está verificado. Estas comprobaciones no son un sandbox del sistema de archivos y no protegen contra directorios padre reemplazados mientras la ejecución está en curso.
Relacionado
Sección titulada «Relacionado»- Tu primer schematic — el flujo de un schematic de principio a fin.
builder new schematic— crea un schematic y ejecuta el codegen para él.builder init— el scriptgenerate:typesque agrega, que ejecuta el codegen una vez por cadaschema.jsonque encuentra bajoschematics/.