import type { SchemaBase } from './dsl.js'; // Field rules: the third semantic dimension of a Field. A rule is a named // transformation between two ends — scale (fen↔yuan), encrypt/decrypt, // mask/unmask. The rule owns both ends; a binding says which field plays // which end. Rules are unique per semantic name (checked at definition). /** One end of a field rule (e.g. 'fen' / 'yuan', 'plain' / 'cipher', 'raw' / 'masked'). */ export interface FieldRuleEnd { /** End name — written back by defineFieldRule from the ends map key. */ name: string; description?: string; } /** A semantic transformation rule between two field representations. */ export interface FieldRuleSchema extends SchemaBase { type: 'fieldRule'; /** Rule name — the semantic uniqueness key. */ name: string; /** The two ends of the rule, keyed by end name. */ ends: Record; } /** One rule per semantic name. Defining the same name twice throws. */ const ruleRegistry = new Map(); export function defineFieldRule(options: { name: string; ends: Record>; description?: string; }): FieldRuleSchema { if (ruleRegistry.has(options.name)) { throw new Error(`fieldRule '${options.name}' is already defined — one rule per semantic`); } const ends: Record = {}; for (const key of Object.keys(options.ends)) { ends[key] = { name: key, description: options.ends[key].description }; } const rule: FieldRuleSchema = { type: 'fieldRule', name: options.name, description: options.description, ends, }; ruleRegistry.set(options.name, rule); return rule; }