Formly Agent Contracts
Contrato Formly
El Contrato Formly convierte la configuración de campos de Angular Formly en JSON estable y versionado que un autor de pruebas E2E o un agente de codificación puede entender sin tener que adivinar cómo está estructurado un formulario.
Dado un FormlyFieldConfig[], el adaptador describe:
los controles, el contenido mostrado, los grupos y las plantillas repetibles del formulario;
la ruta de modelo de cada campo, el tipo Formly, la etiqueta, las restricciones y las opciones;
el comportamiento conocido de visibilidad, obligatoriedad, solo lectura, deshabilitado y opciones dinámicas;
localizadores de prueba exactos o derivados de la aplicación, como
data-testid,data-test-idydata-cy;qué provino directamente de la configuración, qué fue resuelto por una compilación controlada de Formly y qué sigue siendo desconocido; y
diagnósticos estables para comportamientos que no se pueden representar de forma segura.
El resultado es un Contrato de Formulario determinista con validación estricta en tiempo de ejecución, serialización canónica y un hash de contenido. El contrato está pensado para ser una entrada fiable para la planificación de pruebas con Cypress/Playwright y para futuras herramientas de agentes. No es un volcado de los objetos de tiempo de ejecución en vivo de Formly.
Qué existe hoy
Este repositorio proporciona actualmente el esquema v0.3 y dos paquetes del espacio de trabajo:
Paquete | Propósito |
| DTOs del contrato, validación en tiempo de ejecución, JSON canónico y hash de contenido SHA-256 |
| Extracción declarada segura y compilación de escenarios de confianza para Formly 6.1 |
También incluye:
una demo CLI determinista que utiliza un formulario dorado sintético;
una aplicación de prueba Angular renderizada en el navegador con doce fixtures sintéticos de Formly; y
cobertura de compatibilidad para la combinación fijada de Angular
20.3.29y Formly6.1.8.
El analizador y el contrato son el producto actual. Un servidor MCP de producción, la generación automática de Playwright, la observación del navegador y el descubrimiento de código fuente de la aplicación son capas futuras y no se incluyen en este MVP.
Related MCP server: SpecBridge MCP
Úsalo en tu propio código Angular/Formly
El paquete se ejecuta como herramienta de compilación/prueba junto a tu aplicación Angular. No es necesario añadirlo al bundle del navegador de la aplicación. Un flujo de adopción típico es:
application-owned Formly factories
|
generation script or CI job
|
versioned contract JSON
|
Playwright / Cypress / agent tooling1. Añade los paquetes
Los paquetes aún no están publicados en npm. Hasta el primer lanzamiento, clona este repositorio junto a la aplicación consumidora y compila los dos paquetes:
git clone https://github.com/dills122/formly-contract.git
cd formly-contract
pnpm install --frozen-lockfile
pnpm --filter @formly-contract/contract-schema build
pnpm --filter @formly-contract/formly-adapter buildLuego enlázalos desde el package.json de la aplicación consumidora (ajusta la
ruta relativa para tu checkout):
{
"devDependencies": {
"@formly-contract/contract-schema": "link:../formly-contract/packages/contract-schema",
"@formly-contract/formly-adapter": "link:../formly-contract/packages/formly-adapter"
}
}Ejecuta pnpm install en la aplicación consumidora. La aplicación ya debe
proporcionar dependencias de pares compatibles de Angular y Formly; la combinación
actualmente probada es Angular 20.3.29 con Formly 6.1.8. Una vez que los paquetes
estén publicados, las dependencias normales versionadas pnpm add --save-dev reemplazarán
estos enlaces locales.
2. Selecciona los formularios a exponer
El descubrimiento de código fuente de la aplicación no es automático a propósito. Crea un registro pequeño propiedad de la aplicación que importe solo las fábricas de formularios que quieras que el generador de contratos inspeccione:
// tools/contract-forms.ts
import type { FormlyFieldConfig } from '@ngx-formly/core';
import { createClaimFields } from '../src/app/claims/claim.fields';
import { createCustomerFields } from '../src/app/customers/customer.fields';
export interface ContractFormTarget {
id: string;
createFields: () => FormlyFieldConfig[];
}
export const contractForms: ContractFormTarget[] = [
{ id: 'claims.create', createFields: () => createClaimFields() },
{ id: 'customers.edit', createFields: () => createCustomerFields() },
];Cada fábrica debe devolver un árbol de campos nuevo. Si una fábrica necesita entradas de la aplicación, envuélvela en un cierre con valores sintéticos que sean seguros de usar en el desarrollo local y en CI.
3. Genera los artefactos del contrato
Añade un script en tiempo de compilación en el repositorio de la aplicación:
// tools/generate-form-contracts.ts
import { mkdir, writeFile } from 'node:fs/promises';
import { resolve } from 'node:path';
import { canonicalStringify } from '@formly-contract/contract-schema';
import { extractFormContract } from '@formly-contract/formly-adapter';
import { contractForms } from './contract-forms';
const outputDirectory = resolve('artifacts/form-contracts');
await mkdir(outputDirectory, { recursive: true });
for (const target of contractForms) {
const { contract, diagnostics } = extractFormContract({
formId: target.id,
fields: target.createFields(),
});
await writeFile(
resolve(outputDirectory, `${target.id}.json`),
`${canonicalStringify(contract)}\n`,
);
console.log(
`${target.id}: ${contract.nodes.length} root nodes, ${diagnostics.length} diagnostics`,
);
}Ejecuta este archivo con el ejecutor de TypeScript que ya usa el repositorio consumidor, o compílalo como parte de un proyecto de herramientas dirigido a Node. El JSON resultante se puede confirmar para revisión, subir como artefacto de CI o leer por herramientas posteriores de autoría de pruebas. Debido a que es canónico y tiene hash de contenido, un cambio inesperado en el contrato de formulario es visible en el control de código fuente o en CI.
Esta ruta declarada es el mejor punto de partida. Captura la estructura estática y registra los callbacks de expresiones como metadatos dinámicos sin ejecutar código arbitrario de la aplicación.
4. Usa un contrato en Playwright
Valida el JSON almacenado antes de confiar en él, encuentra el nodo semántico que necesitas y
usa uno de sus candidatos de localizador exactos. Para un localizador estándar data-testid:
import { readFile } from 'node:fs/promises';
import {
parseFormContract,
type ContractNode,
type ModelPathSegment,
} from '@formly-contract/contract-schema';
function findNodeByPath(
nodes: readonly ContractNode[],
modelPath: readonly ModelPathSegment[],
): ContractNode | undefined {
for (const node of nodes) {
if (
node.modelPath.length === modelPath.length &&
node.modelPath.every((segment, index) => segment === modelPath[index])
) {
return node;
}
const nested = findNodeByPath(
node.arrayTemplate
? [...node.children, node.arrayTemplate]
: node.children,
modelPath,
);
if (nested) return nested;
}
}
const contract = parseFormContract(
JSON.parse(
await readFile('artifacts/form-contracts/claims.create.json', 'utf8'),
),
);
const claimantName = findNodeByPath(contract.nodes, ['claimant', 'name']);
const testId = claimantName?.locators.find(
(locator) =>
locator.strategy === 'testId' && locator.attribute === 'data-testid',
);
if (!claimantName || !testId) {
throw new Error('claimant.name has no exact data-testid locator');
}
await page.getByTestId(testId.value).fill('Ada Lovelace');Los consumidores reales normalmente pondrán la búsqueda recursiva de nodos y la selección de localizadores en
un helper compartido de Playwright o Cypress. Los controles compuestos pueden exponer varios
objetivos de localizador, por lo que los helpers deben seleccionar por target en lugar de asumir que un
nodo de Formly siempre se asigna a un elemento del DOM. Los arrays de localizadores vacíos y los diagnósticos
deben tratarse como evidencia faltante, no reemplazarse con selectores inventados.
5. Resuelve el comportamiento dinámico cuando sea necesario
Si las expresiones determinan la visibilidad, el estado obligatorio/solo lectura o las listas
de opciones, añade escenarios sintéticos y llama a compileFormContractScenario. Ejecuta esa API en
un entorno de compilación/prueba Angular de confianza configurado con los módulos
reales de Formly de la aplicación y los tipos personalizados. Genera un artefacto por escenario
significativo, usando solo datos sintéticos de modelo y estado de formulario.
El harness de compatibilidad sintético
muestra la configuración completa de Angular TestBed para obtener un
FormlyFormBuilder. El ejemplo detallado de la API a continuación muestra la llamada al escenario.
Por qué es útil
Los formularios grandes de Formly a menudo se ensamblan a partir de grupos anidados, fragmentos compartidos, tipos de campo personalizados, expresiones, opciones dinámicas y convenciones de la aplicación. Leer ese código fuente repetidamente es lento, y adivinar a partir de una página renderizada lleva a pruebas frágiles.
Este proyecto crea un límite pequeño y explícito:
Formly fields + synthetic scenario
|
safe contract projection
|
deterministic versioned JSON
|
E2E planning / agent inspectionLos consumidores pueden inspeccionar un contrato para responder preguntas como:
¿Qué controles existen y en qué orden?
¿Qué valor de modelo edita cada control?
¿Qué valores y límites de validación se conocen?
¿Una lista de opciones está vacía, es estática, dinámica o asíncrona?
¿Qué campos pueden estar ocultos, ser obligatorios, de solo lectura o estar deshabilitados?
¿Qué candidatos de localizador
data-*, role, etiqueta, placeholder o ID de DOM están disponibles?¿Qué hechos son exactos, derivados, resueltos para un escenario o aún desconocidos?
Prueba este repositorio
Requisitos previos:
Node.js
22.22.1pnpm
10.23.0
pnpm install --frozen-lockfile
pnpm demopnpm demo compila la parte de paquetes e imprime un contrato JSON canónico.
Ejecuta la compuerta completa del repositorio con:
pnpm checkEse comando ejecuta lint, todas las pruebas, las compilaciones de producción de paquetes y Angular, la prueba de humo de la demo y las comprobaciones de documentación.
Extrae la estructura de formulario declarada
Usa extractFormContract cuando tengas configuración de Formly y quieras inspeccionarla
sin ejecutar callbacks:
import { extractFormContract } from '@formly-contract/formly-adapter';
import type { FormlyFieldConfig } from '@ngx-formly/core';
const fields: FormlyFieldConfig[] = [
{
key: 'profile.name',
type: 'input',
props: {
label: 'Name',
required: true,
attributes: { 'data-testid': 'profile-name' },
},
},
];
const { contract, diagnostics } = extractFormContract({
formId: 'example.profile',
fields,
});Esta ruta es pura y no muta. No llama a funciones de expresión,
no se suscribe a Observables, no ejecuta validadores ni renderiza componentes de Angular.
Los callbacks reconocidos se convierten en metadatos de reglas dinámicas; el comportamiento no compatible se convierte en
un diagnóstico explícito. El nodo devuelto tiene el ID estable
example.profile::path:s_profile.s_name, la ruta de modelo ['profile', 'name'], su
restricción de obligatoriedad y un localizador exacto data-testid.
Resuelve un escenario sintético
Usa compileFormContractScenario cuando los atributos obligatorio, solo lectura, deshabilitado,
oculto, opciones o localizadores dependan de callbacks de expresiones de Formly:
import { inject } from '@angular/core';
import { FormlyFormBuilder } from '@ngx-formly/core';
import { compileFormContractScenario } from '@formly-contract/formly-adapter';
const builder = inject(FormlyFormBuilder);
const { contract, diagnostics } = compileFormContractScenario({
formId: 'example.profile',
builder,
createFields: () => createProfileFields(),
model: { contactMethod: 'email' },
formState: { readonly: false },
});Esta es una API de compilación/CI de confianza. Usa el
FormlyFormBuilder configurado de la aplicación, por lo que los callbacks de la aplicación y de Formly
pueden ejecutarse. El modelo y el estado del formulario deben ser clonables por clonación estructurada; ambos se clonan antes de que
se ejecute la fábrica de campos o el builder.
El árbol de campos compilado sigue pasando por la misma lista blanca que la extracción
declarada. Por ejemplo, las opciones dinámicas se reducen a registros públicos
label/value/disabled en lugar de copiar propiedades arbitrarias de
objetos de la aplicación.
No expongas este compilador directamente desde un MCP u otro manejador de solicitudes no confiable. Las capas de consulta deben leer artefactos de contrato generados previamente.
Localizadores de prueba
Cada nodo tiene un array ordenado locators. El adaptador lee automáticamente
estos atributos comunes de props.attributes:
data-testiddata-test-iddata-testdata-cydata-pw
También puede conservar candidatos explícitos de role, nombre accesible, placeholder e ID de campo de Formly. Un array vacío significa que no se encontró ningún localizador fiable; el adaptador nunca inventa CSS o XPath.
Las aplicaciones con su propia convención de nombres pueden establecer testIdAttributes y
proporcionar un callback determinista deriveLocators. El callback recibe solo
datos de identidad congelados, no el campo Formly en vivo. Puede devolver varios
objetivos nombrados para un widget compuesto como un rango de fechas; su salida se marca
confidence: "derived". Consulta la
especificación de localizadores v0.3 para ver el contrato
completo y un ejemplo.
Modelo de evidencia
El contrato mantiene tres niveles de evidencia separados:
Evidencia | Significado | ¿Disponible ahora? |
| Leído de forma segura de la configuración de Formly proporcionada | Sí |
| Leído de una compilación controlada de Formly para un escenario sintético | Sí |
| Visto en un DOM de navegador renderizado real | Listo para el esquema; capa de captura no implementada |
Un localizador resuelto no se presenta silenciosamente como observado en el navegador. Del mismo modo, el comportamiento opaco o asíncrono se informa en lugar de adivinarse.
Información de contrato compatible
El esquema v0.3 puede representar:
controles ordenados, grupos, nodos solo de visualización y plantillas de arrays;
IDs de nodo semánticos estables y rutas de modelo acumulativas;
tipos de control de Formly y semánticos comunes;
etiquetas, descripciones, placeholders, valores predeterminados seguros para JSON y wrappers;
restricciones de obligatoriedad, min/max, longitud, patrón de cadena y nombradas;
opciones públicas estáticas y resueltas más metadatos de fuentes de opciones dinámicas/asíncronas;
condiciones de cadena/booleano y metadatos de reglas dinámicas de callback/async;
estado resuelto de oculto, solo lectura y deshabilitado;
candidatos de localizador exactos y derivados, incluidos múltiples objetivos nombrados; y
diagnósticos deterministas, JSON canónico y hash de contenido.
Limitaciones intencionales
Los formularios deben proporcionarse explícitamente; el adaptador no descubre exports arbitrarios de TypeScript ni rutas de la aplicación.
La extracción declarada nunca evalúa funciones ni código fuente de funciones.
El compilador de escenarios realiza la compilación inicial controlada de Formly pero no espera opciones remotas ni comportamiento del navegador impulsado por el ciclo de vida.
Los patrones
RegExpde Formly se diagnostican; v0.3 representa solo patrones de cadena.Las acciones de widgets personalizados y los códecs de valor aún no están modelados.
El proyecto actualmente no genera ni ejecuta pruebas de Cypress/Playwright.
No se incluye un servidor MCP de producción ni una capa de observación del navegador.
La compatibilidad está probada para Angular
20.3.29con Formly6.1.8, no para cada combinación de Angular/Formly.La publicación en npm y la automatización de lanzamientos aún no están incluidas.
Aplicación de prueba sintética
La aplicación de prueba Angular contiene doce formularios inventados que cubren campos nativos y personalizados, wrappers, validadores, extensiones, presets, expresiones, validación, repetidores, comportamiento opaco y alias heredados de Formly v6.
pnpm app:serveAbre http://127.0.0.1:4200/ y elige un fixture del catálogo.
Los formularios y datos del lugar de trabajo deben permanecer en un repositorio de trabajo privado. Un
módulo de fixtures privado puede implementar TestFormDefinition y registrar un grupo a través
de TEST_FORM_GROUPS sin copiar etiquetas, identificadores, opciones o
reglas del lugar de trabajo en este proyecto público.
Estructura del repositorio
packages/
contract-schema/ Versioned DTOs, validation, canonical JSON, and hashing
formly-adapter/ Declared extraction and trusted Formly scenario builds
fixtures/
synthetic-form/ Public golden form and real-builder compatibility fixture
apps/
demo-cli/ Prints the deterministic golden contract
formly-test-app/ Browser-rendered Angular/Formly fixture catalog
docs/ Specifications, ADRs, delivery plans, and evidenceHoja de ruta
La ruta de entrega prevista es:
Form Contract packages (current)
|
read-only MCP queries
|
typed E2E intent
|
deterministic Playwright/Cypress drivers
|
browser observation and parity checksLas capas futuras deben consumir contratos inmutables. No deben mover la ejecución de Angular, la evaluación arbitraria de callbacks ni la invención de selectores a solicitudes rutinarias de agentes.
Documentación
Contribuciones y seguridad
Las contribuciones son bienvenidas. Lee CONTRIBUTING.md y el Código de conducta antes de participar. Informa de problemas de seguridad mediante el proceso privado descrito en SECURITY.md.
Este proyecto está disponible bajo la Licencia MIT.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Live React design-system APIs, patterns, and code validation so AI agents build real UI, not slop.
Machine-native capabilities with explicit contracts and machine-readable commerce.
Define, ship & query your analytics tracking from one source of truth, trusted by humans and agents.
API governance for AI agents. Detects breaking changes, scores blast radius, blocks unsafe calls.
Related MCP Servers
- AlicenseBqualityDmaintenanceExposes TypeScript Language Server Protocol functionality to AI agents, enabling them to query types at specific positions, find definitions and references, get diagnostics, run type tests, and type-check inline code just like in an IDE.91463MIT
- FlicenseAqualityDmaintenanceA clone-and-own MCP server that exposes OpenAPI/Huma contract intelligence to AI agents by turning API specifications into deterministic endpoint metadata, schemas, validation facts, and TypeScript declarations.6
- FlicenseAqualityDmaintenanceEnables AI agents to query component governance rules, validate component props, and generate development prompts for questionnaire editors.4
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to browse, read, compare, and validate OpenAPI contracts for providers and consumers.1MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/dills122/formly-contract'
If you have feedback or need assistance with the MCP directory API, please join our Discord server