@ng-forge/dynamic-form-mcp 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/ng-forge-mcp.js +1146 -536
- package/package.json +6 -6
- package/src/index.js +1146 -537
- package/src/registry/documentation.d.ts +14 -0
- package/src/registry/documentation.d.ts.map +1 -0
- package/src/registry/field-types.d.ts +9 -0
- package/src/registry/field-types.d.ts.map +1 -0
- package/src/registry/index.d.ts +10 -16
- package/src/registry/index.d.ts.map +1 -1
- package/src/registry/instructions.d.ts +1 -1
- package/src/registry/instructions.d.ts.map +1 -1
- package/src/registry/ui-adapters.d.ts +9 -0
- package/src/registry/ui-adapters.d.ts.map +1 -0
- package/src/registry/validators.d.ts +9 -0
- package/src/registry/validators.d.ts.map +1 -0
- package/src/resources/documentation.resource.d.ts +2 -1
- package/src/resources/documentation.resource.d.ts.map +1 -1
- package/src/services/doc-fetcher.d.ts +34 -0
- package/src/services/doc-fetcher.d.ts.map +1 -0
- package/src/services/topic-mapper.d.ts +18 -0
- package/src/services/topic-mapper.d.ts.map +1 -0
- package/src/tools/data/lookup-topics.d.ts +5 -0
- package/src/tools/data/lookup-topics.d.ts.map +1 -1
- package/src/tools/examples.tool.d.ts +18 -0
- package/src/tools/examples.tool.d.ts.map +1 -1
- package/src/tools/index.d.ts +8 -6
- package/src/tools/index.d.ts.map +1 -1
- package/src/tools/lookup.tool.d.ts.map +1 -1
- package/src/tools/search.tool.d.ts +9 -0
- package/src/tools/search.tool.d.ts.map +1 -0
- package/src/tools/validate.tool.d.ts.map +1 -1
- package/src/registry/api-reference.json +0 -561
- package/src/registry/docs.json +0 -266
- package/src/registry/field-types.json +0 -502
- package/src/registry/ui-adapters.json +0 -225
- package/src/registry/validators.json +0 -210
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Documentation Registry Data
|
|
3
|
+
*
|
|
4
|
+
* Maps documentation topics to their online URLs at ng-forge.com.
|
|
5
|
+
* Replaces the previously bundled docs.json with links to the live documentation site.
|
|
6
|
+
*/
|
|
7
|
+
export interface DocPage {
|
|
8
|
+
id: string;
|
|
9
|
+
title: string;
|
|
10
|
+
category: string;
|
|
11
|
+
url: string;
|
|
12
|
+
}
|
|
13
|
+
export declare const DOCUMENTATION: DocPage[];
|
|
14
|
+
//# sourceMappingURL=documentation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"documentation.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/registry/documentation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,eAAO,MAAM,aAAa,EAAE,OAAO,EA0HlC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Field Type Registry Data
|
|
3
|
+
*
|
|
4
|
+
* Canonical source of field type metadata for the MCP server.
|
|
5
|
+
* Previously generated as field-types.json by generate-registry.ts.
|
|
6
|
+
*/
|
|
7
|
+
import type { FieldTypeInfo } from './index.js';
|
|
8
|
+
export declare const FIELD_TYPES: FieldTypeInfo[];
|
|
9
|
+
//# sourceMappingURL=field-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-types.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/registry/field-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,eAAO,MAAM,WAAW,EAAE,aAAa,EAqrBtC,CAAC"}
|
package/src/registry/index.d.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Registry module for
|
|
2
|
+
* Registry module for field type, validator, and UI adapter metadata
|
|
3
3
|
*
|
|
4
4
|
* This module provides access to field types, validators, and UI adapters
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* JSON data is imported directly to work correctly with esbuild bundling.
|
|
5
|
+
* defined as TypeScript data in the registry source files.
|
|
8
6
|
*/
|
|
9
7
|
export interface PropertyInfo {
|
|
10
8
|
name: string;
|
|
@@ -53,12 +51,8 @@ export interface UIAdapterInfo {
|
|
|
53
51
|
fieldTypes: UIAdapterFieldType[];
|
|
54
52
|
providerFunction: string;
|
|
55
53
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
title: string;
|
|
59
|
-
category: string;
|
|
60
|
-
content: string;
|
|
61
|
-
}
|
|
54
|
+
import { type DocPage } from './documentation.js';
|
|
55
|
+
export type { DocPage };
|
|
62
56
|
/**
|
|
63
57
|
* Get all available field types
|
|
64
58
|
*/
|
|
@@ -96,15 +90,15 @@ export declare function getUIAdapter(library: 'material' | 'bootstrap' | 'primen
|
|
|
96
90
|
*/
|
|
97
91
|
export declare function getUIAdapterFieldType(library: 'material' | 'bootstrap' | 'primeng' | 'ionic', fieldType: string): UIAdapterFieldType | undefined;
|
|
98
92
|
/**
|
|
99
|
-
* Get all documentation
|
|
93
|
+
* Get all documentation pages
|
|
100
94
|
*/
|
|
101
|
-
export declare function
|
|
95
|
+
export declare function getDocPages(): DocPage[];
|
|
102
96
|
/**
|
|
103
|
-
* Get a specific documentation
|
|
97
|
+
* Get a specific documentation page by ID
|
|
104
98
|
*/
|
|
105
|
-
export declare function
|
|
99
|
+
export declare function getDocPage(id: string): DocPage | undefined;
|
|
106
100
|
/**
|
|
107
|
-
* Get documentation
|
|
101
|
+
* Get documentation pages by category
|
|
108
102
|
*/
|
|
109
|
-
export declare function
|
|
103
|
+
export declare function getDocPagesByCategory(category: string): DocPage[];
|
|
110
104
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/registry/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/registry/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* This content is served via the ng-forge://instructions resource
|
|
5
5
|
* to guide AI assistants in generating FormConfig objects.
|
|
6
6
|
*/
|
|
7
|
-
export declare const INSTRUCTIONS = "# ng-forge Dynamic Forms - Best Practices\n\nYou MUST follow these practices when generating FormConfig objects for ng-forge.\n\n## Core Principles\n\n1. **Configuration-driven**: ng-forge wraps Angular Reactive Forms. Define structure declaratively via `FormConfig`, not imperatively.\n2. **Type-safe**: Use TypeScript interfaces for form values. The library provides full type inference.\n3. **Validation-first**: Always include validation and user-friendly error messages.\n\n## FormConfig Structure\n\n```typescript\nconst config: FormConfig = {\n // Optional: Default validation messages for all fields\n defaultValidationMessages: {\n required: 'This field is required',\n email: 'Please enter a valid email',\n minLength: 'Must be at least {{requiredLength}} characters',\n },\n // Required: Array of field definitions\n fields: [\n // ... field definitions\n ],\n};\n```\n\n## Field Definition Rules\n\n### Required Properties\n\nEvery field MUST have:\n\n- `key`: Unique identifier (except for `row` type which is layout-only)\n- `type`: One of the registered field types\n- `label`: Human-readable label (for accessibility)\n\n### Value Fields\n\nFor fields that collect user input (`input`, `textarea`, `select`, `checkbox`, `radio`, `datepicker`, `toggle`, `slider`):\n\n```typescript\n{\n key: 'email',\n type: 'input',\n label: 'Email Address',\n required: true, // Shorthand validator\n email: true, // Shorthand validator\n validationMessages: { // Always provide clear messages\n required: 'Email is required',\n email: 'Please enter a valid email'\n },\n props: {\n type: 'email', // HTML input type\n placeholder: 'user@example.com',\n hint: 'We will never share your email' // UI library specific\n }\n}\n```\n\n### Select/Radio Fields\n\nMUST include `options` array:\n\n```typescript\n{\n key: 'country',\n type: 'select',\n label: 'Country',\n required: true,\n options: [\n { value: 'us', label: 'United States' },\n { value: 'uk', label: 'United Kingdom' }\n ],\n props: { placeholder: 'Select a country' }\n}\n```\n\n### Container Fields\n\n#### Row (Horizontal Layout)\n\nUse for side-by-side fields. Row fields do NOT create nested values - children are flat.\n\n```typescript\n{\n key: 'nameRow',\n type: 'row',\n fields: [\n { key: 'firstName', type: 'input', label: 'First', col: 6 },\n { key: 'lastName', type: 'input', label: 'Last', col: 6 }\n ]\n}\n// Result: { firstName: '...', lastName: '...' }\n```\n\nUse `col` property (1-12) to control column widths.\n\n#### Group (Nested Object)\n\nUse when you need nested object structure in form values:\n\n```typescript\n{\n key: 'address',\n type: 'group',\n fields: [\n { key: 'street', type: 'input', label: 'Street' },\n { key: 'city', type: 'input', label: 'City' }\n ]\n}\n// Result: { address: { street: '...', city: '...' } }\n```\n\n#### Array (Repeatable Items)\n\nUse for dynamic lists. Each item is wrapped in a `<div class=\"df-array-item\">` with `role=\"group\"` and `aria-label=\"Item N\"` for accessibility. Use `--df-array-item-gap` CSS variable to control spacing between items.\n\n```typescript\n{\n key: 'contacts',\n type: 'array',\n // \u26A0\uFE0F NO label property on arrays!\n fields: [\n {\n key: 'contact',\n type: 'group',\n fields: [\n { key: 'name', type: 'input', label: 'Name', required: true },\n { key: 'phone', type: 'input', label: 'Phone', required: true }\n ]\n }\n ]\n}\n// Result: { contacts: [{ name: '...', phone: '...' }, ...] }\n```\n\n#### Page (Multi-step Forms)\n\nUse for wizard-style forms:\n\n```typescript\n{\n fields: [\n {\n key: 'step1',\n type: 'page',\n fields: [\n { key: 'name', type: 'input', label: 'Name' },\n { key: 'next', type: 'next', label: 'Continue' },\n ],\n },\n {\n key: 'step2',\n type: 'page',\n fields: [\n { key: 'prev', type: 'previous', label: 'Back' },\n { key: 'submit', type: 'submit', label: 'Submit' },\n ],\n },\n ];\n}\n```\n\n## Validation\n\n### Shorthand Validators (Preferred)\n\nUse shorthand properties directly on field definitions:\n\n```typescript\n{\n key: 'age',\n type: 'input',\n label: 'Age',\n required: true,\n min: 18,\n max: 120,\n validationMessages: {\n required: 'Age is required',\n min: 'Must be at least {{min}}',\n max: 'Cannot exceed {{max}}'\n }\n}\n```\n\nAvailable shorthands: `required`, `email`, `min`, `max`, `minLength`, `maxLength`, `pattern`\n\n### Validation Messages\n\nALWAYS provide validation messages. Use template variables:\n\n- `{{requiredLength}}` - for minLength/maxLength\n- `{{min}}`, `{{max}}` - for min/max\n- `{{requiredPattern}}` - for pattern\n\n## Conditional Logic\n\nUse `logic` array for conditional behavior:\n\n```typescript\n{\n key: 'businessName',\n type: 'input',\n label: 'Business Name',\n logic: [\n {\n type: 'hidden',\n condition: {\n type: 'fieldValue',\n fieldPath: 'accountType',\n operator: 'notEquals',\n value: 'business'\n }\n },\n {\n type: 'required',\n condition: {\n type: 'fieldValue',\n fieldPath: 'accountType',\n operator: 'equals',\n value: 'business'\n }\n }\n ]\n}\n```\n\n### Logic Types\n\n- `hidden` - Show/hide field\n- `disabled` - Enable/disable field\n- `required` - Conditional requirement\n\n### Condition Operators\n\n- `equals`, `notEquals`\n- `greaterThan`, `lessThan`, `greaterThanOrEquals`, `lessThanOrEquals`\n- `contains`, `notContains`\n- `empty`, `notEmpty`\n\n## UI Library Integration\n\nng-forge supports multiple UI libraries. Configure in `app.config.ts`:\n\n```typescript\nimport { provideDynamicForm } from '@ng-forge/dynamic-forms';\nimport { withMaterialFields } from '@ng-forge/dynamic-forms-material';\n\nexport const appConfig = {\n providers: [provideDynamicForm(...withMaterialFields())],\n};\n```\n\nAvailable adapters:\n\n- `@ng-forge/dynamic-forms-material` - Angular Material\n- `@ng-forge/dynamic-forms-bootstrap` - Bootstrap 5\n- `@ng-forge/dynamic-forms-primeng` - PrimeNG\n- `@ng-forge/dynamic-forms-ionic` - Ionic\n\n## Common Patterns\n\n### Always End with Submit Button\n\n```typescript\n{ type: 'submit', key: 'submit', label: 'Submit', props: { color: 'primary' } }\n```\n\n### Use Text Fields for Headings\n\n```typescript\n{ key: 'sectionTitle', type: 'text', label: 'Personal Info', props: { elementType: 'h3' } }\n```\n\n### Input Types via Props\n\n```typescript\n// Email input\n{ key: 'email', type: 'input', props: { type: 'email' } }\n\n// Password input\n{ key: 'password', type: 'input', props: { type: 'password' } }\n\n// Number input\n{ key: 'age', type: 'input', props: { type: 'number' } }\n\n// Phone input\n{ key: 'phone', type: 'input', props: { type: 'tel' } }\n```\n\n## Anti-patterns to Avoid\n\n1. **Missing labels** - Always include labels for accessibility\n2. **Missing validation messages** - Users need clear feedback\n3. **Duplicate keys** - Each key must be unique within its scope\n4. **Select without options** - Select/radio fields must have options\n5. **Array without fields** - Array fields need a fields template\n6. **Group without fields** - Group fields need child fields\n7. **min > max** - Ensure min values are less than max values\n\n## CRITICAL: UI Library Differences\n\nDifferent UI libraries support different properties. Always validate against the correct library using `ngforge_validate_form_config` with the appropriate `uiIntegration` parameter.\n\n### Property Differences by Library\n\n| Property | Material | Bootstrap | PrimeNG | Ionic |\n|----------|----------|-----------|---------|-------|\n| `appearance` | \u2713 (fill, outline) | \u2717 | \u2717 | \u2713 (fill, outline) |\n| `subscriptSizing` | \u2713 | \u2717 | \u2717 | \u2717 |\n| `floatLabel` | \u2713 | \u2717 | \u2713 | \u2717 |\n| `hint` | \u2713 | \u2713 (as `helpText`) | \u2713 | \u2713 |\n\n### Container Fields\n\nContainer fields (`page`, `group`, `row`) do NOT support these properties:\n- `label` - Use `text` field type for headings instead\n- `required`, `email`, `min`, `max`, etc. - Validation is for leaf fields only\n\n### Common Mistakes to Avoid\n\n1. **Using `expressions` on fields** - This property is NOT supported on standard fields. Use `derivation` for computed values or `logic` for conditional behavior.\n\n2. **Adding `label` to container fields** - Pages, groups, and rows don't have labels:\n ```typescript\n // \u274C WRONG\n { key: 'address', type: 'group', label: 'Address', fields: [...] }\n\n // \u2705 CORRECT - Use a text field for the heading\n { key: 'addressTitle', type: 'text', label: 'Address', props: { elementType: 'h3' } }\n { key: 'address', type: 'group', fields: [...] }\n ```\n\n3. **Adding `id` to FormConfig** - The root FormConfig does not accept an `id` property.\n\n4. **Putting slider min/max in props** - For slider fields, `min`, `max`, and `step` are field-level properties:\n ```typescript\n // \u274C WRONG\n { key: 'volume', type: 'slider', label: 'Volume', props: { min: 0, max: 100 } }\n\n // \u2705 CORRECT\n { key: 'volume', type: 'slider', label: 'Volume', min: 0, max: 100 }\n ```\n\n5. **Using unsupported field types** - Each UI library supports specific field types. Use `ngforge_get_field_schema` to see available types.\n\n## Validation Before Use\n\nAlways validate your FormConfig using the `ngforge_validate_form_config` tool before using it. This tool uses the actual TypeScript/Zod schemas, so if validation passes, the config will work correctly at runtime.\n\n```typescript\n// Always specify the UI integration you're using\nngforge_validate_form_config({\n uiIntegration: 'material', // or 'bootstrap', 'primeng', 'ionic'\n config: { fields: [...] }\n})\n```\n\nTo understand what properties are supported for each field type, use `ngforge_get_field_schema`:\n\n```typescript\nngforge_get_field_schema({ uiIntegration: 'material' })\n```\n";
|
|
7
|
+
export declare const INSTRUCTIONS = "# ng-forge Dynamic Forms - Best Practices\n\nYou MUST follow these practices when generating FormConfig objects for ng-forge.\n\n## Core Principles\n\n1. **Configuration-driven**: ng-forge wraps Angular Reactive Forms. Define structure declaratively via `FormConfig`, not imperatively.\n2. **Type-safe**: Use TypeScript interfaces for form values. The library provides full type inference.\n3. **Validation-first**: Always include validation and user-friendly error messages.\n\n## FormConfig Structure\n\n```typescript\nconst config: FormConfig = {\n // Optional: Default validation messages for all fields\n defaultValidationMessages: {\n required: 'This field is required',\n email: 'Please enter a valid email',\n minLength: 'Must be at least {{requiredLength}} characters',\n },\n // Required: Array of field definitions\n fields: [\n // ... field definitions\n ],\n};\n```\n\n## Field Definition Rules\n\n### Required Properties\n\nEvery field MUST have:\n\n- `key`: Unique identifier (except for `row` type which is layout-only)\n- `type`: One of the registered field types\n- `label`: Human-readable label (for accessibility)\n\n### Value Fields\n\nFor fields that collect user input (`input`, `textarea`, `select`, `checkbox`, `radio`, `datepicker`, `toggle`, `slider`):\n\n```typescript\n{\n key: 'email',\n type: 'input',\n label: 'Email Address',\n required: true, // Shorthand validator\n email: true, // Shorthand validator\n validationMessages: { // Always provide clear messages\n required: 'Email is required',\n email: 'Please enter a valid email'\n },\n props: {\n type: 'email', // HTML input type\n placeholder: 'user@example.com',\n hint: 'We will never share your email' // UI library specific\n }\n}\n```\n\n### Select/Radio Fields\n\nMUST include `options` array:\n\n```typescript\n{\n key: 'country',\n type: 'select',\n label: 'Country',\n required: true,\n options: [\n { value: 'us', label: 'United States' },\n { value: 'uk', label: 'United Kingdom' }\n ],\n props: { placeholder: 'Select a country' }\n}\n```\n\n### Container Fields\n\n#### Row (Horizontal Layout)\n\nUse for side-by-side fields. Row fields do NOT create nested values - children are flat.\n\n```typescript\n{\n key: 'nameRow',\n type: 'row',\n fields: [\n { key: 'firstName', type: 'input', label: 'First', col: 6 },\n { key: 'lastName', type: 'input', label: 'Last', col: 6 }\n ]\n}\n// Result: { firstName: '...', lastName: '...' }\n```\n\nUse `col` property (1-12) to control column widths.\n\n#### Group (Nested Object)\n\nUse when you need nested object structure in form values:\n\n```typescript\n{\n key: 'address',\n type: 'group',\n fields: [\n { key: 'street', type: 'input', label: 'Street' },\n { key: 'city', type: 'input', label: 'City' }\n ]\n}\n// Result: { address: { street: '...', city: '...' } }\n```\n\n#### Array (Repeatable Items)\n\nUse for dynamic lists. Each item is wrapped in a `<div class=\"df-array-item\">` with `role=\"group\"` and `aria-label=\"Item N\"` for accessibility. Use `--df-array-item-gap` CSS variable to control spacing between items.\n\n```typescript\n{\n key: 'contacts',\n type: 'array',\n // \u26A0\uFE0F NO label property on arrays!\n fields: [\n {\n key: 'contact',\n type: 'group',\n fields: [\n { key: 'name', type: 'input', label: 'Name', required: true },\n { key: 'phone', type: 'input', label: 'Phone', required: true }\n ]\n }\n ]\n}\n// Result: { contacts: [{ name: '...', phone: '...' }, ...] }\n```\n\n#### Page (Multi-step Forms)\n\nUse for wizard-style forms:\n\n```typescript\n{\n fields: [\n {\n key: 'step1',\n type: 'page',\n fields: [\n { key: 'name', type: 'input', label: 'Name' },\n { key: 'next', type: 'next', label: 'Continue' },\n ],\n },\n {\n key: 'step2',\n type: 'page',\n fields: [\n { key: 'prev', type: 'previous', label: 'Back' },\n { key: 'submit', type: 'submit', label: 'Submit' },\n ],\n },\n ];\n}\n```\n\n## Validation\n\n### Shorthand Validators (Preferred)\n\nUse shorthand properties directly on field definitions:\n\n```typescript\n{\n key: 'age',\n type: 'input',\n label: 'Age',\n required: true,\n min: 18,\n max: 120,\n validationMessages: {\n required: 'Age is required',\n min: 'Must be at least {{min}}',\n max: 'Cannot exceed {{max}}'\n }\n}\n```\n\nAvailable shorthands: `required`, `email`, `min`, `max`, `minLength`, `maxLength`, `pattern`\n\n### Validation Messages\n\nALWAYS provide validation messages. Use template variables:\n\n- `{{requiredLength}}` - for minLength/maxLength\n- `{{min}}`, `{{max}}` - for min/max\n- `{{requiredPattern}}` - for pattern\n\n## Conditional Logic\n\nUse `logic` array for conditional behavior:\n\n```typescript\n{\n key: 'businessName',\n type: 'input',\n label: 'Business Name',\n logic: [\n {\n type: 'hidden',\n condition: {\n type: 'fieldValue',\n fieldPath: 'accountType',\n operator: 'notEquals',\n value: 'business'\n }\n },\n {\n type: 'required',\n condition: {\n type: 'fieldValue',\n fieldPath: 'accountType',\n operator: 'equals',\n value: 'business'\n }\n }\n ]\n}\n```\n\n### Logic Types\n\n- `hidden` - Show/hide field\n- `disabled` - Enable/disable field\n- `required` - Conditional requirement\n\n### Condition Types\n\n#### Field Value Condition\n\nCompares a specific field's value:\n\n```typescript\n{\n type: 'fieldValue',\n fieldPath: 'accountType',\n operator: 'equals',\n value: 'business'\n}\n```\n\n#### Comparison Operators\n\n- `equals`, `notEquals`\n- `greater`, `less`, `greaterOrEqual`, `lessOrEqual`\n- `contains`, `startsWith`, `endsWith`, `matches`\n\n#### JavaScript Condition\n\nEvaluates a JavaScript expression with access to `formValue`, `fieldValue`, `externalData`:\n\n```typescript\n{\n type: 'javascript',\n expression: 'formValue.items.length > 0'\n}\n```\n\n#### Custom Condition\n\nInvokes a registered custom function by name:\n\n```typescript\n{\n type: 'custom',\n functionName: 'myCustomCheck'\n}\n```\n\nRegister functions via `customFnConfig.customFunctions`.\n\n#### Async Custom Condition\n\nInvokes a registered async function that returns `Promise<boolean>` or `Observable<boolean>`:\n\n```typescript\n{\n type: 'async',\n asyncFunctionName: 'checkPermission',\n pendingValue: false, // value while async resolution is pending (default: false)\n debounceMs: 300 // debounce for re-evaluation (default: 300)\n}\n```\n\nRegister functions via `customFnConfig.asyncConditions`. The function receives an `EvaluationContext` with access to `formValue`, `fieldValue`, and `externalData`.\n\n#### HTTP Condition\n\nEvaluates based on an HTTP response from a remote server. Fully declarative and JSON-serializable:\n\n```typescript\n{\n type: 'http',\n http: {\n url: '/api/permissions',\n method: 'GET',\n queryParams: {\n userId: 'formValue.userId',\n role: 'formValue.role'\n }\n },\n responseExpression: 'response.canEdit', // extract boolean from response (default: !!response)\n pendingValue: false, // value while HTTP request is in-flight (default: false)\n cacheDurationMs: 30000, // cache duration in ms (default: 30000)\n debounceMs: 300 // debounce for re-evaluation (default: 300)\n}\n```\n\nUse HTTP conditions when visibility, disabled state, or required state depends on server-side data (e.g., permissions, feature flags, inventory checks). The request re-evaluates reactively when dependent form values change.\n\n#### Logical Combinators\n\nCombine conditions with `and` (all must be true) or `or` (at least one must be true):\n\n```typescript\n{\n type: 'and',\n conditions: [\n { type: 'fieldValue', fieldPath: 'country', operator: 'equals', value: 'US' },\n { type: 'fieldValue', fieldPath: 'age', operator: 'greaterOrEqual', value: 18 }\n ]\n}\n```\n\n## UI Library Integration\n\nng-forge supports multiple UI libraries. Configure in `app.config.ts`:\n\n```typescript\nimport { provideDynamicForm } from '@ng-forge/dynamic-forms';\nimport { withMaterialFields } from '@ng-forge/dynamic-forms-material';\n\nexport const appConfig = {\n providers: [provideDynamicForm(...withMaterialFields())],\n};\n```\n\nAvailable adapters:\n\n- `@ng-forge/dynamic-forms-material` - Angular Material\n- `@ng-forge/dynamic-forms-bootstrap` - Bootstrap 5\n- `@ng-forge/dynamic-forms-primeng` - PrimeNG\n- `@ng-forge/dynamic-forms-ionic` - Ionic\n\n## Common Patterns\n\n### Always End with Submit Button\n\n```typescript\n{ type: 'submit', key: 'submit', label: 'Submit', props: { color: 'primary' } }\n```\n\n### Use Text Fields for Headings\n\n```typescript\n{ key: 'sectionTitle', type: 'text', label: 'Personal Info', props: { elementType: 'h3' } }\n```\n\n### Input Types via Props\n\n```typescript\n// Email input\n{ key: 'email', type: 'input', props: { type: 'email' } }\n\n// Password input\n{ key: 'password', type: 'input', props: { type: 'password' } }\n\n// Number input\n{ key: 'age', type: 'input', props: { type: 'number' } }\n\n// Phone input\n{ key: 'phone', type: 'input', props: { type: 'tel' } }\n```\n\n## Anti-patterns to Avoid\n\n1. **Missing labels** - Always include labels for accessibility\n2. **Missing validation messages** - Users need clear feedback\n3. **Duplicate keys** - Each key must be unique within its scope\n4. **Select without options** - Select/radio fields must have options\n5. **Array without fields** - Array fields need a fields template\n6. **Group without fields** - Group fields need child fields\n7. **min > max** - Ensure min values are less than max values\n\n## CRITICAL: UI Library Differences\n\nDifferent UI libraries support different properties. Always validate against the correct library using `ngforge_validate_form_config` with the appropriate `uiIntegration` parameter.\n\n### Property Differences by Library\n\n| Property | Material | Bootstrap | PrimeNG | Ionic |\n|----------|----------|-----------|---------|-------|\n| `appearance` | \u2713 (fill, outline) | \u2717 | \u2717 | \u2713 (fill, outline) |\n| `subscriptSizing` | \u2713 | \u2717 | \u2717 | \u2717 |\n| `floatLabel` | \u2713 | \u2717 | \u2713 | \u2717 |\n| `hint` | \u2713 | \u2713 (as `helpText`) | \u2713 | \u2713 |\n\n### Container Fields\n\nContainer fields (`page`, `group`, `row`) do NOT support these properties:\n- `label` - Use `text` field type for headings instead\n- `required`, `email`, `min`, `max`, etc. - Validation is for leaf fields only\n\n### Common Mistakes to Avoid\n\n1. **Using `expressions` on fields** - This property is NOT supported on standard fields. Use `derivation` for computed values or `logic` for conditional behavior.\n\n2. **Adding `label` to container fields** - Pages, groups, and rows don't have labels:\n ```typescript\n // \u274C WRONG\n { key: 'address', type: 'group', label: 'Address', fields: [...] }\n\n // \u2705 CORRECT - Use a text field for the heading\n { key: 'addressTitle', type: 'text', label: 'Address', props: { elementType: 'h3' } }\n { key: 'address', type: 'group', fields: [...] }\n ```\n\n3. **Adding `id` to FormConfig** - The root FormConfig does not accept an `id` property.\n\n4. **Putting slider min/max in props** - For slider fields, `min`, `max`, and `step` are field-level properties:\n ```typescript\n // \u274C WRONG\n { key: 'volume', type: 'slider', label: 'Volume', props: { min: 0, max: 100 } }\n\n // \u2705 CORRECT\n { key: 'volume', type: 'slider', label: 'Volume', min: 0, max: 100 }\n ```\n\n5. **Using unsupported field types** - Each UI library supports specific field types. Use `ngforge_get_field_schema` to see available types.\n\n## Validation Before Use\n\nAlways validate your FormConfig using the `ngforge_validate_form_config` tool before using it. This tool uses the actual TypeScript/Zod schemas, so if validation passes, the config will work correctly at runtime.\n\n```typescript\n// Always specify the UI integration you're using\nngforge_validate_form_config({\n uiIntegration: 'material', // or 'bootstrap', 'primeng', 'ionic'\n config: { fields: [...] }\n})\n```\n\nTo understand what properties are supported for each field type, use `ngforge_get_field_schema`:\n\n```typescript\nngforge_get_field_schema({ uiIntegration: 'material' })\n```\n";
|
|
8
8
|
//# sourceMappingURL=instructions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/registry/instructions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/registry/instructions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,YAAY,svYAucxB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI Adapter Registry Data
|
|
3
|
+
*
|
|
4
|
+
* Canonical source of UI adapter metadata for the MCP server.
|
|
5
|
+
* Previously generated as ui-adapters.json by generate-registry.ts.
|
|
6
|
+
*/
|
|
7
|
+
import type { UIAdapterInfo } from './index.js';
|
|
8
|
+
export declare const UI_ADAPTERS: UIAdapterInfo[];
|
|
9
|
+
//# sourceMappingURL=ui-adapters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-adapters.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/registry/ui-adapters.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,eAAO,MAAM,WAAW,EAAE,aAAa,EAgOtC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validator Registry Data
|
|
3
|
+
*
|
|
4
|
+
* Canonical source of validator metadata for the MCP server.
|
|
5
|
+
* Previously generated as validators.json by generate-registry.ts.
|
|
6
|
+
*/
|
|
7
|
+
import type { ValidatorInfo } from './index.js';
|
|
8
|
+
export declare const VALIDATORS: ValidatorInfo[];
|
|
9
|
+
//# sourceMappingURL=validators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/registry/validators.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,eAAO,MAAM,UAAU,EAAE,aAAa,EAsPrC,CAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Documentation Resource
|
|
3
3
|
*
|
|
4
|
-
* Exposes ng-forge
|
|
4
|
+
* Exposes ng-forge documentation as MCP resources.
|
|
5
|
+
* Fetches live content from ng-forge.com with fallback to static links.
|
|
5
6
|
*/
|
|
6
7
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
8
|
export declare function registerDocumentationResource(server: McpServer): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documentation.resource.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/resources/documentation.resource.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"documentation.resource.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/resources/documentation.resource.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAoIrE"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Documentation Fetcher Service
|
|
3
|
+
*
|
|
4
|
+
* Fetches and caches live documentation from ng-forge.com.
|
|
5
|
+
* Uses native fetch (Node >=20) with in-memory caching and TTL.
|
|
6
|
+
*
|
|
7
|
+
* Fetches:
|
|
8
|
+
* - llms.txt: Documentation index
|
|
9
|
+
* - llms-full.txt: Full documentation content, parsed into sections
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Fetch the llms.txt documentation index.
|
|
13
|
+
* Returns null if fetch fails.
|
|
14
|
+
*/
|
|
15
|
+
export declare function fetchDocIndex(): Promise<string | null>;
|
|
16
|
+
/**
|
|
17
|
+
* Fetch all documentation sections from llms-full.txt.
|
|
18
|
+
* Returns null if fetch fails.
|
|
19
|
+
*/
|
|
20
|
+
export declare function fetchAllSections(): Promise<Map<string, string> | null>;
|
|
21
|
+
/**
|
|
22
|
+
* Fetch a specific documentation section by path.
|
|
23
|
+
* Returns null if fetch fails or section not found.
|
|
24
|
+
*/
|
|
25
|
+
export declare function fetchDocSection(path: string): Promise<string | null>;
|
|
26
|
+
/**
|
|
27
|
+
* Clear all caches. Useful for testing or forcing a refresh.
|
|
28
|
+
*/
|
|
29
|
+
export declare function clearCache(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Set cache TTL in milliseconds.
|
|
32
|
+
*/
|
|
33
|
+
export declare function setCacheTtl(ttlMs: number): void;
|
|
34
|
+
//# sourceMappingURL=doc-fetcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doc-fetcher.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/services/doc-fetcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA8DH;;;GAGG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAU5D;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,CAa5E;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAG1E;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAGjC;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE/C"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Topic-to-Section Mapper
|
|
3
|
+
*
|
|
4
|
+
* Maps MCP TOPICS keys to llms-full.txt section paths.
|
|
5
|
+
* Some topics map to multiple sections (concatenated when fetched).
|
|
6
|
+
* Topics with no website equivalent (MCP-specific patterns) return null.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Get the section paths for a topic.
|
|
10
|
+
* Returns null for MCP-only topics (should use hardcoded fallback).
|
|
11
|
+
* Returns undefined for unknown topics.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getTopicSections(topic: string): string[] | null | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Check if a topic is MCP-specific (no website equivalent).
|
|
16
|
+
*/
|
|
17
|
+
export declare function isMcpOnlyTopic(topic: string): boolean;
|
|
18
|
+
//# sourceMappingURL=topic-mapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"topic-mapper.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/services/topic-mapper.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAkFH;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,CAK3E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAErD"}
|
|
@@ -11,6 +11,11 @@ export declare const TOPICS: Record<string, {
|
|
|
11
11
|
brief: string;
|
|
12
12
|
full: string;
|
|
13
13
|
}>;
|
|
14
|
+
/**
|
|
15
|
+
* One-liner descriptions for each topic key.
|
|
16
|
+
* Used by the enhanced `list` output and the search tool.
|
|
17
|
+
*/
|
|
18
|
+
export declare const TOPIC_DESCRIPTIONS: Record<string, string>;
|
|
14
19
|
/**
|
|
15
20
|
* Topic aliases for flexible lookup.
|
|
16
21
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lookup-topics.d.ts","sourceRoot":"","sources":["../../../../../../packages/dynamic-form-mcp/src/tools/data/lookup-topics.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"lookup-topics.d.ts","sourceRoot":"","sources":["../../../../../../packages/dynamic-form-mcp/src/tools/data/lookup-topics.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAm5ElE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA2CrD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA8HhD,CAAC"}
|
|
@@ -8,5 +8,23 @@
|
|
|
8
8
|
* Single tool for "Show me how to do X"
|
|
9
9
|
*/
|
|
10
10
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
11
|
+
/**
|
|
12
|
+
* Pattern definitions with minimal, brief, full, and explained content.
|
|
13
|
+
*/
|
|
14
|
+
export declare const PATTERNS: Record<string, {
|
|
15
|
+
description: string;
|
|
16
|
+
minimal: string;
|
|
17
|
+
brief: string;
|
|
18
|
+
full: string;
|
|
19
|
+
explained: string;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Complete multi-page form example.
|
|
23
|
+
*/
|
|
24
|
+
export declare const COMPLETE_EXAMPLE = "# Complete Multi-Page Form Example\n\nThis is a **complete, copy-pasteable** form configuration that demonstrates:\n- Multi-page navigation\n- Value derivation (computed fields - self-targeting)\n- Conditional visibility (using logic blocks - NO hideWhen/showWhen shorthand)\n- Validation (required, email, minLength)\n- Groups for nested data\n- Various field types\n\n```typescript\nimport { FormConfig } from '@ng-forge/dynamic-forms';\n\nconst formConfig = {\n fields: [\n // ========== PAGE 1: Personal Info ==========\n {\n key: 'personalInfo',\n type: 'page',\n fields: [\n { key: 'header1', type: 'text', label: 'Personal Information', props: { elementType: 'h2' } },\n {\n key: 'nameRow',\n type: 'row',\n fields: [\n { key: 'firstName', type: 'input', label: 'First Name', required: true, minLength: 2, col: 6 },\n { key: 'lastName', type: 'input', label: 'Last Name', required: true, minLength: 2, col: 6 }\n ]\n },\n {\n key: 'fullName',\n type: 'input',\n label: 'Full Name',\n readonly: true,\n // Shorthand derivation - no targetField needed, derivation is on the target field itself\n derivation: '(formValue.firstName || \"\") + \" \" + (formValue.lastName || \"\")'\n },\n { key: 'email', type: 'input', label: 'Email', required: true, email: true, props: { type: 'email' } },\n { key: 'next1', type: 'next', label: 'Continue' }\n ]\n },\n // ========== PAGE 2: Address ==========\n {\n key: 'addressPage',\n type: 'page',\n fields: [\n { key: 'header2', type: 'text', label: 'Address', props: { elementType: 'h2' } },\n {\n key: 'address',\n type: 'group',\n fields: [\n { key: 'street', type: 'input', label: 'Street', required: true },\n {\n key: 'cityRow',\n type: 'row',\n fields: [\n { key: 'city', type: 'input', label: 'City', required: true, col: 6 },\n {\n key: 'state',\n type: 'select',\n label: 'State',\n required: true,\n col: 6,\n options: [\n { label: 'California', value: 'CA' },\n { label: 'New York', value: 'NY' },\n { label: 'Texas', value: 'TX' }\n ]\n }\n ]\n }\n ]\n },\n {\n key: 'navRow2',\n type: 'row',\n fields: [\n { key: 'back2', type: 'previous', label: 'Back', col: 6 },\n { key: 'next2', type: 'next', label: 'Continue', col: 6 }\n ]\n }\n ]\n },\n // ========== PAGE 3: Preferences ==========\n {\n key: 'prefsPage',\n type: 'page',\n fields: [\n { key: 'header3', type: 'text', label: 'Preferences', props: { elementType: 'h2' } },\n {\n key: 'accountType',\n type: 'radio',\n label: 'Account Type',\n required: true,\n options: [\n { label: 'Personal', value: 'personal' },\n { label: 'Business', value: 'business' }\n ]\n },\n {\n key: 'companyName',\n type: 'input',\n label: 'Company Name',\n logic: [\n { type: 'hidden', condition: { type: 'fieldValue', fieldPath: 'accountType', operator: 'notEquals', value: 'business' } },\n { type: 'required', condition: { type: 'fieldValue', fieldPath: 'accountType', operator: 'equals', value: 'business' } }\n ]\n },\n { key: 'acceptTerms', type: 'checkbox', label: 'I accept the terms', required: true },\n {\n key: 'navRow3',\n type: 'row',\n fields: [\n { key: 'back3', type: 'previous', label: 'Back', col: 6 },\n { key: 'submitBtn', type: 'submit', label: 'Submit', col: 6 }\n ]\n }\n ]\n }\n ]\n} as const satisfies FormConfig;\n```\n\n## Form Output Shape\n\n```typescript\n{\n firstName: string;\n lastName: string;\n fullName: string; // Computed via derivation\n email: string;\n address: { // Nested from group\n street: string;\n city: string;\n state: string;\n };\n accountType: 'personal' | 'business';\n companyName?: string; // Only present when accountType is 'business'\n acceptTerms: boolean;\n}\n```";
|
|
25
|
+
/**
|
|
26
|
+
* Mega kitchen sink example (abbreviated - full version exists in get-example.tool.ts).
|
|
27
|
+
*/
|
|
28
|
+
export declare const MEGA_EXAMPLE = "# Kitchen Sink Mega Example\n\nThis example demonstrates **EVERY feature** of ng-forge dynamic forms.\n\n**NOTE:** This is a comprehensive reference. For getting started, use the `complete` pattern instead.\n\n```typescript\nimport { FormConfig } from '@ng-forge/dynamic-forms';\n\nconst megaFormConfig = {\n fields: [\n // ========== PAGE 1: All Field Types ==========\n {\n key: 'fieldTypesPage',\n type: 'page',\n fields: [\n { key: 'pageHeader', type: 'text', label: 'All Field Types Demo', props: { elementType: 'h1' } },\n\n // TEXT INPUTS\n { key: 'textInput', type: 'input', label: 'Text Input', props: { placeholder: 'Type here' } },\n { key: 'emailInput', type: 'input', label: 'Email', email: true, props: { type: 'email' } },\n { key: 'passwordInput', type: 'input', label: 'Password', minLength: 8, props: { type: 'password' } },\n { key: 'numberInput', type: 'input', label: 'Number', min: 0, max: 100, props: { type: 'number' } },\n\n // SELECT & OPTIONS\n {\n key: 'selectField',\n type: 'select',\n label: 'Select (single)',\n options: [\n { label: 'Option A', value: 'a' },\n { label: 'Option B', value: 'b' }\n ]\n },\n {\n key: 'radioField',\n type: 'radio',\n label: 'Radio Group',\n options: [\n { label: 'Yes', value: true },\n { label: 'No', value: false }\n ]\n },\n {\n key: 'multiCheckbox',\n type: 'multi-checkbox',\n label: 'Multi-Checkbox',\n options: [\n { label: 'Red', value: 'red' },\n { label: 'Green', value: 'green' },\n { label: 'Blue', value: 'blue' }\n ]\n },\n\n // BOOLEAN FIELDS\n { key: 'checkboxField', type: 'checkbox', label: 'Single Checkbox' },\n { key: 'toggleField', type: 'toggle', label: 'Toggle Switch' },\n\n // NUMERIC FIELDS\n { key: 'sliderField', type: 'slider', label: 'Slider', minValue: 0, maxValue: 100, step: 5, value: 50 },\n\n // DATE FIELDS\n { key: 'datepickerField', type: 'datepicker', label: 'Date Picker' },\n\n // TEXT AREA\n { key: 'textareaField', type: 'textarea', label: 'Textarea', props: { rows: 4 } },\n\n // HIDDEN\n { key: 'hiddenField', type: 'hidden', value: 'secret-value' },\n\n { key: 'toLogicPage', type: 'next', label: 'Next: Logic Demo' }\n ]\n },\n\n // ========== PAGE 2: Logic Types ==========\n {\n key: 'logicPage',\n type: 'page',\n fields: [\n { key: 'logicHeader', type: 'text', label: 'Logic Types Demo', props: { elementType: 'h1' } },\n\n // DERIVATION\n {\n key: 'sourceA',\n type: 'input',\n label: 'Source A',\n value: '10'\n },\n {\n key: 'sourceB',\n type: 'input',\n label: 'Source B',\n value: '20'\n },\n {\n key: 'derived',\n type: 'input',\n label: 'Derived (A + B)',\n readonly: true,\n // Self-targeting derivation - no targetField needed\n derivation: 'parseInt(formValue.sourceA || 0) + parseInt(formValue.sourceB || 0)'\n },\n\n // CONDITIONAL VISIBILITY\n {\n key: 'showExtra',\n type: 'checkbox',\n label: 'Show extra field'\n },\n {\n key: 'extraField',\n type: 'input',\n label: 'Extra Field',\n logic: [{\n type: 'hidden',\n condition: { type: 'fieldValue', fieldPath: 'showExtra', operator: 'notEquals', value: true }\n }]\n },\n\n // CONDITIONAL REQUIRED\n {\n key: 'makeRequired',\n type: 'checkbox',\n label: 'Make field required'\n },\n {\n key: 'conditionalRequired',\n type: 'input',\n label: 'Conditionally Required',\n logic: [{\n type: 'required',\n condition: { type: 'fieldValue', fieldPath: 'makeRequired', operator: 'equals', value: true }\n }]\n },\n\n {\n key: 'logicNav',\n type: 'row',\n fields: [\n { key: 'backToFields', type: 'previous', label: 'Back', col: 6 },\n { key: 'toContainers', type: 'next', label: 'Next: Containers', col: 6 }\n ]\n }\n ]\n },\n\n // ========== PAGE 3: Containers ==========\n {\n key: 'containersPage',\n type: 'page',\n fields: [\n { key: 'containersHeader', type: 'text', label: 'Containers Demo', props: { elementType: 'h1' } },\n\n // ROW\n {\n key: 'demoRow',\n type: 'row',\n fields: [\n { key: 'col4', type: 'input', label: 'Col 4', col: 4 },\n { key: 'col4b', type: 'input', label: 'Col 4', col: 4 },\n { key: 'col4c', type: 'input', label: 'Col 4', col: 4 }\n ]\n },\n\n // GROUP\n {\n key: 'demoGroup',\n type: 'group',\n fields: [\n { key: 'groupText', type: 'text', label: 'Nested Group:', props: { elementType: 'h3' } },\n { key: 'nestedField1', type: 'input', label: 'Nested Field 1' },\n { key: 'nestedField2', type: 'input', label: 'Nested Field 2' }\n ]\n },\n\n // ARRAY (Simplified API - recommended)\n {\n key: 'itemsHeader', type: 'text', label: 'Dynamic Array:', props: { elementType: 'h3' }\n },\n {\n key: 'demoArray',\n type: 'array',\n template: [\n { key: 'itemName', type: 'input', label: 'Item Name' },\n { key: 'itemQty', type: 'input', label: 'Qty', props: { type: 'number' } }\n ],\n value: [{ itemName: 'Widget', itemQty: '5' }],\n addButton: { label: 'Add Item' }\n },\n\n {\n key: 'containersNav',\n type: 'row',\n fields: [\n { key: 'backToLogic', type: 'previous', label: 'Back', col: 6 },\n { key: 'submitFinal', type: 'submit', label: 'Submit', col: 6 }\n ]\n }\n ]\n }\n ]\n} as const satisfies FormConfig;\n```\n\n## Features Demonstrated\n\n- **All field types:** input, select, radio, checkbox, multi-checkbox, textarea, toggle, slider, datepicker, text, hidden\n- **All container types:** page, row, group, array\n- **All button types:** submit, next, previous, auto-generated add/remove (simplified array)\n- **Logic types:** hidden, required, derivation\n- **Condition types:** fieldValue with operators\n- **Layout:** col property for grid widths";
|
|
11
29
|
export declare function registerExamplesTool(server: McpServer): void;
|
|
12
30
|
//# sourceMappingURL=examples.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"examples.tool.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/tools/examples.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"examples.tool.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/tools/examples.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,MAAM,CAC3B,MAAM,EACN;IACE,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB,CA+qDF,CAAC;AA6JF;;GAEG;AACH,eAAO,MAAM,gBAAgB,4/IA4ItB,CAAC;AAER;;GAEG;AACH,eAAO,MAAM,YAAY,orNAmNkB,CAAC;AAoC5C,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+G5D"}
|
package/src/tools/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Registers all available tools with the MCP server.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* 5 tools with zero overlap, each serving a single clear purpose:
|
|
7
7
|
*
|
|
8
8
|
* | Tool | Purpose | One-liner |
|
|
9
9
|
* |-------------------|----------------|-------------------------|
|
|
@@ -11,12 +11,14 @@
|
|
|
11
11
|
* | ngforge_examples | Working code | "Show me how to do X" |
|
|
12
12
|
* | ngforge_validate | Verification | "Is my config correct?" |
|
|
13
13
|
* | ngforge_scaffold | Generation | "Generate a skeleton" |
|
|
14
|
+
* | ngforge_search | Discovery | "Find topics about X" |
|
|
14
15
|
*
|
|
15
16
|
* RECOMMENDED WORKFLOW:
|
|
16
|
-
* 1. ngforge_lookup topic="workflow" -
|
|
17
|
-
* 2.
|
|
18
|
-
* 3. ngforge_lookup topic="
|
|
19
|
-
* 4.
|
|
17
|
+
* 1. ngforge_lookup topic="workflow" - START HERE: tool usage guide
|
|
18
|
+
* 2. ngforge_search query="your question" - Find relevant topics by keyword
|
|
19
|
+
* 3. ngforge_lookup topic="golden-path" - Get form structure templates
|
|
20
|
+
* 4. ngforge_lookup topic="<field-type>" - Get syntax for specific fields
|
|
21
|
+
* 5. ngforge_validate - Validate your config (catches all errors)
|
|
20
22
|
*
|
|
21
23
|
* For working code examples:
|
|
22
24
|
* - ngforge_examples pattern="complete" - Full multi-page form
|
|
@@ -27,7 +29,7 @@
|
|
|
27
29
|
*/
|
|
28
30
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
29
31
|
/**
|
|
30
|
-
* Register all MCP tools (
|
|
32
|
+
* Register all MCP tools (5 total)
|
|
31
33
|
*/
|
|
32
34
|
export declare function registerTools(server: McpServer): void;
|
|
33
35
|
//# sourceMappingURL=index.d.ts.map
|
package/src/tools/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/tools/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOpE;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAerD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lookup.tool.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/tools/lookup.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"lookup.tool.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/tools/lookup.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAySpE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyF1D"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Search Tool
|
|
3
|
+
*
|
|
4
|
+
* Free-text keyword search across all TOPICS and PATTERNS.
|
|
5
|
+
* Bridges the discoverability gap — find content without knowing exact topic names.
|
|
6
|
+
*/
|
|
7
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
|
+
export declare function registerSearchTool(server: McpServer): void;
|
|
9
|
+
//# sourceMappingURL=search.tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.tool.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/tools/search.tool.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAoKpE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAiD1D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.tool.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/tools/validate.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"validate.tool.d.ts","sourceRoot":"","sources":["../../../../../packages/dynamic-form-mcp/src/tools/validate.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA+UpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2J5D"}
|