@formspec/constraints 0.1.0-alpha.19 → 0.1.0-alpha.21
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/dist/browser.cjs.map +1 -1
- package/dist/browser.js.map +1 -1
- package/dist/constraints.d.ts +82 -0
- package/dist/defaults.d.ts +6 -0
- package/dist/defaults.d.ts.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +10 -0
- package/dist/loader.d.ts.map +1 -1
- package/dist/types.d.ts +32 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/validators/field-options.d.ts +12 -0
- package/dist/validators/field-options.d.ts.map +1 -1
- package/dist/validators/field-types.d.ts +8 -0
- package/dist/validators/field-types.d.ts.map +1 -1
- package/dist/validators/formspec.d.ts +6 -0
- package/dist/validators/formspec.d.ts.map +1 -1
- package/dist/validators/layout.d.ts +8 -0
- package/dist/validators/layout.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/loader.ts","../src/defaults.ts","../src/validators/field-types.ts","../src/validators/layout.ts","../src/validators/field-options.ts","../src/validators/formspec.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { resolve, dirname } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { FormSpecConfig, ConstraintConfig, ResolvedConstraintConfig } from \"./types.js\";\nimport { mergeWithDefaults } from \"./defaults.js\";\n\n/**\n * Default config file names to search for (in order of priority).\n */\nconst CONFIG_FILE_NAMES = [\".formspec.yml\", \".formspec.yaml\", \"formspec.yml\"];\n\n/**\n * Options for loading configuration.\n */\nexport interface LoadConfigOptions {\n /**\n * The directory to search for config files.\n * Defaults to process.cwd().\n */\n cwd?: string;\n\n /**\n * Explicit path to a config file.\n * If provided, skips searching for default config file names.\n */\n configPath?: string;\n\n /**\n * Whether to search parent directories for config files.\n * Defaults to true.\n */\n searchParents?: boolean;\n}\n\n/**\n * Result of loading configuration.\n */\nexport interface LoadConfigResult {\n /** The loaded and merged configuration */\n config: ResolvedConstraintConfig;\n /** The path to the config file that was loaded (if any) */\n configPath: string | null;\n /** Whether a config file was found */\n found: boolean;\n}\n\n/**\n * Searches for a config file in the given directory and optionally parent directories.\n */\nasync function findConfigFile(startDir: string, searchParents: boolean): Promise<string | null> {\n let currentDir = resolve(startDir);\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- intentional infinite loop with break conditions\n while (true) {\n for (const fileName of CONFIG_FILE_NAMES) {\n const filePath = resolve(currentDir, fileName);\n try {\n await readFile(filePath);\n return filePath;\n } catch {\n // File doesn't exist, continue searching\n }\n }\n\n if (!searchParents) {\n break;\n }\n\n const parentDir = dirname(currentDir);\n // Reached filesystem root when dirname returns same path\n if (parentDir === currentDir) {\n break;\n }\n currentDir = parentDir;\n }\n\n return null;\n}\n\n/**\n * Parses a YAML config file and returns the FormSpecConfig.\n */\nasync function parseConfigFile(filePath: string): Promise<FormSpecConfig> {\n const content = await readFile(filePath, \"utf-8\");\n const parsed = parseYaml(content) as unknown;\n\n if (parsed === null || parsed === undefined) {\n return {};\n }\n\n if (typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(`Invalid config file at ${filePath}: expected an object, got ${typeof parsed}`);\n }\n\n return parsed as FormSpecConfig;\n}\n\n/**\n * Loads FormSpec constraint configuration from a .formspec.yml file.\n *\n * @param options - Options for loading configuration\n * @returns The loaded configuration with defaults applied\n *\n * @example\n * ```ts\n * // Load from current directory (searches for .formspec.yml)\n * const result = await loadConfig();\n *\n * // Load from specific directory\n * const result = await loadConfig({ cwd: '/path/to/project' });\n *\n * // Load from specific file\n * const result = await loadConfig({ configPath: '/path/to/config.yml' });\n * ```\n */\nexport async function loadConfig(options: LoadConfigOptions = {}): Promise<LoadConfigResult> {\n const { cwd = process.cwd(), configPath, searchParents = true } = options;\n\n let resolvedPath: string | null = null;\n\n if (configPath) {\n resolvedPath = resolve(cwd, configPath);\n try {\n await readFile(resolvedPath);\n } catch {\n throw new Error(`Config file not found at ${resolvedPath}`);\n }\n } else {\n resolvedPath = await findConfigFile(cwd, searchParents);\n }\n\n if (!resolvedPath) {\n return {\n config: mergeWithDefaults(undefined),\n configPath: null,\n found: false,\n };\n }\n\n const fileConfig = await parseConfigFile(resolvedPath);\n const config = mergeWithDefaults(fileConfig.constraints);\n\n return {\n config,\n configPath: resolvedPath,\n found: true,\n };\n}\n\n/**\n * Synchronously loads config from a pre-parsed YAML string.\n * Useful for testing or when config is already available.\n *\n * @param yamlContent - The YAML content to parse\n * @returns The parsed and merged configuration\n */\nexport function loadConfigFromString(yamlContent: string): ResolvedConstraintConfig {\n const parsed = parseYaml(yamlContent) as FormSpecConfig | null | undefined;\n\n if (parsed === null || parsed === undefined) {\n return mergeWithDefaults(undefined);\n }\n\n if (typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(`Invalid config content: expected an object, got ${typeof parsed}`);\n }\n\n return mergeWithDefaults(parsed.constraints);\n}\n\n/**\n * Creates a constraint configuration directly from an object.\n * Useful for programmatic configuration without YAML.\n *\n * @param config - Partial constraint configuration\n * @returns Complete configuration with defaults applied\n *\n * @example\n * ```ts\n * const config = defineConstraints({\n * fieldTypes: {\n * dynamicEnum: 'error',\n * dynamicSchema: 'error',\n * },\n * layout: {\n * group: 'error',\n * },\n * });\n * ```\n */\nexport function defineConstraints(config: ConstraintConfig): ResolvedConstraintConfig {\n return mergeWithDefaults(config);\n}\n","import type { ConstraintConfig, FormSpecConfig, ResolvedConstraintConfig } from \"./types.js\";\n\n/**\n * Default constraint configuration that allows all features.\n * All constraints default to \"off\" (allowed).\n */\nexport const DEFAULT_CONSTRAINTS: ResolvedConstraintConfig = {\n fieldTypes: {\n text: \"off\",\n number: \"off\",\n boolean: \"off\",\n staticEnum: \"off\",\n dynamicEnum: \"off\",\n dynamicSchema: \"off\",\n array: \"off\",\n object: \"off\",\n },\n layout: {\n group: \"off\",\n conditionals: \"off\",\n maxNestingDepth: Infinity,\n },\n uiSchema: {\n layouts: {\n VerticalLayout: \"off\",\n HorizontalLayout: \"off\",\n Group: \"off\",\n Categorization: \"off\",\n Category: \"off\",\n },\n rules: {\n enabled: \"off\",\n effects: {\n SHOW: \"off\",\n HIDE: \"off\",\n ENABLE: \"off\",\n DISABLE: \"off\",\n },\n },\n },\n fieldOptions: {\n label: \"off\",\n placeholder: \"off\",\n required: \"off\",\n minValue: \"off\",\n maxValue: \"off\",\n minItems: \"off\",\n maxItems: \"off\",\n },\n controlOptions: {\n format: \"off\",\n readonly: \"off\",\n multi: \"off\",\n showUnfocusedDescription: \"off\",\n hideRequiredAsterisk: \"off\",\n custom: {},\n },\n};\n\n/**\n * Default FormSpec configuration.\n */\nexport const DEFAULT_CONFIG: FormSpecConfig = {\n constraints: DEFAULT_CONSTRAINTS,\n};\n\n/**\n * Merges user constraints with defaults, filling in any missing values.\n */\nexport function mergeWithDefaults(config: ConstraintConfig | undefined): ResolvedConstraintConfig {\n if (!config) {\n return DEFAULT_CONSTRAINTS;\n }\n\n return {\n fieldTypes: {\n ...DEFAULT_CONSTRAINTS.fieldTypes,\n ...config.fieldTypes,\n },\n layout: {\n ...DEFAULT_CONSTRAINTS.layout,\n ...config.layout,\n },\n uiSchema: {\n layouts: {\n ...DEFAULT_CONSTRAINTS.uiSchema.layouts,\n ...config.uiSchema?.layouts,\n },\n rules: {\n enabled: config.uiSchema?.rules?.enabled ?? DEFAULT_CONSTRAINTS.uiSchema.rules.enabled,\n effects: {\n ...DEFAULT_CONSTRAINTS.uiSchema.rules.effects,\n ...config.uiSchema?.rules?.effects,\n },\n },\n },\n fieldOptions: {\n ...DEFAULT_CONSTRAINTS.fieldOptions,\n ...config.fieldOptions,\n },\n controlOptions: {\n ...DEFAULT_CONSTRAINTS.controlOptions,\n ...config.controlOptions,\n custom: {\n ...DEFAULT_CONSTRAINTS.controlOptions.custom,\n ...config.controlOptions?.custom,\n },\n },\n };\n}\n","import type { FieldTypeConstraints, Severity, ValidationIssue } from \"../types.js\";\n\n/**\n * Maps FormSpec field._field values to constraint config keys.\n */\nconst FIELD_TYPE_MAP: Record<string, keyof FieldTypeConstraints> = {\n text: \"text\",\n number: \"number\",\n boolean: \"boolean\",\n enum: \"staticEnum\",\n dynamic_enum: \"dynamicEnum\",\n dynamic_schema: \"dynamicSchema\",\n array: \"array\",\n object: \"object\",\n};\n\n/**\n * Human-readable names for field types.\n */\nconst FIELD_TYPE_NAMES: Record<string, string> = {\n text: \"text field\",\n number: \"number field\",\n boolean: \"boolean field\",\n enum: \"static enum field\",\n dynamic_enum: \"dynamic enum field\",\n dynamic_schema: \"dynamic schema field\",\n array: \"array field\",\n object: \"object field\",\n};\n\n/**\n * Context for field type validation.\n */\nexport interface FieldTypeContext {\n /** The _field discriminator value (e.g., \"text\", \"number\", \"enum\") */\n fieldType: string;\n /** The field name */\n fieldName: string;\n /** Optional path for nested fields */\n path?: string;\n}\n\n/**\n * Validates a field type against constraints.\n *\n * @param context - Information about the field being validated\n * @param constraints - Field type constraints\n * @returns Array of validation issues (empty if valid)\n */\nexport function validateFieldTypes(\n context: FieldTypeContext,\n constraints: FieldTypeConstraints\n): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n const constraintKey = FIELD_TYPE_MAP[context.fieldType];\n if (!constraintKey) {\n // Unknown field type, skip validation\n return issues;\n }\n\n const severity = constraints[constraintKey];\n if (severity && severity !== \"off\") {\n const fieldTypeName = FIELD_TYPE_NAMES[context.fieldType] ?? context.fieldType;\n issues.push(createFieldTypeIssue(context, fieldTypeName, severity));\n }\n\n return issues;\n}\n\n/**\n * Creates a validation issue for a disallowed field type.\n */\nfunction createFieldTypeIssue(\n context: FieldTypeContext,\n fieldTypeName: string,\n severity: Severity\n): ValidationIssue {\n const path = context.path ?? context.fieldName;\n return {\n code: \"DISALLOWED_FIELD_TYPE\",\n message: `Field \"${context.fieldName}\" uses ${fieldTypeName}, which is not allowed in this project`,\n severity: severity === \"error\" ? \"error\" : \"warning\",\n category: \"fieldTypes\",\n path,\n fieldName: context.fieldName,\n fieldType: context.fieldType,\n };\n}\n\n/**\n * Checks if a field type is allowed by the constraints.\n * Useful for quick checks without generating issues.\n *\n * @param fieldType - The _field discriminator value\n * @param constraints - Field type constraints\n * @returns true if allowed, false if disallowed\n */\nexport function isFieldTypeAllowed(fieldType: string, constraints: FieldTypeConstraints): boolean {\n const constraintKey = FIELD_TYPE_MAP[fieldType];\n if (!constraintKey) {\n return true; // Unknown types are allowed by default\n }\n\n const severity = constraints[constraintKey];\n return !severity || severity === \"off\";\n}\n\n/**\n * Gets the severity level for a field type.\n *\n * @param fieldType - The _field discriminator value\n * @param constraints - Field type constraints\n * @returns Severity level, or \"off\" if not constrained\n */\nexport function getFieldTypeSeverity(\n fieldType: string,\n constraints: FieldTypeConstraints\n): Severity {\n const constraintKey = FIELD_TYPE_MAP[fieldType];\n if (!constraintKey) {\n return \"off\";\n }\n\n return constraints[constraintKey] ?? \"off\";\n}\n","import type { LayoutConstraints, Severity, ValidationIssue } from \"../types.js\";\n\n/**\n * Context for layout validation.\n */\nexport interface LayoutContext {\n /** The type of layout element (\"group\" | \"conditional\") */\n layoutType: \"group\" | \"conditional\";\n /** Optional label for the element (for groups) */\n label?: string;\n /** Current nesting depth */\n depth: number;\n /** Path to this element */\n path?: string;\n}\n\n/**\n * Validates a layout element against constraints.\n *\n * @param context - Information about the layout element\n * @param constraints - Layout constraints\n * @returns Array of validation issues (empty if valid)\n */\nexport function validateLayout(\n context: LayoutContext,\n constraints: LayoutConstraints\n): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n // Check if groups are allowed\n if (context.layoutType === \"group\") {\n const groupSeverity = constraints.group;\n if (groupSeverity && groupSeverity !== \"off\") {\n issues.push(createGroupIssue(context, groupSeverity));\n }\n }\n\n // Check if conditionals are allowed\n if (context.layoutType === \"conditional\") {\n const conditionalSeverity = constraints.conditionals;\n if (conditionalSeverity && conditionalSeverity !== \"off\") {\n issues.push(createConditionalIssue(context, conditionalSeverity));\n }\n }\n\n // Check nesting depth (applies to both groups and fields within nested structures)\n const maxDepth = constraints.maxNestingDepth;\n if (maxDepth !== undefined && context.depth > maxDepth) {\n issues.push(createNestingDepthIssue(context, maxDepth));\n }\n\n return issues;\n}\n\n/**\n * Creates a validation issue for a disallowed group.\n */\nfunction createGroupIssue(context: LayoutContext, severity: Severity): ValidationIssue {\n const labelInfo = context.label ? ` \"${context.label}\"` : \"\";\n const issue: ValidationIssue = {\n code: \"DISALLOWED_GROUP\",\n message: `Group${labelInfo} is not allowed - visual grouping is not supported in this project`,\n severity: severity === \"error\" ? \"error\" : \"warning\",\n category: \"layout\",\n };\n if (context.path !== undefined) {\n issue.path = context.path;\n }\n return issue;\n}\n\n/**\n * Creates a validation issue for a disallowed conditional.\n */\nfunction createConditionalIssue(context: LayoutContext, severity: Severity): ValidationIssue {\n const issue: ValidationIssue = {\n code: \"DISALLOWED_CONDITIONAL\",\n message: `Conditional visibility (when/is) is not allowed in this project`,\n severity: severity === \"error\" ? \"error\" : \"warning\",\n category: \"layout\",\n };\n if (context.path !== undefined) {\n issue.path = context.path;\n }\n return issue;\n}\n\n/**\n * Creates a validation issue for exceeding nesting depth.\n */\nfunction createNestingDepthIssue(context: LayoutContext, maxDepth: number): ValidationIssue {\n const issue: ValidationIssue = {\n code: \"EXCEEDED_NESTING_DEPTH\",\n message: `Nesting depth ${String(context.depth)} exceeds maximum allowed depth of ${String(maxDepth)}`,\n severity: \"error\",\n category: \"layout\",\n };\n if (context.path !== undefined) {\n issue.path = context.path;\n }\n return issue;\n}\n\n/**\n * Checks if a layout type is allowed by the constraints.\n *\n * @param layoutType - The type of layout element\n * @param constraints - Layout constraints\n * @returns true if allowed, false if disallowed\n */\nexport function isLayoutTypeAllowed(\n layoutType: \"group\" | \"conditional\",\n constraints: LayoutConstraints\n): boolean {\n if (layoutType === \"group\") {\n const severity = constraints.group;\n return !severity || severity === \"off\";\n }\n\n // layoutType === \"conditional\"\n const severity = constraints.conditionals;\n return !severity || severity === \"off\";\n}\n\n/**\n * Checks if a nesting depth is allowed.\n *\n * @param depth - Current nesting depth\n * @param constraints - Layout constraints\n * @returns true if allowed, false if exceeds limit\n */\nexport function isNestingDepthAllowed(depth: number, constraints: LayoutConstraints): boolean {\n const maxDepth = constraints.maxNestingDepth;\n if (maxDepth === undefined) {\n return true;\n }\n return depth <= maxDepth;\n}\n","import type { FieldOptionConstraints, Severity, ValidationIssue } from \"../types.js\";\n\n/**\n * Known field options that can be validated.\n */\nexport type FieldOption =\n | \"label\"\n | \"placeholder\"\n | \"required\"\n | \"minValue\"\n | \"maxValue\"\n | \"minItems\"\n | \"maxItems\";\n\n/**\n * Context for field option validation.\n */\nexport interface FieldOptionsContext {\n /** The field name */\n fieldName: string;\n /** Which options are present on this field */\n presentOptions: FieldOption[];\n /** Path to this field */\n path?: string;\n}\n\n/**\n * Validates field options against constraints.\n *\n * @param context - Information about the field and its options\n * @param constraints - Field option constraints\n * @returns Array of validation issues (empty if valid)\n */\nexport function validateFieldOptions(\n context: FieldOptionsContext,\n constraints: FieldOptionConstraints\n): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n for (const option of context.presentOptions) {\n const severity = constraints[option];\n if (severity && severity !== \"off\") {\n issues.push(createFieldOptionIssue(context, option, severity));\n }\n }\n\n return issues;\n}\n\n/**\n * Creates a validation issue for a disallowed field option.\n */\nfunction createFieldOptionIssue(\n context: FieldOptionsContext,\n option: FieldOption,\n severity: Severity\n): ValidationIssue {\n const path = context.path ?? context.fieldName;\n return {\n code: \"DISALLOWED_FIELD_OPTION\",\n message: `Field \"${context.fieldName}\" uses the \"${option}\" option, which is not allowed in this project`,\n severity: severity === \"error\" ? \"error\" : \"warning\",\n category: \"fieldOptions\",\n path,\n fieldName: context.fieldName,\n };\n}\n\n/**\n * Extracts which options are present on a field object.\n * Works with FormSpec field types.\n *\n * @param field - A field object with potential options\n * @returns Array of present option names\n */\nexport function extractFieldOptions(field: Record<string, unknown>): FieldOption[] {\n const options: FieldOption[] = [];\n\n if (field[\"label\"] !== undefined) options.push(\"label\");\n if (field[\"placeholder\"] !== undefined) options.push(\"placeholder\");\n if (field[\"required\"] !== undefined) options.push(\"required\");\n // NumberField uses \"min\"/\"max\" in core types, map to \"minValue\"/\"maxValue\" constraints\n if (field[\"min\"] !== undefined || field[\"minValue\"] !== undefined) options.push(\"minValue\");\n if (field[\"max\"] !== undefined || field[\"maxValue\"] !== undefined) options.push(\"maxValue\");\n if (field[\"minItems\"] !== undefined) options.push(\"minItems\");\n if (field[\"maxItems\"] !== undefined) options.push(\"maxItems\");\n\n return options;\n}\n\n/**\n * Checks if a specific field option is allowed.\n *\n * @param option - The option to check\n * @param constraints - Field option constraints\n * @returns true if allowed, false if disallowed\n */\nexport function isFieldOptionAllowed(\n option: FieldOption,\n constraints: FieldOptionConstraints\n): boolean {\n const severity = constraints[option];\n return !severity || severity === \"off\";\n}\n\n/**\n * Gets the severity level for a field option.\n *\n * @param option - The option to check\n * @param constraints - Field option constraints\n * @returns Severity level, or \"off\" if not constrained\n */\nexport function getFieldOptionSeverity(\n option: FieldOption,\n constraints: FieldOptionConstraints\n): Severity {\n return constraints[option] ?? \"off\";\n}\n","import type { FormElement, FormSpec, AnyField } from \"@formspec/core\";\nimport type {\n ConstraintConfig,\n ResolvedConstraintConfig,\n ValidationIssue,\n ValidationResult,\n} from \"../types.js\";\nimport { mergeWithDefaults } from \"../defaults.js\";\nimport { validateFieldTypes } from \"./field-types.js\";\nimport { validateLayout } from \"./layout.js\";\nimport { validateFieldOptions, extractFieldOptions } from \"./field-options.js\";\n\n/**\n * Options for validating FormSpec elements.\n */\nexport interface FormSpecValidationOptions {\n /** Constraint configuration (will be merged with defaults) */\n constraints?: ConstraintConfig;\n}\n\n/**\n * Validates FormSpec elements against constraints.\n *\n * This is the main entry point for validating a form specification\n * against a constraint configuration. It walks through all elements\n * and checks each one against the configured constraints.\n *\n * @param elements - FormSpec elements to validate\n * @param options - Validation options including constraints\n * @returns Validation result with all issues found\n *\n * @example\n * ```ts\n * import { formspec, field, group } from '@formspec/dsl';\n * import { validateFormSpecElements, defineConstraints } from '@formspec/constraints';\n *\n * const form = formspec(\n * group(\"Contact\",\n * field.text(\"name\"),\n * field.dynamicEnum(\"country\", \"countries\"),\n * ),\n * );\n *\n * const result = validateFormSpecElements(form.elements, {\n * constraints: {\n * fieldTypes: { dynamicEnum: 'error' },\n * layout: { group: 'error' },\n * },\n * });\n *\n * if (!result.valid) {\n * console.error('Validation failed:', result.issues);\n * }\n * ```\n */\nexport function validateFormSpecElements(\n elements: readonly FormElement[],\n options: FormSpecValidationOptions = {}\n): ValidationResult {\n const constraints = mergeWithDefaults(options.constraints);\n const issues: ValidationIssue[] = [];\n\n // Walk through all elements\n walkElements(elements, constraints, issues, \"\", 0);\n\n return {\n valid: !issues.some((issue) => issue.severity === \"error\"),\n issues,\n };\n}\n\n/**\n * Validates a complete FormSpec against constraints.\n *\n * @param formSpec - The FormSpec to validate\n * @param options - Validation options including constraints\n * @returns Validation result with all issues found\n */\nexport function validateFormSpec(\n formSpec: FormSpec<readonly FormElement[]>,\n options: FormSpecValidationOptions = {}\n): ValidationResult {\n return validateFormSpecElements(formSpec.elements, options);\n}\n\n/**\n * Recursively walks through FormSpec elements and validates each one.\n */\nfunction walkElements(\n elements: readonly FormElement[],\n constraints: ResolvedConstraintConfig,\n issues: ValidationIssue[],\n pathPrefix: string,\n depth: number\n): void {\n for (const element of elements) {\n const elementPath = pathPrefix;\n\n if (element._type === \"field\") {\n validateField(element, constraints, issues, elementPath, depth);\n } else if (element._type === \"group\") {\n validateGroup(element, constraints, issues, elementPath, depth);\n } else {\n // element._type === \"conditional\"\n validateConditional(element, constraints, issues, elementPath, depth);\n }\n }\n}\n\n/**\n * Validates a field element.\n */\nfunction validateField(\n field: AnyField,\n constraints: ResolvedConstraintConfig,\n issues: ValidationIssue[],\n pathPrefix: string,\n depth: number\n): void {\n const fieldPath = pathPrefix ? `${pathPrefix}/${field.name}` : field.name;\n\n // Validate field type\n const fieldTypeIssues = validateFieldTypes(\n {\n fieldType: field._field,\n fieldName: field.name,\n path: fieldPath,\n },\n constraints.fieldTypes\n );\n issues.push(...fieldTypeIssues);\n\n // Validate field options\n const presentOptions = extractFieldOptions(field as unknown as Record<string, unknown>);\n if (presentOptions.length > 0) {\n const optionIssues = validateFieldOptions(\n {\n fieldName: field.name,\n presentOptions,\n path: fieldPath,\n },\n constraints.fieldOptions\n );\n issues.push(...optionIssues);\n }\n\n // Check nesting depth for array/object fields\n if (field._field === \"array\" || field._field === \"object\") {\n const layoutIssues = validateLayout(\n {\n layoutType: \"group\", // Arrays/objects contribute to nesting depth\n depth: depth + 1,\n path: fieldPath,\n },\n constraints.layout\n );\n // Only add nesting depth issues, not group issues\n issues.push(...layoutIssues.filter((issue) => issue.code === \"EXCEEDED_NESTING_DEPTH\"));\n\n // Recursively validate nested elements\n if (field._field === \"array\" && \"items\" in field) {\n walkElements(\n field.items as readonly FormElement[],\n constraints,\n issues,\n `${fieldPath}[]`,\n depth + 1\n );\n } else if (\"properties\" in field) {\n // field._field === \"object\"\n walkElements(\n field.properties as readonly FormElement[],\n constraints,\n issues,\n fieldPath,\n depth + 1\n );\n }\n }\n}\n\n/**\n * Validates a group element.\n */\nfunction validateGroup(\n group: {\n readonly _type: \"group\";\n readonly label: string;\n readonly elements: readonly FormElement[];\n },\n constraints: ResolvedConstraintConfig,\n issues: ValidationIssue[],\n pathPrefix: string,\n depth: number\n): void {\n const groupPath = pathPrefix ? `${pathPrefix}/[group:${group.label}]` : `[group:${group.label}]`;\n\n // Validate group usage\n const layoutIssues = validateLayout(\n {\n layoutType: \"group\",\n label: group.label,\n depth,\n path: groupPath,\n },\n constraints.layout\n );\n issues.push(...layoutIssues);\n\n // Recursively validate nested elements (groups don't increase nesting depth for schema)\n walkElements(group.elements, constraints, issues, pathPrefix, depth);\n}\n\n/**\n * Validates a conditional element.\n */\nfunction validateConditional(\n conditional: {\n readonly _type: \"conditional\";\n readonly field: string;\n readonly value: unknown;\n readonly elements: readonly FormElement[];\n },\n constraints: ResolvedConstraintConfig,\n issues: ValidationIssue[],\n pathPrefix: string,\n depth: number\n): void {\n const condPath = pathPrefix\n ? `${pathPrefix}/[when:${conditional.field}=${String(conditional.value)}]`\n : `[when:${conditional.field}=${String(conditional.value)}]`;\n\n // Validate conditional usage\n const layoutIssues = validateLayout(\n {\n layoutType: \"conditional\",\n depth,\n path: condPath,\n },\n constraints.layout\n );\n issues.push(...layoutIssues);\n\n // Recursively validate nested elements\n walkElements(conditional.elements, constraints, issues, pathPrefix, depth);\n}\n"],"mappings":"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","names":["severity"]}
|
|
1
|
+
{"version":3,"sources":["../src/loader.ts","../src/defaults.ts","../src/validators/field-types.ts","../src/validators/layout.ts","../src/validators/field-options.ts","../src/validators/formspec.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { resolve, dirname } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { FormSpecConfig, ConstraintConfig, ResolvedConstraintConfig } from \"./types.js\";\nimport { mergeWithDefaults } from \"./defaults.js\";\n\n/**\n * Default config file names to search for (in order of priority).\n */\nconst CONFIG_FILE_NAMES = [\".formspec.yml\", \".formspec.yaml\", \"formspec.yml\"];\n\n/**\n * Options for loading configuration.\n *\n * @public\n */\nexport interface LoadConfigOptions {\n /**\n * The directory to search for config files.\n * Defaults to process.cwd().\n */\n cwd?: string;\n\n /**\n * Explicit path to a config file.\n * If provided, skips searching for default config file names.\n */\n configPath?: string;\n\n /**\n * Whether to search parent directories for config files.\n * Defaults to true.\n */\n searchParents?: boolean;\n}\n\n/**\n * Result of loading configuration.\n *\n * @public\n */\nexport interface LoadConfigResult {\n /** The loaded and merged configuration */\n config: ResolvedConstraintConfig;\n /** The path to the config file that was loaded (if any) */\n configPath: string | null;\n /** Whether a config file was found */\n found: boolean;\n}\n\n/**\n * Searches for a config file in the given directory and optionally parent directories.\n */\nasync function findConfigFile(startDir: string, searchParents: boolean): Promise<string | null> {\n let currentDir = resolve(startDir);\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- intentional infinite loop with break conditions\n while (true) {\n for (const fileName of CONFIG_FILE_NAMES) {\n const filePath = resolve(currentDir, fileName);\n try {\n await readFile(filePath);\n return filePath;\n } catch {\n // File doesn't exist, continue searching\n }\n }\n\n if (!searchParents) {\n break;\n }\n\n const parentDir = dirname(currentDir);\n // Reached filesystem root when dirname returns same path\n if (parentDir === currentDir) {\n break;\n }\n currentDir = parentDir;\n }\n\n return null;\n}\n\n/**\n * Parses a YAML config file and returns the FormSpecConfig.\n */\nasync function parseConfigFile(filePath: string): Promise<FormSpecConfig> {\n const content = await readFile(filePath, \"utf-8\");\n const parsed = parseYaml(content) as unknown;\n\n if (parsed === null || parsed === undefined) {\n return {};\n }\n\n if (typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(`Invalid config file at ${filePath}: expected an object, got ${typeof parsed}`);\n }\n\n return parsed as FormSpecConfig;\n}\n\n/**\n * Loads FormSpec constraint configuration from a .formspec.yml file.\n *\n * @param options - Options for loading configuration\n * @returns The loaded configuration with defaults applied\n *\n * @example\n * ```ts\n * // Load from current directory (searches for .formspec.yml)\n * const result = await loadConfig();\n *\n * // Load from specific directory\n * const result = await loadConfig({ cwd: '/path/to/project' });\n *\n * // Load from specific file\n * const result = await loadConfig({ configPath: '/path/to/config.yml' });\n * ```\n *\n * @public\n */\nexport async function loadConfig(options: LoadConfigOptions = {}): Promise<LoadConfigResult> {\n const { cwd = process.cwd(), configPath, searchParents = true } = options;\n\n let resolvedPath: string | null = null;\n\n if (configPath) {\n resolvedPath = resolve(cwd, configPath);\n try {\n await readFile(resolvedPath);\n } catch {\n throw new Error(`Config file not found at ${resolvedPath}`);\n }\n } else {\n resolvedPath = await findConfigFile(cwd, searchParents);\n }\n\n if (!resolvedPath) {\n return {\n config: mergeWithDefaults(undefined),\n configPath: null,\n found: false,\n };\n }\n\n const fileConfig = await parseConfigFile(resolvedPath);\n const config = mergeWithDefaults(fileConfig.constraints);\n\n return {\n config,\n configPath: resolvedPath,\n found: true,\n };\n}\n\n/**\n * Synchronously loads config from a pre-parsed YAML string.\n * Useful for testing or when config is already available.\n *\n * @param yamlContent - The YAML content to parse\n * @returns The parsed and merged configuration\n *\n * @public\n */\nexport function loadConfigFromString(yamlContent: string): ResolvedConstraintConfig {\n const parsed = parseYaml(yamlContent) as FormSpecConfig | null | undefined;\n\n if (parsed === null || parsed === undefined) {\n return mergeWithDefaults(undefined);\n }\n\n if (typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(`Invalid config content: expected an object, got ${typeof parsed}`);\n }\n\n return mergeWithDefaults(parsed.constraints);\n}\n\n/**\n * Creates a constraint configuration directly from an object.\n * Useful for programmatic configuration without YAML.\n *\n * @param config - Partial constraint configuration\n * @returns Complete configuration with defaults applied\n *\n * @example\n * ```ts\n * const config = defineConstraints({\n * fieldTypes: {\n * dynamicEnum: 'error',\n * dynamicSchema: 'error',\n * },\n * layout: {\n * group: 'error',\n * },\n * });\n * ```\n *\n * @public\n */\nexport function defineConstraints(config: ConstraintConfig): ResolvedConstraintConfig {\n return mergeWithDefaults(config);\n}\n","import type { ConstraintConfig, FormSpecConfig, ResolvedConstraintConfig } from \"./types.js\";\n\n/**\n * Default constraint configuration that allows all features.\n * All constraints default to \"off\" (allowed).\n *\n * @public\n */\nexport const DEFAULT_CONSTRAINTS: ResolvedConstraintConfig = {\n fieldTypes: {\n text: \"off\",\n number: \"off\",\n boolean: \"off\",\n staticEnum: \"off\",\n dynamicEnum: \"off\",\n dynamicSchema: \"off\",\n array: \"off\",\n object: \"off\",\n },\n layout: {\n group: \"off\",\n conditionals: \"off\",\n maxNestingDepth: Infinity,\n },\n uiSchema: {\n layouts: {\n VerticalLayout: \"off\",\n HorizontalLayout: \"off\",\n Group: \"off\",\n Categorization: \"off\",\n Category: \"off\",\n },\n rules: {\n enabled: \"off\",\n effects: {\n SHOW: \"off\",\n HIDE: \"off\",\n ENABLE: \"off\",\n DISABLE: \"off\",\n },\n },\n },\n fieldOptions: {\n label: \"off\",\n placeholder: \"off\",\n required: \"off\",\n minValue: \"off\",\n maxValue: \"off\",\n minItems: \"off\",\n maxItems: \"off\",\n },\n controlOptions: {\n format: \"off\",\n readonly: \"off\",\n multi: \"off\",\n showUnfocusedDescription: \"off\",\n hideRequiredAsterisk: \"off\",\n custom: {},\n },\n};\n\n/**\n * Default FormSpec configuration.\n *\n * @public\n */\nexport const DEFAULT_CONFIG: FormSpecConfig = {\n constraints: DEFAULT_CONSTRAINTS,\n};\n\n/**\n * Merges user constraints with defaults, filling in any missing values.\n *\n * @public\n */\nexport function mergeWithDefaults(config: ConstraintConfig | undefined): ResolvedConstraintConfig {\n if (!config) {\n return DEFAULT_CONSTRAINTS;\n }\n\n return {\n fieldTypes: {\n ...DEFAULT_CONSTRAINTS.fieldTypes,\n ...config.fieldTypes,\n },\n layout: {\n ...DEFAULT_CONSTRAINTS.layout,\n ...config.layout,\n },\n uiSchema: {\n layouts: {\n ...DEFAULT_CONSTRAINTS.uiSchema.layouts,\n ...config.uiSchema?.layouts,\n },\n rules: {\n enabled: config.uiSchema?.rules?.enabled ?? DEFAULT_CONSTRAINTS.uiSchema.rules.enabled,\n effects: {\n ...DEFAULT_CONSTRAINTS.uiSchema.rules.effects,\n ...config.uiSchema?.rules?.effects,\n },\n },\n },\n fieldOptions: {\n ...DEFAULT_CONSTRAINTS.fieldOptions,\n ...config.fieldOptions,\n },\n controlOptions: {\n ...DEFAULT_CONSTRAINTS.controlOptions,\n ...config.controlOptions,\n custom: {\n ...DEFAULT_CONSTRAINTS.controlOptions.custom,\n ...config.controlOptions?.custom,\n },\n },\n };\n}\n","import type { FieldTypeConstraints, Severity, ValidationIssue } from \"../types.js\";\n\n/**\n * Maps FormSpec field._field values to constraint config keys.\n */\nconst FIELD_TYPE_MAP: Record<string, keyof FieldTypeConstraints> = {\n text: \"text\",\n number: \"number\",\n boolean: \"boolean\",\n enum: \"staticEnum\",\n dynamic_enum: \"dynamicEnum\",\n dynamic_schema: \"dynamicSchema\",\n array: \"array\",\n object: \"object\",\n};\n\n/**\n * Human-readable names for field types.\n */\nconst FIELD_TYPE_NAMES: Record<string, string> = {\n text: \"text field\",\n number: \"number field\",\n boolean: \"boolean field\",\n enum: \"static enum field\",\n dynamic_enum: \"dynamic enum field\",\n dynamic_schema: \"dynamic schema field\",\n array: \"array field\",\n object: \"object field\",\n};\n\n/**\n * Context for field type validation.\n *\n * @public\n */\nexport interface FieldTypeContext {\n /** The _field discriminator value (e.g., \"text\", \"number\", \"enum\") */\n fieldType: string;\n /** The field name */\n fieldName: string;\n /** Optional path for nested fields */\n path?: string;\n}\n\n/**\n * Validates a field type against constraints.\n *\n * @param context - Information about the field being validated\n * @param constraints - Field type constraints\n * @returns Array of validation issues (empty if valid)\n *\n * @public\n */\nexport function validateFieldTypes(\n context: FieldTypeContext,\n constraints: FieldTypeConstraints\n): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n const constraintKey = FIELD_TYPE_MAP[context.fieldType];\n if (!constraintKey) {\n // Unknown field type, skip validation\n return issues;\n }\n\n const severity = constraints[constraintKey];\n if (severity && severity !== \"off\") {\n const fieldTypeName = FIELD_TYPE_NAMES[context.fieldType] ?? context.fieldType;\n issues.push(createFieldTypeIssue(context, fieldTypeName, severity));\n }\n\n return issues;\n}\n\n/**\n * Creates a validation issue for a disallowed field type.\n */\nfunction createFieldTypeIssue(\n context: FieldTypeContext,\n fieldTypeName: string,\n severity: Severity\n): ValidationIssue {\n const path = context.path ?? context.fieldName;\n return {\n code: \"DISALLOWED_FIELD_TYPE\",\n message: `Field \"${context.fieldName}\" uses ${fieldTypeName}, which is not allowed in this project`,\n severity: severity === \"error\" ? \"error\" : \"warning\",\n category: \"fieldTypes\",\n path,\n fieldName: context.fieldName,\n fieldType: context.fieldType,\n };\n}\n\n/**\n * Checks if a field type is allowed by the constraints.\n * Useful for quick checks without generating issues.\n *\n * @param fieldType - The _field discriminator value\n * @param constraints - Field type constraints\n * @returns true if allowed, false if disallowed\n *\n * @public\n */\nexport function isFieldTypeAllowed(fieldType: string, constraints: FieldTypeConstraints): boolean {\n const constraintKey = FIELD_TYPE_MAP[fieldType];\n if (!constraintKey) {\n return true; // Unknown types are allowed by default\n }\n\n const severity = constraints[constraintKey];\n return !severity || severity === \"off\";\n}\n\n/**\n * Gets the severity level for a field type.\n *\n * @param fieldType - The _field discriminator value\n * @param constraints - Field type constraints\n * @returns Severity level, or \"off\" if not constrained\n *\n * @public\n */\nexport function getFieldTypeSeverity(\n fieldType: string,\n constraints: FieldTypeConstraints\n): Severity {\n const constraintKey = FIELD_TYPE_MAP[fieldType];\n if (!constraintKey) {\n return \"off\";\n }\n\n return constraints[constraintKey] ?? \"off\";\n}\n","import type { LayoutConstraints, Severity, ValidationIssue } from \"../types.js\";\n\n/**\n * Context for layout validation.\n *\n * @public\n */\nexport interface LayoutContext {\n /** The type of layout element (\"group\" | \"conditional\") */\n layoutType: \"group\" | \"conditional\";\n /** Optional label for the element (for groups) */\n label?: string;\n /** Current nesting depth */\n depth: number;\n /** Path to this element */\n path?: string;\n}\n\n/**\n * Validates a layout element against constraints.\n *\n * @param context - Information about the layout element\n * @param constraints - Layout constraints\n * @returns Array of validation issues (empty if valid)\n *\n * @public\n */\nexport function validateLayout(\n context: LayoutContext,\n constraints: LayoutConstraints\n): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n // Check if groups are allowed\n if (context.layoutType === \"group\") {\n const groupSeverity = constraints.group;\n if (groupSeverity && groupSeverity !== \"off\") {\n issues.push(createGroupIssue(context, groupSeverity));\n }\n }\n\n // Check if conditionals are allowed\n if (context.layoutType === \"conditional\") {\n const conditionalSeverity = constraints.conditionals;\n if (conditionalSeverity && conditionalSeverity !== \"off\") {\n issues.push(createConditionalIssue(context, conditionalSeverity));\n }\n }\n\n // Check nesting depth (applies to both groups and fields within nested structures)\n const maxDepth = constraints.maxNestingDepth;\n if (maxDepth !== undefined && context.depth > maxDepth) {\n issues.push(createNestingDepthIssue(context, maxDepth));\n }\n\n return issues;\n}\n\n/**\n * Creates a validation issue for a disallowed group.\n */\nfunction createGroupIssue(context: LayoutContext, severity: Severity): ValidationIssue {\n const labelInfo = context.label ? ` \"${context.label}\"` : \"\";\n const issue: ValidationIssue = {\n code: \"DISALLOWED_GROUP\",\n message: `Group${labelInfo} is not allowed - visual grouping is not supported in this project`,\n severity: severity === \"error\" ? \"error\" : \"warning\",\n category: \"layout\",\n };\n if (context.path !== undefined) {\n issue.path = context.path;\n }\n return issue;\n}\n\n/**\n * Creates a validation issue for a disallowed conditional.\n */\nfunction createConditionalIssue(context: LayoutContext, severity: Severity): ValidationIssue {\n const issue: ValidationIssue = {\n code: \"DISALLOWED_CONDITIONAL\",\n message: `Conditional visibility (when/is) is not allowed in this project`,\n severity: severity === \"error\" ? \"error\" : \"warning\",\n category: \"layout\",\n };\n if (context.path !== undefined) {\n issue.path = context.path;\n }\n return issue;\n}\n\n/**\n * Creates a validation issue for exceeding nesting depth.\n */\nfunction createNestingDepthIssue(context: LayoutContext, maxDepth: number): ValidationIssue {\n const issue: ValidationIssue = {\n code: \"EXCEEDED_NESTING_DEPTH\",\n message: `Nesting depth ${String(context.depth)} exceeds maximum allowed depth of ${String(maxDepth)}`,\n severity: \"error\",\n category: \"layout\",\n };\n if (context.path !== undefined) {\n issue.path = context.path;\n }\n return issue;\n}\n\n/**\n * Checks if a layout type is allowed by the constraints.\n *\n * @param layoutType - The type of layout element\n * @param constraints - Layout constraints\n * @returns true if allowed, false if disallowed\n *\n * @public\n */\nexport function isLayoutTypeAllowed(\n layoutType: \"group\" | \"conditional\",\n constraints: LayoutConstraints\n): boolean {\n if (layoutType === \"group\") {\n const severity = constraints.group;\n return !severity || severity === \"off\";\n }\n\n // layoutType === \"conditional\"\n const severity = constraints.conditionals;\n return !severity || severity === \"off\";\n}\n\n/**\n * Checks if a nesting depth is allowed.\n *\n * @param depth - Current nesting depth\n * @param constraints - Layout constraints\n * @returns true if allowed, false if exceeds limit\n *\n * @public\n */\nexport function isNestingDepthAllowed(depth: number, constraints: LayoutConstraints): boolean {\n const maxDepth = constraints.maxNestingDepth;\n if (maxDepth === undefined) {\n return true;\n }\n return depth <= maxDepth;\n}\n","import type { FieldOptionConstraints, Severity, ValidationIssue } from \"../types.js\";\n\n/**\n * Known field options that can be validated.\n *\n * @public\n */\nexport type FieldOption =\n | \"label\"\n | \"placeholder\"\n | \"required\"\n | \"minValue\"\n | \"maxValue\"\n | \"minItems\"\n | \"maxItems\";\n\n/**\n * Context for field option validation.\n *\n * @public\n */\nexport interface FieldOptionsContext {\n /** The field name */\n fieldName: string;\n /** Which options are present on this field */\n presentOptions: FieldOption[];\n /** Path to this field */\n path?: string;\n}\n\n/**\n * Validates field options against constraints.\n *\n * @param context - Information about the field and its options\n * @param constraints - Field option constraints\n * @returns Array of validation issues (empty if valid)\n *\n * @public\n */\nexport function validateFieldOptions(\n context: FieldOptionsContext,\n constraints: FieldOptionConstraints\n): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n for (const option of context.presentOptions) {\n const severity = constraints[option];\n if (severity && severity !== \"off\") {\n issues.push(createFieldOptionIssue(context, option, severity));\n }\n }\n\n return issues;\n}\n\n/**\n * Creates a validation issue for a disallowed field option.\n */\nfunction createFieldOptionIssue(\n context: FieldOptionsContext,\n option: FieldOption,\n severity: Severity\n): ValidationIssue {\n const path = context.path ?? context.fieldName;\n return {\n code: \"DISALLOWED_FIELD_OPTION\",\n message: `Field \"${context.fieldName}\" uses the \"${option}\" option, which is not allowed in this project`,\n severity: severity === \"error\" ? \"error\" : \"warning\",\n category: \"fieldOptions\",\n path,\n fieldName: context.fieldName,\n };\n}\n\n/**\n * Extracts which options are present on a field object.\n * Works with FormSpec field types.\n *\n * @param field - A field object with potential options\n * @returns Array of present option names\n *\n * @public\n */\nexport function extractFieldOptions(field: Record<string, unknown>): FieldOption[] {\n const options: FieldOption[] = [];\n\n if (field[\"label\"] !== undefined) options.push(\"label\");\n if (field[\"placeholder\"] !== undefined) options.push(\"placeholder\");\n if (field[\"required\"] !== undefined) options.push(\"required\");\n // NumberField uses \"min\"/\"max\" in core types, map to \"minValue\"/\"maxValue\" constraints\n if (field[\"min\"] !== undefined || field[\"minValue\"] !== undefined) options.push(\"minValue\");\n if (field[\"max\"] !== undefined || field[\"maxValue\"] !== undefined) options.push(\"maxValue\");\n if (field[\"minItems\"] !== undefined) options.push(\"minItems\");\n if (field[\"maxItems\"] !== undefined) options.push(\"maxItems\");\n\n return options;\n}\n\n/**\n * Checks if a specific field option is allowed.\n *\n * @param option - The option to check\n * @param constraints - Field option constraints\n * @returns true if allowed, false if disallowed\n *\n * @public\n */\nexport function isFieldOptionAllowed(\n option: FieldOption,\n constraints: FieldOptionConstraints\n): boolean {\n const severity = constraints[option];\n return !severity || severity === \"off\";\n}\n\n/**\n * Gets the severity level for a field option.\n *\n * @param option - The option to check\n * @param constraints - Field option constraints\n * @returns Severity level, or \"off\" if not constrained\n *\n * @public\n */\nexport function getFieldOptionSeverity(\n option: FieldOption,\n constraints: FieldOptionConstraints\n): Severity {\n return constraints[option] ?? \"off\";\n}\n","import type { FormElement, FormSpec, AnyField } from \"@formspec/core\";\nimport type {\n ConstraintConfig,\n ResolvedConstraintConfig,\n ValidationIssue,\n ValidationResult,\n} from \"../types.js\";\nimport { mergeWithDefaults } from \"../defaults.js\";\nimport { validateFieldTypes } from \"./field-types.js\";\nimport { validateLayout } from \"./layout.js\";\nimport { validateFieldOptions, extractFieldOptions } from \"./field-options.js\";\n\n/**\n * Options for validating FormSpec elements.\n *\n * @public\n */\nexport interface FormSpecValidationOptions {\n /** Constraint configuration (will be merged with defaults) */\n constraints?: ConstraintConfig;\n}\n\n/**\n * Validates FormSpec elements against constraints.\n *\n * This is the main entry point for validating a form specification\n * against a constraint configuration. It walks through all elements\n * and checks each one against the configured constraints.\n *\n * @param elements - FormSpec elements to validate\n * @param options - Validation options including constraints\n * @returns Validation result with all issues found\n *\n * @example\n * ```ts\n * import { formspec, field, group } from '@formspec/dsl';\n * import { validateFormSpecElements, defineConstraints } from '@formspec/constraints';\n *\n * const form = formspec(\n * group(\"Contact\",\n * field.text(\"name\"),\n * field.dynamicEnum(\"country\", \"countries\"),\n * ),\n * );\n *\n * const result = validateFormSpecElements(form.elements, {\n * constraints: {\n * fieldTypes: { dynamicEnum: 'error' },\n * layout: { group: 'error' },\n * },\n * });\n *\n * if (!result.valid) {\n * console.error('Validation failed:', result.issues);\n * }\n * ```\n *\n * @public\n */\nexport function validateFormSpecElements(\n elements: readonly FormElement[],\n options: FormSpecValidationOptions = {}\n): ValidationResult {\n const constraints = mergeWithDefaults(options.constraints);\n const issues: ValidationIssue[] = [];\n\n // Walk through all elements\n walkElements(elements, constraints, issues, \"\", 0);\n\n return {\n valid: !issues.some((issue) => issue.severity === \"error\"),\n issues,\n };\n}\n\n/**\n * Validates a complete FormSpec against constraints.\n *\n * @param formSpec - The FormSpec to validate\n * @param options - Validation options including constraints\n * @returns Validation result with all issues found\n *\n * @public\n */\nexport function validateFormSpec(\n formSpec: FormSpec<readonly FormElement[]>,\n options: FormSpecValidationOptions = {}\n): ValidationResult {\n return validateFormSpecElements(formSpec.elements, options);\n}\n\n/**\n * Recursively walks through FormSpec elements and validates each one.\n */\nfunction walkElements(\n elements: readonly FormElement[],\n constraints: ResolvedConstraintConfig,\n issues: ValidationIssue[],\n pathPrefix: string,\n depth: number\n): void {\n for (const element of elements) {\n const elementPath = pathPrefix;\n\n if (element._type === \"field\") {\n validateField(element, constraints, issues, elementPath, depth);\n } else if (element._type === \"group\") {\n validateGroup(element, constraints, issues, elementPath, depth);\n } else {\n // element._type === \"conditional\"\n validateConditional(element, constraints, issues, elementPath, depth);\n }\n }\n}\n\n/**\n * Validates a field element.\n */\nfunction validateField(\n field: AnyField,\n constraints: ResolvedConstraintConfig,\n issues: ValidationIssue[],\n pathPrefix: string,\n depth: number\n): void {\n const fieldPath = pathPrefix ? `${pathPrefix}/${field.name}` : field.name;\n\n // Validate field type\n const fieldTypeIssues = validateFieldTypes(\n {\n fieldType: field._field,\n fieldName: field.name,\n path: fieldPath,\n },\n constraints.fieldTypes\n );\n issues.push(...fieldTypeIssues);\n\n // Validate field options\n const presentOptions = extractFieldOptions(field as unknown as Record<string, unknown>);\n if (presentOptions.length > 0) {\n const optionIssues = validateFieldOptions(\n {\n fieldName: field.name,\n presentOptions,\n path: fieldPath,\n },\n constraints.fieldOptions\n );\n issues.push(...optionIssues);\n }\n\n // Check nesting depth for array/object fields\n if (field._field === \"array\" || field._field === \"object\") {\n const layoutIssues = validateLayout(\n {\n layoutType: \"group\", // Arrays/objects contribute to nesting depth\n depth: depth + 1,\n path: fieldPath,\n },\n constraints.layout\n );\n // Only add nesting depth issues, not group issues\n issues.push(...layoutIssues.filter((issue) => issue.code === \"EXCEEDED_NESTING_DEPTH\"));\n\n // Recursively validate nested elements\n if (field._field === \"array\" && \"items\" in field) {\n walkElements(\n field.items as readonly FormElement[],\n constraints,\n issues,\n `${fieldPath}[]`,\n depth + 1\n );\n } else if (\"properties\" in field) {\n // field._field === \"object\"\n walkElements(\n field.properties as readonly FormElement[],\n constraints,\n issues,\n fieldPath,\n depth + 1\n );\n }\n }\n}\n\n/**\n * Validates a group element.\n */\nfunction validateGroup(\n group: {\n readonly _type: \"group\";\n readonly label: string;\n readonly elements: readonly FormElement[];\n },\n constraints: ResolvedConstraintConfig,\n issues: ValidationIssue[],\n pathPrefix: string,\n depth: number\n): void {\n const groupPath = pathPrefix ? `${pathPrefix}/[group:${group.label}]` : `[group:${group.label}]`;\n\n // Validate group usage\n const layoutIssues = validateLayout(\n {\n layoutType: \"group\",\n label: group.label,\n depth,\n path: groupPath,\n },\n constraints.layout\n );\n issues.push(...layoutIssues);\n\n // Recursively validate nested elements (groups don't increase nesting depth for schema)\n walkElements(group.elements, constraints, issues, pathPrefix, depth);\n}\n\n/**\n * Validates a conditional element.\n */\nfunction validateConditional(\n conditional: {\n readonly _type: \"conditional\";\n readonly field: string;\n readonly value: unknown;\n readonly elements: readonly FormElement[];\n },\n constraints: ResolvedConstraintConfig,\n issues: ValidationIssue[],\n pathPrefix: string,\n depth: number\n): void {\n const condPath = pathPrefix\n ? `${pathPrefix}/[when:${conditional.field}=${String(conditional.value)}]`\n : `[when:${conditional.field}=${String(conditional.value)}]`;\n\n // Validate conditional usage\n const layoutIssues = validateLayout(\n {\n layoutType: \"conditional\",\n depth,\n path: condPath,\n },\n constraints.layout\n );\n issues.push(...layoutIssues);\n\n // Recursively validate nested elements\n walkElements(conditional.elements, constraints, issues, pathPrefix, depth);\n}\n"],"mappings":"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","names":["severity"]}
|
package/dist/loader.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { ConstraintConfig, ResolvedConstraintConfig } from "./types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Options for loading configuration.
|
|
4
|
+
*
|
|
5
|
+
* @public
|
|
4
6
|
*/
|
|
5
7
|
export interface LoadConfigOptions {
|
|
6
8
|
/**
|
|
@@ -21,6 +23,8 @@ export interface LoadConfigOptions {
|
|
|
21
23
|
}
|
|
22
24
|
/**
|
|
23
25
|
* Result of loading configuration.
|
|
26
|
+
*
|
|
27
|
+
* @public
|
|
24
28
|
*/
|
|
25
29
|
export interface LoadConfigResult {
|
|
26
30
|
/** The loaded and merged configuration */
|
|
@@ -47,6 +51,8 @@ export interface LoadConfigResult {
|
|
|
47
51
|
* // Load from specific file
|
|
48
52
|
* const result = await loadConfig({ configPath: '/path/to/config.yml' });
|
|
49
53
|
* ```
|
|
54
|
+
*
|
|
55
|
+
* @public
|
|
50
56
|
*/
|
|
51
57
|
export declare function loadConfig(options?: LoadConfigOptions): Promise<LoadConfigResult>;
|
|
52
58
|
/**
|
|
@@ -55,6 +61,8 @@ export declare function loadConfig(options?: LoadConfigOptions): Promise<LoadCon
|
|
|
55
61
|
*
|
|
56
62
|
* @param yamlContent - The YAML content to parse
|
|
57
63
|
* @returns The parsed and merged configuration
|
|
64
|
+
*
|
|
65
|
+
* @public
|
|
58
66
|
*/
|
|
59
67
|
export declare function loadConfigFromString(yamlContent: string): ResolvedConstraintConfig;
|
|
60
68
|
/**
|
|
@@ -76,6 +84,8 @@ export declare function loadConfigFromString(yamlContent: string): ResolvedConst
|
|
|
76
84
|
* },
|
|
77
85
|
* });
|
|
78
86
|
* ```
|
|
87
|
+
*
|
|
88
|
+
* @public
|
|
79
89
|
*/
|
|
80
90
|
export declare function defineConstraints(config: ConstraintConfig): ResolvedConstraintConfig;
|
|
81
91
|
//# sourceMappingURL=loader.d.ts.map
|
package/dist/loader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAkB,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAQ7F
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAkB,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAQ7F;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,0CAA0C;IAC1C,MAAM,EAAE,wBAAwB,CAAC;IACjC,2DAA2D;IAC3D,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,sCAAsC;IACtC,KAAK,EAAE,OAAO,CAAC;CAChB;AAqDD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAgC3F;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,wBAAwB,CAYlF;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG,wBAAwB,CAEpF"}
|
package/dist/types.d.ts
CHANGED
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
* - "error": Violation fails validation
|
|
4
4
|
* - "warn": Violation emits warning but passes
|
|
5
5
|
* - "off": Feature is allowed (no violation)
|
|
6
|
+
*
|
|
7
|
+
* @public
|
|
6
8
|
*/
|
|
7
9
|
export type Severity = "error" | "warn" | "off";
|
|
8
10
|
/**
|
|
9
11
|
* Field type constraints - control which field types are allowed.
|
|
10
12
|
* Fine-grained control over each DSL field builder.
|
|
13
|
+
*
|
|
14
|
+
* @public
|
|
11
15
|
*/
|
|
12
16
|
export interface FieldTypeConstraints {
|
|
13
17
|
/** field.text() - basic text input */
|
|
@@ -29,6 +33,8 @@ export interface FieldTypeConstraints {
|
|
|
29
33
|
}
|
|
30
34
|
/**
|
|
31
35
|
* Layout and structure constraints - control grouping, conditionals, nesting.
|
|
36
|
+
*
|
|
37
|
+
* @public
|
|
32
38
|
*/
|
|
33
39
|
export interface LayoutConstraints {
|
|
34
40
|
/** group() - visual grouping of fields */
|
|
@@ -40,6 +46,8 @@ export interface LayoutConstraints {
|
|
|
40
46
|
}
|
|
41
47
|
/**
|
|
42
48
|
* JSONForms layout type constraints.
|
|
49
|
+
*
|
|
50
|
+
* @public
|
|
43
51
|
*/
|
|
44
52
|
export interface LayoutTypeConstraints {
|
|
45
53
|
/** VerticalLayout - stack elements vertically */
|
|
@@ -55,6 +63,8 @@ export interface LayoutTypeConstraints {
|
|
|
55
63
|
}
|
|
56
64
|
/**
|
|
57
65
|
* JSONForms rule effect constraints.
|
|
66
|
+
*
|
|
67
|
+
* @public
|
|
58
68
|
*/
|
|
59
69
|
export interface RuleEffectConstraints {
|
|
60
70
|
/** SHOW - show element when condition is true */
|
|
@@ -68,6 +78,8 @@ export interface RuleEffectConstraints {
|
|
|
68
78
|
}
|
|
69
79
|
/**
|
|
70
80
|
* JSONForms rule constraints.
|
|
81
|
+
*
|
|
82
|
+
* @public
|
|
71
83
|
*/
|
|
72
84
|
export interface RuleConstraints {
|
|
73
85
|
/** Whether rules are enabled at all */
|
|
@@ -77,6 +89,8 @@ export interface RuleConstraints {
|
|
|
77
89
|
}
|
|
78
90
|
/**
|
|
79
91
|
* UI Schema feature constraints - control JSONForms-specific features.
|
|
92
|
+
*
|
|
93
|
+
* @public
|
|
80
94
|
*/
|
|
81
95
|
export interface UISchemaConstraints {
|
|
82
96
|
/** Layout type constraints */
|
|
@@ -86,6 +100,8 @@ export interface UISchemaConstraints {
|
|
|
86
100
|
}
|
|
87
101
|
/**
|
|
88
102
|
* Field configuration option constraints - control which field options are allowed.
|
|
103
|
+
*
|
|
104
|
+
* @public
|
|
89
105
|
*/
|
|
90
106
|
export interface FieldOptionConstraints {
|
|
91
107
|
/** label - field label text */
|
|
@@ -106,6 +122,8 @@ export interface FieldOptionConstraints {
|
|
|
106
122
|
/**
|
|
107
123
|
* Control options constraints - control which JSONForms Control.options are allowed.
|
|
108
124
|
* These are renderer-specific options that may not be universally supported.
|
|
125
|
+
*
|
|
126
|
+
* @public
|
|
109
127
|
*/
|
|
110
128
|
export interface ControlOptionConstraints {
|
|
111
129
|
/** format - renderer format hint (e.g., "radio", "textarea") */
|
|
@@ -123,6 +141,8 @@ export interface ControlOptionConstraints {
|
|
|
123
141
|
}
|
|
124
142
|
/**
|
|
125
143
|
* Complete constraint configuration for a FormSpec project.
|
|
144
|
+
*
|
|
145
|
+
* @public
|
|
126
146
|
*/
|
|
127
147
|
export interface ConstraintConfig {
|
|
128
148
|
/** Field type constraints */
|
|
@@ -138,6 +158,8 @@ export interface ConstraintConfig {
|
|
|
138
158
|
}
|
|
139
159
|
/**
|
|
140
160
|
* Fully resolved rule constraints with all properties required.
|
|
161
|
+
*
|
|
162
|
+
* @public
|
|
141
163
|
*/
|
|
142
164
|
export interface ResolvedRuleConstraints {
|
|
143
165
|
enabled: Severity;
|
|
@@ -145,6 +167,8 @@ export interface ResolvedRuleConstraints {
|
|
|
145
167
|
}
|
|
146
168
|
/**
|
|
147
169
|
* Fully resolved UI schema constraints with all properties required.
|
|
170
|
+
*
|
|
171
|
+
* @public
|
|
148
172
|
*/
|
|
149
173
|
export interface ResolvedUISchemaConstraints {
|
|
150
174
|
layouts: Required<LayoutTypeConstraints>;
|
|
@@ -153,6 +177,8 @@ export interface ResolvedUISchemaConstraints {
|
|
|
153
177
|
/**
|
|
154
178
|
* Fully resolved constraint configuration with all properties required.
|
|
155
179
|
* This is the type returned by mergeWithDefaults().
|
|
180
|
+
*
|
|
181
|
+
* @public
|
|
156
182
|
*/
|
|
157
183
|
export interface ResolvedConstraintConfig {
|
|
158
184
|
fieldTypes: Required<FieldTypeConstraints>;
|
|
@@ -164,6 +190,8 @@ export interface ResolvedConstraintConfig {
|
|
|
164
190
|
/**
|
|
165
191
|
* Top-level FormSpec configuration file structure.
|
|
166
192
|
* The .formspec.yml file uses this structure.
|
|
193
|
+
*
|
|
194
|
+
* @public
|
|
167
195
|
*/
|
|
168
196
|
export interface FormSpecConfig {
|
|
169
197
|
/** Constraint configuration */
|
|
@@ -171,6 +199,8 @@ export interface FormSpecConfig {
|
|
|
171
199
|
}
|
|
172
200
|
/**
|
|
173
201
|
* A single validation issue found during constraint checking.
|
|
202
|
+
*
|
|
203
|
+
* @public
|
|
174
204
|
*/
|
|
175
205
|
export interface ValidationIssue {
|
|
176
206
|
/** Unique code identifying the issue type */
|
|
@@ -190,6 +220,8 @@ export interface ValidationIssue {
|
|
|
190
220
|
}
|
|
191
221
|
/**
|
|
192
222
|
* Result of validating a FormSpec or schema against constraints.
|
|
223
|
+
*
|
|
224
|
+
* @public
|
|
193
225
|
*/
|
|
194
226
|
export interface ValidationResult {
|
|
195
227
|
/** Whether validation passed (no errors, warnings OK) */
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import type { FieldOptionConstraints, Severity, ValidationIssue } from "../types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Known field options that can be validated.
|
|
4
|
+
*
|
|
5
|
+
* @public
|
|
4
6
|
*/
|
|
5
7
|
export type FieldOption = "label" | "placeholder" | "required" | "minValue" | "maxValue" | "minItems" | "maxItems";
|
|
6
8
|
/**
|
|
7
9
|
* Context for field option validation.
|
|
10
|
+
*
|
|
11
|
+
* @public
|
|
8
12
|
*/
|
|
9
13
|
export interface FieldOptionsContext {
|
|
10
14
|
/** The field name */
|
|
@@ -20,6 +24,8 @@ export interface FieldOptionsContext {
|
|
|
20
24
|
* @param context - Information about the field and its options
|
|
21
25
|
* @param constraints - Field option constraints
|
|
22
26
|
* @returns Array of validation issues (empty if valid)
|
|
27
|
+
*
|
|
28
|
+
* @public
|
|
23
29
|
*/
|
|
24
30
|
export declare function validateFieldOptions(context: FieldOptionsContext, constraints: FieldOptionConstraints): ValidationIssue[];
|
|
25
31
|
/**
|
|
@@ -28,6 +34,8 @@ export declare function validateFieldOptions(context: FieldOptionsContext, const
|
|
|
28
34
|
*
|
|
29
35
|
* @param field - A field object with potential options
|
|
30
36
|
* @returns Array of present option names
|
|
37
|
+
*
|
|
38
|
+
* @public
|
|
31
39
|
*/
|
|
32
40
|
export declare function extractFieldOptions(field: Record<string, unknown>): FieldOption[];
|
|
33
41
|
/**
|
|
@@ -36,6 +44,8 @@ export declare function extractFieldOptions(field: Record<string, unknown>): Fie
|
|
|
36
44
|
* @param option - The option to check
|
|
37
45
|
* @param constraints - Field option constraints
|
|
38
46
|
* @returns true if allowed, false if disallowed
|
|
47
|
+
*
|
|
48
|
+
* @public
|
|
39
49
|
*/
|
|
40
50
|
export declare function isFieldOptionAllowed(option: FieldOption, constraints: FieldOptionConstraints): boolean;
|
|
41
51
|
/**
|
|
@@ -44,6 +54,8 @@ export declare function isFieldOptionAllowed(option: FieldOption, constraints: F
|
|
|
44
54
|
* @param option - The option to check
|
|
45
55
|
* @param constraints - Field option constraints
|
|
46
56
|
* @returns Severity level, or "off" if not constrained
|
|
57
|
+
*
|
|
58
|
+
* @public
|
|
47
59
|
*/
|
|
48
60
|
export declare function getFieldOptionSeverity(option: FieldOption, constraints: FieldOptionConstraints): Severity;
|
|
49
61
|
//# sourceMappingURL=field-options.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-options.d.ts","sourceRoot":"","sources":["../../src/validators/field-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAErF
|
|
1
|
+
{"version":3,"file":"field-options.d.ts","sourceRoot":"","sources":["../../src/validators/field-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAErF;;;;GAIG;AACH,MAAM,MAAM,WAAW,GACnB,OAAO,GACP,aAAa,GACb,UAAU,GACV,UAAU,GACV,UAAU,GACV,UAAU,GACV,UAAU,CAAC;AAEf;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,qBAAqB;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,cAAc,EAAE,WAAW,EAAE,CAAC;IAC9B,yBAAyB;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,mBAAmB,EAC5B,WAAW,EAAE,sBAAsB,GAClC,eAAe,EAAE,CAWnB;AAqBD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,EAAE,CAajF;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,sBAAsB,GAClC,OAAO,CAGT;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,sBAAsB,GAClC,QAAQ,CAEV"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { FieldTypeConstraints, Severity, ValidationIssue } from "../types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Context for field type validation.
|
|
4
|
+
*
|
|
5
|
+
* @public
|
|
4
6
|
*/
|
|
5
7
|
export interface FieldTypeContext {
|
|
6
8
|
/** The _field discriminator value (e.g., "text", "number", "enum") */
|
|
@@ -16,6 +18,8 @@ export interface FieldTypeContext {
|
|
|
16
18
|
* @param context - Information about the field being validated
|
|
17
19
|
* @param constraints - Field type constraints
|
|
18
20
|
* @returns Array of validation issues (empty if valid)
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
19
23
|
*/
|
|
20
24
|
export declare function validateFieldTypes(context: FieldTypeContext, constraints: FieldTypeConstraints): ValidationIssue[];
|
|
21
25
|
/**
|
|
@@ -25,6 +29,8 @@ export declare function validateFieldTypes(context: FieldTypeContext, constraint
|
|
|
25
29
|
* @param fieldType - The _field discriminator value
|
|
26
30
|
* @param constraints - Field type constraints
|
|
27
31
|
* @returns true if allowed, false if disallowed
|
|
32
|
+
*
|
|
33
|
+
* @public
|
|
28
34
|
*/
|
|
29
35
|
export declare function isFieldTypeAllowed(fieldType: string, constraints: FieldTypeConstraints): boolean;
|
|
30
36
|
/**
|
|
@@ -33,6 +39,8 @@ export declare function isFieldTypeAllowed(fieldType: string, constraints: Field
|
|
|
33
39
|
* @param fieldType - The _field discriminator value
|
|
34
40
|
* @param constraints - Field type constraints
|
|
35
41
|
* @returns Severity level, or "off" if not constrained
|
|
42
|
+
*
|
|
43
|
+
* @public
|
|
36
44
|
*/
|
|
37
45
|
export declare function getFieldTypeSeverity(fieldType: string, constraints: FieldTypeConstraints): Severity;
|
|
38
46
|
//# sourceMappingURL=field-types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-types.d.ts","sourceRoot":"","sources":["../../src/validators/field-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AA8BnF
|
|
1
|
+
{"version":3,"file":"field-types.d.ts","sourceRoot":"","sources":["../../src/validators/field-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AA8BnF;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,gBAAgB,EACzB,WAAW,EAAE,oBAAoB,GAChC,eAAe,EAAE,CAgBnB;AAsBD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,oBAAoB,GAAG,OAAO,CAQhG;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,oBAAoB,GAChC,QAAQ,CAOV"}
|
|
@@ -2,6 +2,8 @@ import type { FormElement, FormSpec } from "@formspec/core";
|
|
|
2
2
|
import type { ConstraintConfig, ValidationResult } from "../types.js";
|
|
3
3
|
/**
|
|
4
4
|
* Options for validating FormSpec elements.
|
|
5
|
+
*
|
|
6
|
+
* @public
|
|
5
7
|
*/
|
|
6
8
|
export interface FormSpecValidationOptions {
|
|
7
9
|
/** Constraint configuration (will be merged with defaults) */
|
|
@@ -41,6 +43,8 @@ export interface FormSpecValidationOptions {
|
|
|
41
43
|
* console.error('Validation failed:', result.issues);
|
|
42
44
|
* }
|
|
43
45
|
* ```
|
|
46
|
+
*
|
|
47
|
+
* @public
|
|
44
48
|
*/
|
|
45
49
|
export declare function validateFormSpecElements(elements: readonly FormElement[], options?: FormSpecValidationOptions): ValidationResult;
|
|
46
50
|
/**
|
|
@@ -49,6 +53,8 @@ export declare function validateFormSpecElements(elements: readonly FormElement[
|
|
|
49
53
|
* @param formSpec - The FormSpec to validate
|
|
50
54
|
* @param options - Validation options including constraints
|
|
51
55
|
* @returns Validation result with all issues found
|
|
56
|
+
*
|
|
57
|
+
* @public
|
|
52
58
|
*/
|
|
53
59
|
export declare function validateFormSpec(formSpec: FormSpec<readonly FormElement[]>, options?: FormSpecValidationOptions): ValidationResult;
|
|
54
60
|
//# sourceMappingURL=formspec.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formspec.d.ts","sourceRoot":"","sources":["../../src/validators/formspec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAY,MAAM,gBAAgB,CAAC;AACtE,OAAO,KAAK,EACV,gBAAgB,EAGhB,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAMrB
|
|
1
|
+
{"version":3,"file":"formspec.d.ts","sourceRoot":"","sources":["../../src/validators/formspec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAY,MAAM,gBAAgB,CAAC;AACtE,OAAO,KAAK,EACV,gBAAgB,EAGhB,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAMrB;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,8DAA8D;IAC9D,WAAW,CAAC,EAAE,gBAAgB,CAAC;CAChC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,SAAS,WAAW,EAAE,EAChC,OAAO,GAAE,yBAA8B,GACtC,gBAAgB,CAWlB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,CAAC,SAAS,WAAW,EAAE,CAAC,EAC1C,OAAO,GAAE,yBAA8B,GACtC,gBAAgB,CAElB"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { LayoutConstraints, ValidationIssue } from "../types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Context for layout validation.
|
|
4
|
+
*
|
|
5
|
+
* @public
|
|
4
6
|
*/
|
|
5
7
|
export interface LayoutContext {
|
|
6
8
|
/** The type of layout element ("group" | "conditional") */
|
|
@@ -18,6 +20,8 @@ export interface LayoutContext {
|
|
|
18
20
|
* @param context - Information about the layout element
|
|
19
21
|
* @param constraints - Layout constraints
|
|
20
22
|
* @returns Array of validation issues (empty if valid)
|
|
23
|
+
*
|
|
24
|
+
* @public
|
|
21
25
|
*/
|
|
22
26
|
export declare function validateLayout(context: LayoutContext, constraints: LayoutConstraints): ValidationIssue[];
|
|
23
27
|
/**
|
|
@@ -26,6 +30,8 @@ export declare function validateLayout(context: LayoutContext, constraints: Layo
|
|
|
26
30
|
* @param layoutType - The type of layout element
|
|
27
31
|
* @param constraints - Layout constraints
|
|
28
32
|
* @returns true if allowed, false if disallowed
|
|
33
|
+
*
|
|
34
|
+
* @public
|
|
29
35
|
*/
|
|
30
36
|
export declare function isLayoutTypeAllowed(layoutType: "group" | "conditional", constraints: LayoutConstraints): boolean;
|
|
31
37
|
/**
|
|
@@ -34,6 +40,8 @@ export declare function isLayoutTypeAllowed(layoutType: "group" | "conditional",
|
|
|
34
40
|
* @param depth - Current nesting depth
|
|
35
41
|
* @param constraints - Layout constraints
|
|
36
42
|
* @returns true if allowed, false if exceeds limit
|
|
43
|
+
*
|
|
44
|
+
* @public
|
|
37
45
|
*/
|
|
38
46
|
export declare function isNestingDepthAllowed(depth: number, constraints: LayoutConstraints): boolean;
|
|
39
47
|
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../src/validators/layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAY,eAAe,EAAE,MAAM,aAAa,CAAC;AAEhF
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../src/validators/layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAY,eAAe,EAAE,MAAM,aAAa,CAAC;AAEhF;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,2DAA2D;IAC3D,UAAU,EAAE,OAAO,GAAG,aAAa,CAAC;IACpC,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,aAAa,EACtB,WAAW,EAAE,iBAAiB,GAC7B,eAAe,EAAE,CA0BnB;AAmDD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,OAAO,GAAG,aAAa,EACnC,WAAW,EAAE,iBAAiB,GAC7B,OAAO,CAST;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,iBAAiB,GAAG,OAAO,CAM5F"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@formspec/constraints",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.21",
|
|
4
4
|
"description": "Constraint validation for FormSpec - restrict features based on target environment capabilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"yaml": "^2.7.0",
|
|
29
|
-
"@formspec/core": "0.1.0-alpha.
|
|
29
|
+
"@formspec/core": "0.1.0-alpha.21"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"tsd": "^0.31.0",
|
|
33
33
|
"vitest": "^3.0.0",
|
|
34
|
-
"@formspec/dsl": "0.1.0-alpha.
|
|
34
|
+
"@formspec/dsl": "0.1.0-alpha.21"
|
|
35
35
|
},
|
|
36
36
|
"tsd": {
|
|
37
37
|
"directory": "src/__tests__"
|