Skip to main content
Glama
dills122

Formly Agent Contracts

by dills122

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-id und data-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

@formly-contract/contract-schema

Vertrags-DTOs, Laufzeitvalidierung, kanonisches JSON und SHA-256-Inhalts-Hashing

@formly-contract/formly-adapter

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.29 und Formly 6.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 tooling

1. 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 build

Verknü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 inspection

Verbraucher 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.1

  • pnpm 10.23.0

pnpm install --frozen-lockfile
pnpm demo

pnpm demo baut den Paketausschnitt und gibt einen kanonischen JSON-Vertrag aus. Führen Sie das vollständige Repository-Gate aus mit:

pnpm check

Dieser 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-testid

  • data-test-id

  • data-test

  • data-cy

  • data-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?

declared

Sicher aus gelieferter Formly-Konfiguration gelesen

Ja

resolved

Aus einem kontrollierten Formly-Build für ein synthetisches Szenario gelesen

Ja

observed

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.29 mit Formly 6.1.8 bewiesen, 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 evidence

Roadmap

Der beabsichtigte Lieferpfad ist:

Form Contract packages (current)
              |
      read-only MCP queries
              |
        typed E2E intent
              |
 deterministic Playwright/Cypress drivers
              |
 browser observation and parity checks

Zukü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.

Maintenance

ActivityMaintained
ResponsivenessResponsive

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

Related MCP Servers

Latest Blog Posts

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