Formly Agent Contracts
Formly Contract
Formly Contract verwandelt Angular-Formly-Feldkonfigurationen in stabiles, versioniertes JSON, das ein E2E-Testautor oder Coding-Agent verstehen kann, ohne raten zu müssen, wie ein Formular aufgebaut ist.
Gegeben eine FormlyFieldConfig[], beschreibt der Adapter:
die Steuerelemente, Anzeigeinhalte, Gruppen und wiederholbaren Vorlagen im Formular;
den Modellpfad jedes Felds, den Formly-Typ, das Label, Einschränkungen und Auswahlmöglichkeiten;
bekanntes Sichtbarkeits-, Pflicht-, Readonly-, Deaktiviert- und dynamisches Optionsverhalten;
exakte oder aus der Anwendung abgeleitete Test-Locators wie
data-testid,data-test-idunddata-cy;was direkt aus der Konfiguration stammt, was durch einen kontrollierten Formly-Build aufgelöst wurde und was unbekannt bleibt; und
stabile Diagnosen für Verhalten, das nicht sicher dargestellt werden kann.
Das Ergebnis ist ein deterministischer Form Contract mit strenger Laufzeitvalidierung, kanonischer Serialisierung und einem Inhalts-Hash. Der Vertrag ist als zuverlässige Eingabe für Cypress/Playwright-Testplanung und zukünftige Agent-Tools gedacht. Er ist kein Dump der Live-Laufzeitobjekte von Formly.
Was heute existiert
Dieses Repository bietet derzeit Schema v0.3 und zwei Workspace-Pakete:
Paket | Zweck |
| Vertrags-DTOs, Laufzeitvalidierung, kanonisches JSON und SHA-256-Inhalts-Hashing |
| Sichere deklarierte Extraktion und vertrauenswürdige Szenariokompilierung für Formly 6.1 |
Es enthält außerdem:
eine deterministische CLI-Demo mit einem synthetischen Golden-Formular;
eine im Browser gerenderte Angular-Testanwendung mit zwölf synthetischen Formly-Fixtures; und
Kompatibilitätsabdeckung für die festgelegte Kombination aus Angular
20.3.29und Formly6.1.8.
Der Parser und der Vertrag sind das aktuelle Produkt. Ein Produktions-MCP-Server, automatische Playwright-Generierung, Browser-Beobachtung und Anwendungsquellcode-Erkennung sind zukünftige Schichten und werden von diesem MVP nicht mitgeliefert.
Related MCP server: SpecBridge MCP
Verwenden Sie es in Ihrer eigenen Angular/Formly-Codebasis
Das Paket läuft als Build-/Test-Werkzeug neben Ihrer Angular-Anwendung. Es muss nicht zum Browser-Bundle der Anwendung hinzugefügt werden. Ein typischer Einführungsablauf ist:
application-owned Formly factories
|
generation script or CI job
|
versioned contract JSON
|
Playwright / Cypress / agent tooling1. Pakete hinzufügen
Die Pakete sind noch nicht auf npm veröffentlicht. Bis zur ersten Veröffentlichung klonen Sie dieses Repository neben die verbrauchende Anwendung und bauen Sie die beiden Pakete:
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 buildVerknüpfen Sie sie dann aus der package.json der verbrauchenden Anwendung (passen Sie
den relativen Pfad für Ihren Checkout an):
{
"devDependencies": {
"@formly-contract/contract-schema": "link:../formly-contract/packages/contract-schema",
"@formly-contract/formly-adapter": "link:../formly-contract/packages/formly-adapter"
}
}Führen Sie pnpm install in der verbrauchenden Anwendung aus. Die Anwendung muss bereits
kompatible Angular- und Formly-Peer-Abhängigkeiten bereitstellen; die derzeit getestete
Kombination ist Angular 20.3.29 mit Formly 6.1.8. Sobald die Pakete veröffentlicht
sind, ersetzen normale versionierte pnpm add --save-dev-Abhängigkeiten diese lokalen Links.
2. Formulare auswählen, die offengelegt werden sollen
Die Erkennung von Anwendungsquellcode ist bewusst nicht automatisch. Erstellen Sie ein kleines, anwendungseigenes Register, das nur die Formularfabriken importiert, die der Vertragsgenerator untersuchen soll:
// 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() },
];Jede Fabrik sollte einen frischen Feldbaum zurückgeben. Wenn eine Fabrik Anwendungseingaben benötigt, umschließen Sie sie mit einer Closure mit synthetischen Werten, die für die lokale Entwicklung und CI sicher sind.
3. Vertragsartefakte generieren
Fügen Sie ein Build-Zeitskript im Anwendungsrepository hinzu:
// 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`,
);
}Führen Sie diese Datei mit dem TypeScript-Runner aus, der bereits vom verbrauchenden Repository verwendet wird, oder kompilieren Sie sie als Teil eines Node-zielenden Tooling-Projekts. Das resultierende JSON kann für die Überprüfung committet, als CI-Artefakt hochgeladen oder von nachgelagerten Testautoren-Tools gelesen werden. Da es kanonisch und inhaltsgehasht ist, ist eine unerwartete Änderung des Formularvertrags in der Quellcodeverwaltung oder CI sichtbar.
Dieser deklarierte Pfad ist der beste Ausgangspunkt. Er erfasst die statische Struktur und zeichnet Ausdrucks-Callbacks als dynamische Metadaten auf, ohne beliebigen Anwendungscode auszuführen.
4. Einen Vertrag in Playwright verwenden
Validieren Sie gespeichertes JSON, bevor Sie ihm vertrauen, finden Sie den semantischen
Knoten, den Sie benötigen, und verwenden Sie einen seiner exakten Locator-Kandidaten. Für
einen Standard-data-testid-Locator:
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');Echte Verbraucher werden normalerweise rekursive Knotensuche und Locator-Auswahl in einen
gemeinsamen Playwright- oder Cypress-Helfer legen. Zusammengesetzte Steuerelemente können
mehrere Locator-Ziele offenlegen, daher sollten Helfer nach target auswählen, anstatt
anzunehmen, dass ein Formly-Knoten immer auf ein DOM-Element abgebildet wird. Leere
Locator-Arrays und Diagnosen müssen als fehlende Beweise behandelt werden, nicht durch
erfundene Selektoren ersetzt werden.
5. Dynamisches Verhalten bei Bedarf auflösen
Wenn Ausdrücke Sichtbarkeit, Pflicht-/Readonly-Zustand oder Optionslisten bestimmen,
fügen Sie synthetische Szenarien hinzu und rufen Sie compileFormContractScenario auf.
Führen Sie diese API in einer vertrauenswürdigen Angular-Test-/Build-Umgebung aus, die mit
den echten Formly-Modulen und benutzerdefinierten Typen der Anwendung konfiguriert ist.
Generieren Sie ein Artefakt pro aussagekräftigem Szenario, wobei Sie nur synthetische
Modell- und Formularzustandsdaten verwenden.
Der synthetische Kompatibilitäts-Harness
zeigt das vollständige Angular-TestBed-Setup zum Erhalten eines
FormlyFormBuilder. Das detaillierte API-Beispiel unten zeigt den Szenarioaufruf.
Warum das nützlich ist
Große Formly-Formulare werden oft aus verschachtelten Gruppen, gemeinsamen Fragmenten, benutzerdefinierten Feldtypen, Ausdrücken, dynamischen Auswahlmöglichkeiten und Anwendungskonventionen zusammengesetzt. Das wiederholte Lesen dieser Quelle ist langsam, und das Raten von einer gerenderten Seite führt zu fragilen Tests.
Dieses Projekt schafft eine kleine, explizite Grenze:
Formly fields + synthetic scenario
|
safe contract projection
|
deterministic versioned JSON
|
E2E planning / agent inspectionVerbraucher können einen Vertrag einsehen, um Fragen zu beantworten wie:
Welche Steuerelemente existieren und in welcher Reihenfolge?
Welchen Modellwert bearbeitet jedes Steuerelement?
Welche Werte und Validierungsgrenzen sind bekannt?
Ist eine Auswahlliste leer, statisch, dynamisch oder asynchron?
Welche Felder können versteckt, pflicht, readonly oder deaktiviert sein?
Welche
data-*, Rolle, Label, Platzhalter- oder DOM-ID-Locator-Kandidaten sind verfügbar?Welche Fakten sind exakt, abgeleitet, für ein Szenario aufgelöst oder noch unbekannt?
Dieses Repository ausprobieren
Voraussetzungen:
Node.js
22.22.1pnpm
10.23.0
pnpm install --frozen-lockfile
pnpm demopnpm demo baut den Paketausschnitt und gibt einen kanonischen JSON-Vertrag aus.
Führen Sie das vollständige Repository-Gate aus mit:
pnpm checkDieser Befehl führt Lint, alle Tests, Paket- und Angular-Produktionsbuilds, den Demo-Smoke-Test und Dokumentationsprüfungen aus.
Deklarierte Formularstruktur extrahieren
Verwenden Sie extractFormContract, wenn Sie Formly-Konfiguration haben und sie
untersuchen möchten, ohne Callbacks auszuführen:
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,
});Dieser Pfad ist rein und nicht mutierend. Er ruft keine Ausdrucksfunktionen auf,
abonniert keine Observables, führt keine Validatoren aus und rendert keine Angular-Komponenten.
Erkannte Callbacks werden zu Metadaten für dynamische Regeln; nicht unterstütztes Verhalten
wird zu einer expliziten Diagnose. Der zurückgegebene Knoten hat die stabile ID
example.profile::path:s_profile.s_name, den Modellpfad ['profile', 'name'], seine
Pflichteinschränkung und einen exakten data-testid-Locator.
Ein synthetisches Szenario auflösen
Verwenden Sie compileFormContractScenario, wenn Pflicht-, Readonly-, Deaktiviert-,
Versteckt-, Options- oder Locator-Attribute von Formly-Ausdrucks-Callbacks abhängen:
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 },
});Dies ist eine vertrauenswürdige Build-/CI-API. Sie verwendet den konfigurierten
FormlyFormBuilder der Anwendung, sodass Anwendungs- und Formly-Callbacks ausgeführt
werden können. Das Modell und der Formularzustand müssen strukturklonbar sein; beide
werden geklont, bevor die Feld-Fabrik oder der Builder läuft.
Der gebaute Feldbaum durchläuft weiterhin dieselbe Whitelist wie die deklarierte
Extraktion. Beispielsweise werden dynamische Optionen auf öffentliche
label/value/disabled-Datensätze reduziert, anstatt beliebige Eigenschaften aus
Anwendungsobjekten zu kopieren.
Setzen Sie diesen Compiler nicht direkt aus einem MCP- oder anderen nicht vertrauenswürdigen Anfrage-Handler ein. Abfrageebenen sollten zuvor generierte Vertragsartefakte lesen.
Test-Locators
Jeder Knoten hat ein geordnetes locators-Array. Der Adapter liest automatisch diese
häufigen Attribute aus props.attributes:
data-testiddata-test-iddata-testdata-cydata-pw
Er kann auch explizite Rollen-, zugängliche Namen-, Platzhalter- und Formly-Feld-ID-Kandidaten beibehalten. Ein leeres Array bedeutet, dass kein zuverlässiger Locator gefunden wurde; der Adapter erfindet niemals CSS oder XPath.
Anwendungen mit eigener Namenskonvention können testIdAttributes setzen und einen
deterministischen deriveLocators-Callback bereitstellen. Der Callback erhält nur
eingefrorene Identitätsdaten, nicht das Live-Formly-Feld. Er kann mehrere benannte Ziele
für ein zusammengesetztes Widget wie einen Datumsbereich zurückgeben; seine Ausgabe wird
als confidence: "derived" markiert. Siehe die
v0.3-Locator-Spezifikation für den vollständigen
Vertrag und Beispiele.
Beweismodell
Der Vertrag hält drei Beweisstufen getrennt:
Beweis | Bedeutung | Jetzt verfügbar? |
| Sicher aus gelieferter Formly-Konfiguration gelesen | Ja |
| Aus einem kontrollierten Formly-Build für ein synthetisches Szenario gelesen | Ja |
| In einem echten gerenderten Browser-DOM gesehen | Schema-bereit; Erfassungsschicht nicht implementiert |
Ein aufgelöster Locator wird nicht stillschweigend als im Browser beobachtet dargestellt. Ebenso wird undurchsichtiges oder asynchrones Verhalten gemeldet, nicht geraten.
Unterstützte Vertragsinformationen
Schema v0.3 kann darstellen:
geordnete Steuerelemente, Gruppen, Nur-Anzeige-Knoten und Array-Vorlagen;
stabile semantische Knoten-IDs und kumulative Modellpfade;
Formly- und gängige semantische Steuerelementtypen;
Labels, Beschreibungen, Platzhalter, JSON-sichere Standardwerte und Wrapper;
Pflicht-, Min-/Max-, Längen-, Zeichenfolgenmuster- und benannte Einschränkungen;
statische und aufgelöste öffentliche Optionen plus Metadaten für dynamische/async Optionsquellen;
Zeichenfolgen-/Boolesche Bedingungen und Callback-/Async-Dynamikregel-Metadaten;
aufgelösten Versteckt-, Readonly- und Deaktiviert-Zustand;
exakte und abgeleitete Locator-Kandidaten, einschließlich mehrerer benannter Ziele; und
deterministische Diagnosen, kanonisches JSON und Inhalts-Hashing.
Bewusste Einschränkungen
Formulare müssen explizit geliefert werden; der Adapter entdeckt keine beliebigen TypeScript-Exporte oder Anwendungsrouten.
Deklarierte Extraktion wertet niemals Funktionen oder Funktionsquellen aus.
Der Szenariokompilierer führt den anfänglichen kontrollierten Formly-Build aus, wartet aber nicht auf entfernte Optionen oder lebenszyklusgesteuertes Browserverhalten.
Formly-
RegExp-Muster werden diagnostiziert; v0.3 stellt nur Zeichenfolgenmuster dar.Benutzerdefinierte Widget-Aktionen und Wert-Codecs sind noch nicht modelliert.
Das Projekt generiert oder führt derzeit keine Cypress/Playwright-Tests aus.
Kein Produktions-MCP-Server oder Browser-Beobachtungsschicht ist enthalten.
Kompatibilität ist für Angular
20.3.29mit Formly6.1.8bewiesen, nicht für jede Angular/Formly-Kombination.npm-Veröffentlichung und Release-Automatisierung sind noch nicht enthalten.
Synthetische Testanwendung
Die Angular-Testanwendung enthält zwölf erfundene Formulare, die native und benutzerdefinierte Felder, Wrapper, Validatoren, Erweiterungen, Voreinstellungen, Ausdrücke, Validierung, Wiederholer, undurchsichtiges Verhalten und Legacy-Formly-v6-Aliase abdecken.
pnpm app:serveÖffnen Sie http://127.0.0.1:4200/ und wählen Sie ein Fixture aus dem Katalog.
Arbeitsplatzformulare und -daten sollten in einem privaten Arbeitsrepository bleiben. Ein
privates Fixture-Modul kann TestFormDefinition implementieren und eine Gruppe über
TEST_FORM_GROUPS registrieren, ohne Arbeitsplatz-Labels, -Kennungen, -Optionen oder
-Regeln in dieses öffentliche Projekt zu kopieren.
Repository-Struktur
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 evidenceRoadmap
Der beabsichtigte Lieferpfad ist:
Form Contract packages (current)
|
read-only MCP queries
|
typed E2E intent
|
deterministic Playwright/Cypress drivers
|
browser observation and parity checksZukünftige Schichten sollten unveränderliche Verträge konsumieren. Sie sollten keine Angular-Ausführung, beliebige Callback-Auswertung oder Selektor-Erfindung in routinemäßige Agent-Anfragen verschieben.
Dokumentation
Mitwirken und Sicherheit
Beiträge sind willkommen. Lies CONTRIBUTING.md und den Code of Conduct, bevor du dich beteiligst. Melde Sicherheitsprobleme über das in SECURITY.md beschriebene private Verfahren.
Dieses Projekt ist unter der MIT License verfügbar.
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