@lokascript/framework 4.6.0 → 4.8.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/CHANGELOG.md +121 -1
- package/dist/api/create-dsl.d.ts +18 -2
- package/dist/api/create-dsl.d.ts.map +1 -1
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +1799 -713
- package/dist/api/index.js.map +1 -1
- package/dist/api/translation-loss.d.ts +84 -0
- package/dist/api/translation-loss.d.ts.map +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1057 -684
- package/dist/core/index.js.map +1 -1
- package/dist/core/matching/confidence-model.d.ts +54 -0
- package/dist/core/matching/confidence-model.d.ts.map +1 -0
- package/dist/core/matching/index.d.ts +12 -0
- package/dist/core/matching/index.d.ts.map +1 -0
- package/dist/core/matching/match-skeleton.d.ts +114 -0
- package/dist/core/matching/match-skeleton.d.ts.map +1 -0
- package/dist/core/matching/stock-confidence.d.ts +15 -0
- package/dist/core/matching/stock-confidence.d.ts.map +1 -0
- package/dist/core/matching/stock-reader.d.ts +63 -0
- package/dist/core/matching/stock-reader.d.ts.map +1 -0
- package/dist/core/matching/stock-reading.d.ts +44 -0
- package/dist/core/matching/stock-reading.d.ts.map +1 -0
- package/dist/core/matching/value-reader.d.ts +62 -0
- package/dist/core/matching/value-reader.d.ts.map +1 -0
- package/dist/core/pattern-matching/index.js +561 -660
- package/dist/core/pattern-matching/index.js.map +1 -1
- package/dist/core/pattern-matching/pattern-matcher.d.ts +0 -117
- package/dist/core/pattern-matching/pattern-matcher.d.ts.map +1 -1
- package/dist/core/types.d.ts +53 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/generation/index.d.ts +2 -0
- package/dist/generation/index.d.ts.map +1 -1
- package/dist/generation/index.js +593 -1
- package/dist/generation/index.js.map +1 -1
- package/dist/generation/pattern-render.d.ts +72 -0
- package/dist/generation/pattern-render.d.ts.map +1 -0
- package/dist/generation/schema-patterns.d.ts +152 -0
- package/dist/generation/schema-patterns.d.ts.map +1 -0
- package/dist/index.cjs +2016 -904
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1998 -903
- package/dist/index.js.map +1 -1
- package/dist/ir/index.js.map +1 -1
- package/dist/parsing/index.js +561 -660
- package/dist/parsing/index.js.map +1 -1
- package/dist/testing/gate/index.d.ts +8 -0
- package/dist/testing/gate/index.d.ts.map +1 -0
- package/dist/testing/gate/index.js +664 -0
- package/dist/testing/gate/index.js.map +1 -0
- package/dist/testing/gate/lint/format.d.ts +7 -0
- package/dist/testing/gate/lint/format.d.ts.map +1 -0
- package/dist/testing/gate/lint/index.d.ts +30 -0
- package/dist/testing/gate/lint/index.d.ts.map +1 -0
- package/dist/testing/gate/lint/rules/extractor-coverage.d.ts +18 -0
- package/dist/testing/gate/lint/rules/extractor-coverage.d.ts.map +1 -0
- package/dist/testing/gate/lint/rules/index.d.ts +14 -0
- package/dist/testing/gate/lint/rules/index.d.ts.map +1 -0
- package/dist/testing/gate/lint/rules/keyword-classification.d.ts +19 -0
- package/dist/testing/gate/lint/rules/keyword-classification.d.ts.map +1 -0
- package/dist/testing/gate/lint/rules/keyword-coverage.d.ts +13 -0
- package/dist/testing/gate/lint/rules/keyword-coverage.d.ts.map +1 -0
- package/dist/testing/gate/lint/rules/marker-tokenization.d.ts +20 -0
- package/dist/testing/gate/lint/rules/marker-tokenization.d.ts.map +1 -0
- package/dist/testing/gate/lint/rules/position-ordering.d.ts +25 -0
- package/dist/testing/gate/lint/rules/position-ordering.d.ts.map +1 -0
- package/dist/testing/gate/lint/rules/renderer-coherence.d.ts +24 -0
- package/dist/testing/gate/lint/rules/renderer-coherence.d.ts.map +1 -0
- package/dist/testing/gate/lint/rules/schema-rules.d.ts +10 -0
- package/dist/testing/gate/lint/rules/schema-rules.d.ts.map +1 -0
- package/dist/testing/gate/lint/types.d.ts +74 -0
- package/dist/testing/gate/lint/types.d.ts.map +1 -0
- package/dist/testing/gate/round-trip.d.ts +184 -0
- package/dist/testing/gate/round-trip.d.ts.map +1 -0
- package/package.json +6 -2
- package/src/__test__/fixtures/sql-dsl.ts +8 -2
- package/src/api/create-dsl-engine.test.ts +150 -0
- package/src/api/create-dsl.test.ts +7 -0
- package/src/api/create-dsl.ts +173 -22
- package/src/api/index.ts +1 -0
- package/src/api/translation-loss.test.ts +89 -0
- package/src/api/translation-loss.ts +128 -0
- package/src/core/index.ts +1 -0
- package/src/core/matching/confidence-model.ts +58 -0
- package/src/core/matching/index.ts +12 -0
- package/src/core/matching/match-skeleton.test.ts +179 -0
- package/src/core/matching/match-skeleton.ts +621 -0
- package/src/core/matching/stock-confidence.ts +238 -0
- package/src/core/matching/stock-reader.test.ts +265 -0
- package/src/core/matching/stock-reader.ts +205 -0
- package/src/core/matching/stock-reading.ts +681 -0
- package/src/core/matching/value-reader.ts +85 -0
- package/src/core/pattern-matching/pattern-matcher.ts +11 -876
- package/src/core/types.ts +53 -0
- package/src/generation/index.ts +2 -0
- package/src/generation/pattern-render.ts +378 -0
- package/src/generation/schema-patterns.test.ts +139 -0
- package/src/generation/schema-patterns.ts +974 -0
- package/src/testing/gate/index.ts +8 -0
- package/src/testing/gate/lint/format.ts +23 -0
- package/src/testing/gate/lint/index.ts +73 -0
- package/src/testing/gate/lint/lint.test.ts +131 -0
- package/src/testing/gate/lint/rules/extractor-coverage.ts +63 -0
- package/src/testing/gate/lint/rules/index.ts +37 -0
- package/src/testing/gate/lint/rules/keyword-classification.ts +52 -0
- package/src/testing/gate/lint/rules/keyword-coverage.ts +38 -0
- package/src/testing/gate/lint/rules/marker-tokenization.ts +129 -0
- package/src/testing/gate/lint/rules/position-ordering.ts +87 -0
- package/src/testing/gate/lint/rules/renderer-coherence.ts +100 -0
- package/src/testing/gate/lint/rules/schema-rules.ts +35 -0
- package/src/testing/gate/lint/types.ts +83 -0
- package/src/testing/gate/round-trip.test.ts +208 -0
- package/src/testing/gate/round-trip.ts +503 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/generation/pattern-generator.ts","../../src/core/types.ts","../../src/generation/renderer.ts","../../src/generation/diagnostics.ts"],"sourcesContent":["/**\n * Pattern Generator\n *\n * Generates LanguagePattern objects from CommandSchema + LanguageProfile.\n * This solves the pattern explosion problem by deriving patterns from\n * high-level schema definitions rather than hand-writing each one.\n */\n\nimport type { LanguagePattern, PatternToken, ExtractionRule } from '../core/types';\nimport type { CommandSchema, RoleSpec } from '../schema';\n\n/**\n * Minimal language profile interface for pattern generation.\n */\nexport interface PatternGenLanguageProfile {\n readonly code: string;\n readonly wordOrder: 'SVO' | 'SOV' | 'VSO' | 'VOS' | 'OSV' | 'OVS' | 'free';\n readonly keywords: Record<string, { primary: string; alternatives?: string[] }>;\n readonly roleMarkers?: Record<\n string,\n { primary: string; alternatives?: string[]; position?: 'before' | 'after' }\n >;\n}\n\n/**\n * Configuration for pattern generation.\n */\nexport interface GeneratorConfig {\n /** Base priority for generated patterns (default: 100) */\n readonly basePriority?: number;\n /** Include optional role variants (default: true) */\n readonly includeOptionalVariants?: boolean;\n}\n\nconst defaultConfig: GeneratorConfig = {\n basePriority: 100,\n includeOptionalVariants: true,\n};\n\n/**\n * Generate a language pattern from a command schema and language profile.\n *\n * @param schema - Command schema defining the command structure\n * @param profile - Language profile with word order and keywords\n * @param config - Optional configuration\n * @returns Generated language pattern\n */\nexport function generatePattern(\n schema: CommandSchema,\n profile: PatternGenLanguageProfile,\n config: GeneratorConfig = defaultConfig\n): LanguagePattern {\n const id = `${schema.action}-${profile.code}-generated`;\n const priority = config.basePriority ?? 100;\n\n // Get keyword translation\n const keyword = profile.keywords[schema.action];\n if (!keyword) {\n throw new Error(`No keyword translation for '${schema.action}' in ${profile.code}`);\n }\n\n // Build tokens based on word order\n const tokens = buildTokens(schema, profile, keyword.primary, keyword.alternatives);\n\n // Build extraction rules\n const extraction = buildExtractionRules(schema, profile);\n\n // Build format string for documentation\n const format = buildFormatString(schema, profile, keyword.primary);\n\n return {\n id,\n language: profile.code,\n command: schema.action,\n priority,\n template: {\n format,\n tokens,\n },\n extraction,\n };\n}\n\n/**\n * Build pattern tokens based on word order and role markers.\n */\nfunction buildTokens(\n schema: CommandSchema,\n profile: PatternGenLanguageProfile,\n keyword: string,\n alternatives?: string[]\n): PatternToken[] {\n const tokens: PatternToken[] = [];\n const keywordToken: PatternToken = {\n type: 'literal',\n value: keyword,\n ...(alternatives?.length && { alternatives }),\n };\n\n // Sort roles by word order\n const sortedRoles = sortRolesByWordOrder(schema.roles, profile.wordOrder);\n\n // For SVO: [action, patient, destination, source, ...]\n if (profile.wordOrder === 'SVO') {\n // Add keyword first\n tokens.push(keywordToken);\n\n // Add roles with markers\n for (const role of sortedRoles) {\n addRoleWithMarker(tokens, role, profile);\n }\n }\n // For SOV: [patient, destination, source, ..., action, postVerb roles...]\n else if (profile.wordOrder === 'SOV') {\n // `sovSlot: 'postVerb'` moves a role AFTER the verb, which is what the\n // renderer does (`renderer.ts` buckets by the same field). Generation has\n // to mirror it: a role the renderer writes post-verb but the pattern\n // expects pre-verb produces a faithful surface its own parser drops the\n // argument from — voice's `戻る 2` re-parsing as a bare `back`.\n const preVerb: PatternToken[] = [];\n const postVerb: PatternToken[] = [];\n\n for (const role of sortedRoles) {\n addRoleWithMarker(role.sovSlot === 'postVerb' ? postVerb : preVerb, role, profile);\n }\n\n tokens.push(...preVerb, keywordToken, ...postVerb);\n }\n // For VSO: [action, destination, patient, source, ...]\n else if (profile.wordOrder === 'VSO') {\n // Add keyword first\n tokens.push(keywordToken);\n\n // Add roles with markers\n for (const role of sortedRoles) {\n addRoleWithMarker(tokens, role, profile);\n }\n }\n // Other word orders can be added as needed\n else {\n // Fallback to SVO-style ordering\n tokens.push(keywordToken);\n for (const role of sortedRoles) {\n addRoleWithMarker(tokens, role, profile);\n }\n }\n\n return tokens;\n}\n\n/**\n * Add a role token with its grammatical marker if needed.\n * For optional roles, wraps the role + marker in a group.\n */\nfunction addRoleWithMarker(\n tokens: PatternToken[],\n roleSpec: RoleSpec,\n profile: PatternGenLanguageProfile\n): void {\n const marker = getMarkerForRole(roleSpec, profile);\n const isOptional = !roleSpec.required;\n\n // Build the role token\n const roleToken: PatternToken = {\n type: 'role',\n role: roleSpec.role,\n optional: isOptional,\n expectedTypes: roleSpec.expectedTypes,\n ...(roleSpec.greedy && { greedy: true }),\n };\n\n if (marker) {\n const markerInfo = profile.roleMarkers?.[roleSpec.role];\n // Priority: schema markerPosition → profile roleMarkers position → word-order default\n const defaultPosition = profile.wordOrder === 'SOV' ? 'after' : 'before';\n const position = roleSpec.markerPosition ?? markerInfo?.position ?? defaultPosition;\n\n if (isOptional) {\n // Optional role: wrap marker + role in optional group\n if (position === 'before') {\n tokens.push({\n type: 'group',\n optional: true,\n tokens: [{ type: 'literal', value: marker }, roleToken],\n });\n } else {\n tokens.push({\n type: 'group',\n optional: true,\n tokens: [roleToken, { type: 'literal', value: marker }],\n });\n }\n } else {\n // Required role: add marker + role separately\n if (position === 'before') {\n tokens.push({ type: 'literal', value: marker });\n tokens.push(roleToken);\n } else {\n tokens.push(roleToken);\n tokens.push({ type: 'literal', value: marker });\n }\n }\n } else {\n // No marker - just add the role\n tokens.push(roleToken);\n }\n}\n\n/**\n * Get the grammatical marker for a role from the profile.\n */\nfunction getMarkerForRole(\n roleSpec: RoleSpec,\n profile: PatternGenLanguageProfile\n): string | undefined {\n // Check for role-specific override first\n if (roleSpec.markerOverride?.[profile.code]) {\n return roleSpec.markerOverride[profile.code];\n }\n\n // Use profile's default marker for this role\n return profile.roleMarkers?.[roleSpec.role]?.primary;\n}\n\n/**\n * Sort roles by word order for pattern building.\n *\n * Exported so the renderer sorts with exactly this comparator — a rendered\n * surface whose role order differs from the generated pattern would not re-parse.\n */\nexport function sortRolesByWordOrder(roles: RoleSpec[], wordOrder: string): RoleSpec[] {\n const sorted = [...roles];\n\n if (wordOrder === 'SVO') {\n // Sort by svoPosition (higher = earlier)\n sorted.sort((a, b) => (b.svoPosition ?? 0) - (a.svoPosition ?? 0));\n } else if (wordOrder === 'SOV') {\n // Sort by sovPosition (higher = earlier)\n sorted.sort((a, b) => (b.sovPosition ?? 0) - (a.sovPosition ?? 0));\n }\n // VSO and others use SVO-style ordering\n\n return sorted;\n}\n\n/**\n * Build extraction rules for capturing role values during parsing.\n */\nfunction buildExtractionRules(\n schema: CommandSchema,\n profile: PatternGenLanguageProfile\n): Record<string, ExtractionRule> {\n const rules: Record<string, ExtractionRule> = {};\n\n for (const roleSpec of schema.roles) {\n // Build the rule object correctly with readonly properties\n const marker = getMarkerForRole(roleSpec, profile);\n\n const rule: ExtractionRule = {\n ...(roleSpec.default !== undefined && { default: roleSpec.default }),\n ...(marker && { marker }),\n };\n\n rules[roleSpec.role] = rule;\n }\n\n return rules;\n}\n\n/**\n * Build a human-readable format string for the pattern.\n */\nfunction buildFormatString(\n schema: CommandSchema,\n profile: PatternGenLanguageProfile,\n keyword: string\n): string {\n const isSOV = profile.wordOrder === 'SOV';\n const preVerb: string[] = [];\n const postVerb: string[] = [];\n\n // Order roles the same way buildTokens does (descending position). Iterating\n // declaration order here would disagree with the token order whenever a\n // schema's roles are declared in a different order than their positions imply.\n const sortedRoles = sortRolesByWordOrder(schema.roles, profile.wordOrder);\n for (const role of sortedRoles) {\n const marker = getMarkerForRole(role, profile);\n const roleName = `{${role.role}}`;\n // Same pre/post-verb split buildTokens applies, so the documented format\n // string keeps describing the tokens it is generated alongside.\n const bucket = isSOV && role.sovSlot === 'postVerb' ? postVerb : preVerb;\n\n if (marker) {\n const markerInfo = profile.roleMarkers?.[role.role];\n if (markerInfo?.position === 'after') {\n bucket.push(`${roleName} ${marker}`);\n } else {\n bucket.push(`${marker} ${roleName}`);\n }\n } else {\n bucket.push(roleName);\n }\n }\n\n return (isSOV ? [...preVerb, keyword, ...postVerb] : [keyword, ...preVerb, ...postVerb]).join(\n ' '\n );\n}\n\n/**\n * Generate multiple pattern variants (with and without optional roles).\n */\nexport function generatePatternVariants(\n schema: CommandSchema,\n profile: PatternGenLanguageProfile,\n config: GeneratorConfig = defaultConfig\n): LanguagePattern[] {\n const patterns: LanguagePattern[] = [];\n\n // Main pattern (all roles)\n patterns.push(generatePattern(schema, profile, config));\n\n // TODO: Generate variants with optional roles omitted\n // This can be added later when needed\n\n return patterns;\n}\n","/**\n * Core Types — re-exported from @lokascript/intent + framework-specific extensions\n *\n * The universal semantic types (SemanticNode, SemanticValue, etc.) now live in\n * @lokascript/intent and are re-exported here for backward compatibility.\n *\n * Framework-specific types (tokenization, pattern matching) are defined below.\n */\n\n// =============================================================================\n// Re-export everything from @lokascript/intent\n// =============================================================================\n\nexport type {\n ActionType,\n SemanticRole,\n SemanticValue,\n ExpectedType,\n LiteralValue,\n SelectorValue,\n ReferenceValue,\n PropertyPathValue,\n ExpressionValue,\n FlagValue,\n Annotation,\n ProtocolDiagnostic,\n AsyncVariant,\n MatchArm,\n SemanticNode,\n SemanticMetadata,\n SourcePosition,\n CommandSemanticNode,\n EventHandlerSemanticNode,\n EventModifiers,\n ConditionalSemanticNode,\n CompoundSemanticNode,\n LoopVariant,\n LoopSemanticNode,\n LSEEnvelope,\n} from '@lokascript/intent';\n\nexport {\n createLiteral,\n createSelector,\n createReference,\n createPropertyPath,\n createExpression,\n createFlag,\n createCommandNode,\n createEventHandlerNode,\n createConditionalNode,\n createCompoundNode,\n createLoopNode,\n createTryNode,\n createAsyncNode,\n createMatchNode,\n extractValue,\n extractRoleValue,\n getRoleValue,\n} from '@lokascript/intent';\n\n// =============================================================================\n// Framework-specific types (multilingual DSL infrastructure)\n// =============================================================================\n\nimport type {\n ActionType,\n SemanticRole,\n SemanticValue,\n SelectorValue,\n ExpectedType,\n SourcePosition,\n} from '@lokascript/intent';\n\n/**\n * Token kind - categorizes what type of token this is.\n */\nexport type TokenKind =\n | 'keyword' // Command or modifier keyword\n | 'selector' // CSS selector or identifier (#id, .class, table-name)\n | 'literal' // String or number literal\n | 'particle' // Grammatical particle (を, に, من)\n | 'conjunction' // Grammatical conjunction\n | 'event-modifier' // Event modifier (.once, .debounce(300))\n | 'identifier' // Generic identifier\n | 'operator' // Operators (., +, -, etc.)\n | 'punctuation' // Punctuation (parentheses, etc.)\n | 'url'; // URL or path\n\n/**\n * A language token - the result of tokenization.\n */\nexport interface LanguageToken {\n readonly value: string;\n readonly kind: TokenKind;\n readonly position: SourcePosition;\n readonly normalized?: string;\n readonly stem?: string;\n readonly stemConfidence?: number;\n readonly metadata?: Record<string, unknown>;\n}\n\n/**\n * Token stream - provides sequential access to tokens with backtracking.\n */\nexport interface TokenStream {\n readonly tokens: readonly LanguageToken[];\n readonly language: string;\n peek(offset?: number): LanguageToken | null;\n advance(): LanguageToken;\n isAtEnd(): boolean;\n mark(): StreamMark;\n reset(mark: StreamMark): void;\n position(): number;\n}\n\nexport interface StreamMark {\n readonly position: number;\n}\n\n/**\n * Language tokenizer interface - converts text to tokens.\n */\nexport interface LanguageTokenizer {\n readonly language: string;\n readonly direction: 'ltr' | 'rtl';\n tokenize(input: string): TokenStream;\n classifyToken(token: string): TokenKind;\n}\n\n// =============================================================================\n// Pattern Matching Types\n// =============================================================================\n\nexport interface LanguagePattern {\n readonly id: string;\n readonly language: string;\n readonly command: ActionType;\n readonly priority: number;\n readonly template: PatternTemplate;\n readonly extraction: ExtractionRules;\n readonly constraints?: PatternConstraints;\n}\n\nexport interface PatternTemplate {\n readonly format: string;\n readonly tokens: PatternToken[];\n}\n\nexport type PatternToken = LiteralPatternToken | RolePatternToken | GroupPatternToken;\n\nexport interface LiteralPatternToken {\n readonly type: 'literal';\n readonly value: string;\n readonly alternatives?: string[];\n}\n\nexport interface RolePatternToken {\n readonly type: 'role';\n readonly role: SemanticRole;\n readonly optional?: boolean;\n readonly expectedTypes?: Array<ExpectedType>;\n readonly greedy?: boolean;\n}\n\nexport interface GroupPatternToken {\n readonly type: 'group';\n readonly tokens: PatternToken[];\n readonly optional?: boolean;\n}\n\nexport interface ExtractionRules {\n readonly [role: string]: ExtractionRule;\n}\n\nexport interface ExtractionRule {\n readonly position?: number;\n readonly marker?: string;\n readonly markerAlternatives?: string[];\n readonly transform?: (raw: string) => SemanticValue;\n readonly default?: SemanticValue;\n readonly value?: string;\n readonly fromRole?: string;\n}\n\nexport interface PatternConstraints {\n readonly requiredRoles?: SemanticRole[];\n readonly forbiddenRoles?: SemanticRole[];\n readonly validPatientTypes?: Array<SelectorValue['selectorKind']>;\n readonly conflictsWith?: string[];\n}\n\nexport interface PatternMatchResult {\n readonly pattern: LanguagePattern;\n readonly captured: ReadonlyMap<SemanticRole, SemanticValue>;\n readonly consumedTokens: number;\n readonly confidence: number;\n}\n\nexport interface PatternMatchError {\n readonly message: string;\n readonly position: SourcePosition;\n readonly expectedPatterns?: string[];\n readonly partialMatch?: Partial<PatternMatchResult>;\n}\n","/**\n * Natural Language Renderer\n *\n * Interface and utilities for rendering SemanticNode → human-readable text\n * in any supported language. This is the inverse of parsing: it converts\n * a language-neutral semantic representation back to natural-language syntax.\n *\n * Every domain that supports `translate()` needs a renderer.\n */\n\nimport type { SemanticNode } from '../core/types';\nimport { extractRoleValue, extractValue } from '../core/types';\nimport type { CommandSchema } from '../schema';\nimport { sortRolesByWordOrder, type PatternGenLanguageProfile } from './pattern-generator';\n\n// =============================================================================\n// Renderer Interface\n// =============================================================================\n\n/**\n * Renders a SemanticNode to human-readable text in a target language.\n */\nexport interface NaturalLanguageRenderer {\n render(node: SemanticNode, language: string): string;\n}\n\n// =============================================================================\n// Renderer Helpers\n// =============================================================================\n\n/**\n * Keyword table: action → language → translated keyword.\n *\n * @example\n * ```typescript\n * const KEYWORDS: KeywordTable = {\n * select: { en: 'select', ja: '選択', es: 'seleccionar' },\n * insert: { en: 'insert', ja: '挿入', es: 'insertar' },\n * };\n * ```\n */\nexport type KeywordTable = Record<string, Record<string, string>>;\n\n/**\n * Marker table: marker name → language → translated marker.\n *\n * @example\n * ```typescript\n * const MARKERS: MarkerTable = {\n * from: { en: 'from', ja: 'から', es: 'de' },\n * into: { en: 'into', ja: 'に', es: 'en' },\n * };\n * ```\n */\nexport type MarkerTable = Record<string, Record<string, string>>;\n\n/**\n * Configuration for building a renderer from schemas and profiles.\n */\nexport interface RendererConfig {\n /** Command keyword translations per language */\n readonly keywords: KeywordTable;\n\n /** Role marker translations per language (prepositions/particles) */\n readonly markers: MarkerTable;\n\n /** Languages that use SOV word order */\n readonly sovLanguages: ReadonlySet<string>;\n\n /** Languages that use VSO word order (optional, defaults to empty) */\n readonly vsoLanguages?: ReadonlySet<string>;\n}\n\n/**\n * Look up a command keyword in the target language.\n * Falls back to the key itself if no translation found.\n */\nexport function lookupKeyword(keywords: KeywordTable, action: string, language: string): string {\n return keywords[action]?.[language] ?? action;\n}\n\n/**\n * Look up a role marker in the target language.\n * Falls back to the key itself if no translation found.\n */\nexport function lookupMarker(markers: MarkerTable, marker: string, language: string): string {\n return markers[marker]?.[language] ?? marker;\n}\n\n/**\n * Build a phrase from parts, filtering empty strings and joining with space.\n *\n * @example\n * ```typescript\n * buildPhrase('select', '', 'name', 'from', 'users')\n * // → 'select name from users'\n * ```\n */\nexport function buildPhrase(...parts: string[]): string {\n return parts.filter(Boolean).join(' ');\n}\n\n/**\n * Build keyword and marker tables from schemas and language profiles.\n * Extracts translations from the profile's keyword definitions and\n * role marker overrides.\n *\n * @example\n * ```typescript\n * const { keywords, markers } = buildTablesFromProfiles(schemas, profiles);\n * ```\n */\nexport function buildTablesFromProfiles(\n schemas: readonly CommandSchema[],\n profiles: readonly PatternGenLanguageProfile[]\n): { keywords: KeywordTable; markers: MarkerTable } {\n const keywords: KeywordTable = {};\n const markers: MarkerTable = {};\n\n // Build keyword table from profiles\n for (const profile of profiles) {\n for (const [action, kw] of Object.entries(profile.keywords)) {\n if (!keywords[action]) keywords[action] = {};\n keywords[action][profile.code] = kw.primary;\n }\n }\n\n // Build marker table from schema markerOverrides\n for (const schema of schemas) {\n for (const role of schema.roles) {\n if (role.markerOverride) {\n // Use role name as marker key\n const markerKey = role.role;\n if (!markers[markerKey]) markers[markerKey] = {};\n for (const [lang, markerText] of Object.entries(role.markerOverride)) {\n markers[markerKey][lang] = markerText;\n }\n }\n }\n }\n\n // Also extract role markers from profiles\n for (const profile of profiles) {\n if (profile.roleMarkers) {\n for (const [markerKey, markerDef] of Object.entries(profile.roleMarkers)) {\n if (!markers[markerKey]) markers[markerKey] = {};\n markers[markerKey][profile.code] = markerDef.primary;\n }\n }\n }\n\n return { keywords, markers };\n}\n\n/**\n * Detect word order from language profiles.\n * Returns sets of SOV and VSO language codes.\n */\nexport function detectWordOrders(profiles: readonly PatternGenLanguageProfile[]): {\n sovLanguages: Set<string>;\n vsoLanguages: Set<string>;\n} {\n const sovLanguages = new Set<string>();\n const vsoLanguages = new Set<string>();\n\n for (const profile of profiles) {\n if (profile.wordOrder === 'SOV') sovLanguages.add(profile.code);\n if (profile.wordOrder === 'VSO') vsoLanguages.add(profile.code);\n }\n\n return { sovLanguages, vsoLanguages };\n}\n\n/**\n * Create a basic renderer from schemas and profiles.\n *\n * This generates a renderer that handles word-order reordering automatically.\n * For each command, it constructs the output by placing the keyword and\n * role values in the correct order for the target language.\n *\n * For complex domain-specific rendering, implement `NaturalLanguageRenderer`\n * directly instead.\n *\n * @example\n * ```typescript\n * const renderer = createSchemaRenderer(schemas, profiles);\n * renderer.render(node, 'ja'); // → \"users から name 選択\"\n * ```\n */\nexport function createSchemaRenderer(\n schemas: readonly CommandSchema[],\n profiles: readonly PatternGenLanguageProfile[]\n): NaturalLanguageRenderer {\n const tables = buildRenderTables(schemas, profiles);\n\n return {\n render(node: SemanticNode, language: string): string {\n // An action with no schema still has a name — render that rather than\n // nothing. `createDomainRenderer` returns null for this case instead.\n return renderFromSchema(node, language, tables) ?? node.action;\n },\n };\n}\n\n// =============================================================================\n// Domain renderer (hand-written cases + schema fallthrough)\n// =============================================================================\n\n/**\n * Renders a SemanticNode, or returns `null` when the action cannot be rendered.\n *\n * The nullable counterpart to {@link NaturalLanguageRenderer}: `null` means \"I\n * do not know this action\", which callers can act on. A domain that signals the\n * same condition with a sentinel string forces consumers into string matching.\n */\nexport type DomainRenderFn = (node: SemanticNode, language: string) => string | null;\n\n/**\n * Configuration for {@link createDomainRenderer}.\n */\nexport interface DomainRendererConfig {\n /** Schemas for this domain's commands, including any extensions. */\n readonly schemas: readonly CommandSchema[];\n\n /** Language profiles supplying keywords and role markers. */\n readonly profiles: readonly PatternGenLanguageProfile[];\n\n /**\n * Hand-written renderers per action. These take absolute precedence over the\n * schema-driven path, so a domain's existing output is preserved byte for byte.\n *\n * An override returning `null` means \"this action cannot be rendered\" and is\n * passed straight through — it does not fall through to the schema path,\n * since a hand-written renderer knows more about its action than the schema does.\n */\n readonly overrides?: Readonly<Record<string, DomainRenderFn>>;\n}\n\n/**\n * Create a renderer that composes a domain's hand-written per-action renderers\n * with the schema-driven fallback.\n *\n * Resolution order:\n * 1. `overrides[node.action]` — the domain's own rendering, unchanged\n * 2. schema-driven rendering — any action with a schema but no hand-written case\n * 3. `null` — no override and no schema\n *\n * Step 2 is what makes a domain extensible: a consumer that adds a command\n * schema (with per-language keywords in the profiles) gets correct word order,\n * markers and keywords for free, without the domain package having to know\n * about that command.\n *\n * @example\n * ```typescript\n * const render = createDomainRenderer({\n * schemas: allSchemas,\n * profiles: allProfiles,\n * overrides: { select: renderSelect, insert: renderInsert },\n * });\n * render(node, 'ja'); // hand-written for `select`, schema-driven otherwise\n * render(bogusNode, 'en'); // → null\n * ```\n */\nexport function createDomainRenderer(config: DomainRendererConfig): DomainRenderFn {\n const { schemas, profiles, overrides } = config;\n\n // Built on first render — a domain module can construct its renderer at import\n // time without paying for table construction it may never use.\n let tables: RenderTables | undefined;\n\n return (node: SemanticNode, language: string): string | null => {\n const override = overrides?.[node.action];\n if (override) return override(node, language);\n\n tables ??= buildRenderTables(schemas, profiles);\n return renderFromSchema(node, language, tables);\n };\n}\n\n// =============================================================================\n// Shared schema-driven rendering\n// =============================================================================\n\ninterface RenderTables {\n readonly keywords: KeywordTable;\n readonly markers: MarkerTable;\n /** Marker side per role per language, from each profile's roleMarkers. */\n readonly markerPositions: Record<string, Record<string, 'before' | 'after'>>;\n readonly sovLanguages: ReadonlySet<string>;\n readonly schemaMap: ReadonlyMap<string, CommandSchema>;\n}\n\nfunction buildRenderTables(\n schemas: readonly CommandSchema[],\n profiles: readonly PatternGenLanguageProfile[]\n): RenderTables {\n const { keywords, markers } = buildTablesFromProfiles(schemas, profiles);\n const { sovLanguages } = detectWordOrders(profiles);\n\n const markerPositions: Record<string, Record<string, 'before' | 'after'>> = {};\n for (const profile of profiles) {\n for (const [role, markerDef] of Object.entries(profile.roleMarkers ?? {})) {\n if (!markerDef.position) continue;\n markerPositions[role] ??= {};\n markerPositions[role][profile.code] = markerDef.position;\n }\n }\n\n const schemaMap = new Map<string, CommandSchema>();\n for (const s of schemas) schemaMap.set(s.action, s);\n return { keywords, markers, markerPositions, sovLanguages, schemaMap };\n}\n\n/**\n * The one schema-driven rendering algorithm, shared by `createSchemaRenderer`\n * and `createDomainRenderer` so the two can never drift.\n *\n * Returns `null` when the action has no schema.\n */\nfunction renderFromSchema(\n node: SemanticNode,\n language: string,\n tables: RenderTables\n): string | null {\n const schema = tables.schemaMap.get(node.action);\n if (!schema) return null;\n\n const keyword = lookupKeyword(tables.keywords, node.action, language);\n const isSOV = tables.sovLanguages.has(language);\n\n // Order roles by their declared positions, using the SAME comparator pattern\n // generation uses. Rendering in declaration order instead would produce a\n // surface the generated pattern cannot re-parse whenever the two disagree.\n const ordered = sortRolesByWordOrder([...schema.roles], isSOV ? 'SOV' : 'SVO');\n\n // Roles rendered before the verb, and (SOV only) after it.\n const preVerb: string[] = [];\n const postVerb: string[] = [];\n\n for (const role of ordered) {\n let value = extractRoleValue(node, role.role);\n if (!value && role.default !== undefined) {\n value = String(extractValue(role.default));\n }\n // A role with no value is skipped entirely — including its marker. Emitting\n // the marker of an absent role produces dangling text (\"analyze #content as\",\n // \"#content として 分析\"), which is never valid surface syntax. This applies to\n // required roles too: a required role with no value is a malformed node, and\n // a dangling marker is a worse rendering of it than simply leaving it out.\n if (!value) continue;\n\n if (role.quoteMultiword && /\\s/.test(value) && !/^([\"']).*\\1$/.test(value)) {\n value = `\"${value}\"`;\n }\n\n // Marker resolution, most specific first. `renderOverride` for this exact\n // language is the most specific statement; `''` means \"render this role\n // bare\" (a marker that exists only to help the parser). The `'*'` key is a\n // blanket statement about the PROFILE default, so it ranks below a\n // per-language markerOverride — which is how SQL's `get` renders bare in\n // SVO languages while keeping its SOV source particles.\n const markerText =\n role.renderOverride?.[language] ??\n role.markerOverride?.[language] ??\n role.renderOverride?.['*'] ??\n tables.markers[role.role]?.[language];\n\n const markerPosition =\n role.markerPositionOverride?.[language] ??\n role.markerPosition ??\n tables.markerPositions[role.role]?.[language] ??\n (isSOV ? 'after' : 'before');\n\n const bucket = isSOV && role.sovSlot === 'postVerb' ? postVerb : preVerb;\n if (markerText && markerPosition === 'before') {\n bucket.push(markerText, value);\n } else if (markerText) {\n bucket.push(value, markerText);\n } else {\n bucket.push(value);\n }\n }\n\n return isSOV\n ? buildPhrase(...preVerb, keyword, ...postVerb)\n : buildPhrase(keyword, ...preVerb, ...postVerb);\n}\n","/**\n * Structured Error Diagnostics\n *\n * Re-exported from @lokascript/intent.\n * This module is the framework's re-export point for the diagnostic types\n * that live in the universal intent package.\n */\n\nexport type {\n DiagnosticSeverity,\n Diagnostic,\n DiagnosticResult,\n DiagnosticSummary,\n DiagnosticCollector,\n DiagnosticOptions,\n} from '@lokascript/intent';\n\nexport { createDiagnosticCollector, fromError, filterBySeverity } from '@lokascript/intent';\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/generation/pattern-generator.ts","../../src/core/types.ts","../../src/generation/renderer.ts","../../src/generation/diagnostics.ts","../../src/generation/schema-patterns.ts","../../src/generation/pattern-render.ts"],"sourcesContent":["/**\n * Pattern Generator\n *\n * Generates LanguagePattern objects from CommandSchema + LanguageProfile.\n * This solves the pattern explosion problem by deriving patterns from\n * high-level schema definitions rather than hand-writing each one.\n */\n\nimport type { LanguagePattern, PatternToken, ExtractionRule } from '../core/types';\nimport type { CommandSchema, RoleSpec } from '../schema';\n\n/**\n * Minimal language profile interface for pattern generation.\n */\nexport interface PatternGenLanguageProfile {\n readonly code: string;\n readonly wordOrder: 'SVO' | 'SOV' | 'VSO' | 'VOS' | 'OSV' | 'OVS' | 'free';\n readonly keywords: Record<string, { primary: string; alternatives?: string[] }>;\n readonly roleMarkers?: Record<\n string,\n { primary: string; alternatives?: string[]; position?: 'before' | 'after' }\n >;\n}\n\n/**\n * Configuration for pattern generation.\n */\nexport interface GeneratorConfig {\n /** Base priority for generated patterns (default: 100) */\n readonly basePriority?: number;\n /** Include optional role variants (default: true) */\n readonly includeOptionalVariants?: boolean;\n}\n\nconst defaultConfig: GeneratorConfig = {\n basePriority: 100,\n includeOptionalVariants: true,\n};\n\n/**\n * Generate a language pattern from a command schema and language profile.\n *\n * @param schema - Command schema defining the command structure\n * @param profile - Language profile with word order and keywords\n * @param config - Optional configuration\n * @returns Generated language pattern\n */\nexport function generatePattern(\n schema: CommandSchema,\n profile: PatternGenLanguageProfile,\n config: GeneratorConfig = defaultConfig\n): LanguagePattern {\n const id = `${schema.action}-${profile.code}-generated`;\n const priority = config.basePriority ?? 100;\n\n // Get keyword translation\n const keyword = profile.keywords[schema.action];\n if (!keyword) {\n throw new Error(`No keyword translation for '${schema.action}' in ${profile.code}`);\n }\n\n // Build tokens based on word order\n const tokens = buildTokens(schema, profile, keyword.primary, keyword.alternatives);\n\n // Build extraction rules\n const extraction = buildExtractionRules(schema, profile);\n\n // Build format string for documentation\n const format = buildFormatString(schema, profile, keyword.primary);\n\n return {\n id,\n language: profile.code,\n command: schema.action,\n priority,\n template: {\n format,\n tokens,\n },\n extraction,\n };\n}\n\n/**\n * Build pattern tokens based on word order and role markers.\n */\nfunction buildTokens(\n schema: CommandSchema,\n profile: PatternGenLanguageProfile,\n keyword: string,\n alternatives?: string[]\n): PatternToken[] {\n const tokens: PatternToken[] = [];\n const keywordToken: PatternToken = {\n type: 'literal',\n value: keyword,\n ...(alternatives?.length && { alternatives }),\n };\n\n // Sort roles by word order\n const sortedRoles = sortRolesByWordOrder(schema.roles, profile.wordOrder);\n\n // For SVO: [action, patient, destination, source, ...]\n if (profile.wordOrder === 'SVO') {\n // Add keyword first\n tokens.push(keywordToken);\n\n // Add roles with markers\n for (const role of sortedRoles) {\n addRoleWithMarker(tokens, role, profile);\n }\n }\n // For SOV: [patient, destination, source, ..., action, postVerb roles...]\n else if (profile.wordOrder === 'SOV') {\n // `sovSlot: 'postVerb'` moves a role AFTER the verb, which is what the\n // renderer does (`renderer.ts` buckets by the same field). Generation has\n // to mirror it: a role the renderer writes post-verb but the pattern\n // expects pre-verb produces a faithful surface its own parser drops the\n // argument from — voice's `戻る 2` re-parsing as a bare `back`.\n const preVerb: PatternToken[] = [];\n const postVerb: PatternToken[] = [];\n\n for (const role of sortedRoles) {\n addRoleWithMarker(role.sovSlot === 'postVerb' ? postVerb : preVerb, role, profile);\n }\n\n tokens.push(...preVerb, keywordToken, ...postVerb);\n }\n // For VSO: [action, destination, patient, source, ...]\n else if (profile.wordOrder === 'VSO') {\n // Add keyword first\n tokens.push(keywordToken);\n\n // Add roles with markers\n for (const role of sortedRoles) {\n addRoleWithMarker(tokens, role, profile);\n }\n }\n // Other word orders can be added as needed\n else {\n // Fallback to SVO-style ordering\n tokens.push(keywordToken);\n for (const role of sortedRoles) {\n addRoleWithMarker(tokens, role, profile);\n }\n }\n\n return tokens;\n}\n\n/**\n * Add a role token with its grammatical marker if needed.\n * For optional roles, wraps the role + marker in a group.\n */\nfunction addRoleWithMarker(\n tokens: PatternToken[],\n roleSpec: RoleSpec,\n profile: PatternGenLanguageProfile\n): void {\n const marker = getMarkerForRole(roleSpec, profile);\n const isOptional = !roleSpec.required;\n\n // Build the role token\n const roleToken: PatternToken = {\n type: 'role',\n role: roleSpec.role,\n optional: isOptional,\n expectedTypes: roleSpec.expectedTypes,\n ...(roleSpec.greedy && { greedy: true }),\n };\n\n if (marker) {\n const markerInfo = profile.roleMarkers?.[roleSpec.role];\n // Priority: schema markerPosition → profile roleMarkers position → word-order default\n const defaultPosition = profile.wordOrder === 'SOV' ? 'after' : 'before';\n const position = roleSpec.markerPosition ?? markerInfo?.position ?? defaultPosition;\n\n if (isOptional) {\n // Optional role: wrap marker + role in optional group\n if (position === 'before') {\n tokens.push({\n type: 'group',\n optional: true,\n tokens: [{ type: 'literal', value: marker }, roleToken],\n });\n } else {\n tokens.push({\n type: 'group',\n optional: true,\n tokens: [roleToken, { type: 'literal', value: marker }],\n });\n }\n } else {\n // Required role: add marker + role separately\n if (position === 'before') {\n tokens.push({ type: 'literal', value: marker });\n tokens.push(roleToken);\n } else {\n tokens.push(roleToken);\n tokens.push({ type: 'literal', value: marker });\n }\n }\n } else {\n // No marker - just add the role\n tokens.push(roleToken);\n }\n}\n\n/**\n * Get the grammatical marker for a role from the profile.\n */\nfunction getMarkerForRole(\n roleSpec: RoleSpec,\n profile: PatternGenLanguageProfile\n): string | undefined {\n // Check for role-specific override first\n if (roleSpec.markerOverride?.[profile.code]) {\n return roleSpec.markerOverride[profile.code];\n }\n\n // Use profile's default marker for this role\n return profile.roleMarkers?.[roleSpec.role]?.primary;\n}\n\n/**\n * Sort roles by word order for pattern building.\n *\n * Exported so the renderer sorts with exactly this comparator — a rendered\n * surface whose role order differs from the generated pattern would not re-parse.\n */\nexport function sortRolesByWordOrder(roles: RoleSpec[], wordOrder: string): RoleSpec[] {\n const sorted = [...roles];\n\n if (wordOrder === 'SVO') {\n // Sort by svoPosition (higher = earlier)\n sorted.sort((a, b) => (b.svoPosition ?? 0) - (a.svoPosition ?? 0));\n } else if (wordOrder === 'SOV') {\n // Sort by sovPosition (higher = earlier)\n sorted.sort((a, b) => (b.sovPosition ?? 0) - (a.sovPosition ?? 0));\n }\n // VSO and others use SVO-style ordering\n\n return sorted;\n}\n\n/**\n * Build extraction rules for capturing role values during parsing.\n */\nfunction buildExtractionRules(\n schema: CommandSchema,\n profile: PatternGenLanguageProfile\n): Record<string, ExtractionRule> {\n const rules: Record<string, ExtractionRule> = {};\n\n for (const roleSpec of schema.roles) {\n // Build the rule object correctly with readonly properties\n const marker = getMarkerForRole(roleSpec, profile);\n\n const rule: ExtractionRule = {\n ...(roleSpec.default !== undefined && { default: roleSpec.default }),\n ...(marker && { marker }),\n };\n\n rules[roleSpec.role] = rule;\n }\n\n return rules;\n}\n\n/**\n * Build a human-readable format string for the pattern.\n */\nfunction buildFormatString(\n schema: CommandSchema,\n profile: PatternGenLanguageProfile,\n keyword: string\n): string {\n const isSOV = profile.wordOrder === 'SOV';\n const preVerb: string[] = [];\n const postVerb: string[] = [];\n\n // Order roles the same way buildTokens does (descending position). Iterating\n // declaration order here would disagree with the token order whenever a\n // schema's roles are declared in a different order than their positions imply.\n const sortedRoles = sortRolesByWordOrder(schema.roles, profile.wordOrder);\n for (const role of sortedRoles) {\n const marker = getMarkerForRole(role, profile);\n const roleName = `{${role.role}}`;\n // Same pre/post-verb split buildTokens applies, so the documented format\n // string keeps describing the tokens it is generated alongside.\n const bucket = isSOV && role.sovSlot === 'postVerb' ? postVerb : preVerb;\n\n if (marker) {\n const markerInfo = profile.roleMarkers?.[role.role];\n if (markerInfo?.position === 'after') {\n bucket.push(`${roleName} ${marker}`);\n } else {\n bucket.push(`${marker} ${roleName}`);\n }\n } else {\n bucket.push(roleName);\n }\n }\n\n return (isSOV ? [...preVerb, keyword, ...postVerb] : [keyword, ...preVerb, ...postVerb]).join(\n ' '\n );\n}\n\n/**\n * Generate multiple pattern variants (with and without optional roles).\n */\nexport function generatePatternVariants(\n schema: CommandSchema,\n profile: PatternGenLanguageProfile,\n config: GeneratorConfig = defaultConfig\n): LanguagePattern[] {\n const patterns: LanguagePattern[] = [];\n\n // Main pattern (all roles)\n patterns.push(generatePattern(schema, profile, config));\n\n // TODO: Generate variants with optional roles omitted\n // This can be added later when needed\n\n return patterns;\n}\n","/**\n * Core Types — re-exported from @lokascript/intent + framework-specific extensions\n *\n * The universal semantic types (SemanticNode, SemanticValue, etc.) now live in\n * @lokascript/intent and are re-exported here for backward compatibility.\n *\n * Framework-specific types (tokenization, pattern matching) are defined below.\n */\n\n// =============================================================================\n// Re-export everything from @lokascript/intent\n// =============================================================================\n\nexport type {\n ActionType,\n SemanticRole,\n SemanticValue,\n ExpectedType,\n LiteralValue,\n SelectorValue,\n ReferenceValue,\n PropertyPathValue,\n ExpressionValue,\n FlagValue,\n Annotation,\n ProtocolDiagnostic,\n AsyncVariant,\n MatchArm,\n SemanticNode,\n SemanticMetadata,\n SourcePosition,\n CommandSemanticNode,\n EventHandlerSemanticNode,\n EventModifiers,\n ConditionalSemanticNode,\n CompoundSemanticNode,\n LoopVariant,\n LoopSemanticNode,\n LSEEnvelope,\n} from '@lokascript/intent';\n\nexport {\n createLiteral,\n createSelector,\n createReference,\n createPropertyPath,\n createExpression,\n createFlag,\n createCommandNode,\n createEventHandlerNode,\n createConditionalNode,\n createCompoundNode,\n createLoopNode,\n createTryNode,\n createAsyncNode,\n createMatchNode,\n extractValue,\n extractRoleValue,\n getRoleValue,\n} from '@lokascript/intent';\n\n// =============================================================================\n// Framework-specific types (multilingual DSL infrastructure)\n// =============================================================================\n\nimport type {\n ActionType,\n SemanticRole,\n SemanticValue,\n SelectorValue,\n ExpectedType,\n SourcePosition,\n} from '@lokascript/intent';\n\n/**\n * Token kind - categorizes what type of token this is.\n */\nexport type TokenKind =\n | 'keyword' // Command or modifier keyword\n | 'selector' // CSS selector or identifier (#id, .class, table-name)\n | 'literal' // String or number literal\n | 'particle' // Grammatical particle (を, に, من)\n | 'conjunction' // Grammatical conjunction\n | 'event-modifier' // Event modifier (.once, .debounce(300))\n | 'identifier' // Generic identifier\n | 'operator' // Operators (., +, -, etc.)\n | 'punctuation' // Punctuation (parentheses, etc.)\n | 'url'; // URL or path\n\n/**\n * A language token - the result of tokenization.\n */\nexport interface LanguageToken {\n readonly value: string;\n readonly kind: TokenKind;\n readonly position: SourcePosition;\n readonly normalized?: string;\n readonly stem?: string;\n readonly stemConfidence?: number;\n readonly metadata?: Record<string, unknown>;\n}\n\n/**\n * Token stream - provides sequential access to tokens with backtracking.\n */\nexport interface TokenStream {\n readonly tokens: readonly LanguageToken[];\n readonly language: string;\n peek(offset?: number): LanguageToken | null;\n advance(): LanguageToken;\n isAtEnd(): boolean;\n mark(): StreamMark;\n reset(mark: StreamMark): void;\n position(): number;\n}\n\nexport interface StreamMark {\n readonly position: number;\n}\n\n/**\n * Language tokenizer interface - converts text to tokens.\n */\nexport interface LanguageTokenizer {\n readonly language: string;\n readonly direction: 'ltr' | 'rtl';\n tokenize(input: string): TokenStream;\n classifyToken(token: string): TokenKind;\n}\n\n// =============================================================================\n// Pattern Matching Types\n// =============================================================================\n\nexport interface LanguagePattern {\n readonly id: string;\n readonly language: string;\n readonly command: ActionType;\n readonly priority: number;\n readonly template: PatternTemplate;\n readonly extraction: ExtractionRules;\n readonly constraints?: PatternConstraints;\n /**\n * The pattern reads a form the renderer does not write by choosing it\n * (hyperscript's wait `esperar evento {event}`: the renderer writes the event\n * word itself, before a name no table knows). The renderer skips it.\n */\n readonly parseOnly?: boolean;\n}\n\nexport interface PatternTemplate {\n readonly format: string;\n readonly tokens: PatternToken[];\n}\n\nexport type PatternToken = LiteralPatternToken | RolePatternToken | GroupPatternToken;\n\nexport interface LiteralPatternToken {\n readonly type: 'literal';\n readonly value: string;\n readonly alternatives?: string[];\n /**\n * Parse-only marker: the matcher still consumes this literal, but the\n * renderer skips it. Set when a role declares `renderOverride: { <lang>: '' }`\n * (hyperscript's fetch `from`: required to PARSE `fetch from /api`, absent from\n * the render, since `fetch from \"/api\"` is not canonical _hyperscript).\n */\n readonly renderSuppress?: boolean;\n}\n\nexport interface RolePatternToken {\n readonly type: 'role';\n readonly role: SemanticRole;\n readonly optional?: boolean;\n readonly expectedTypes?: Array<ExpectedType>;\n readonly greedy?: boolean;\n /**\n * The words the slot reads, from the schema's `RoleSpec.words` for the pattern's language (its\n * `'*'` list and the language's own): the stock reader reads the slot only from one of them.\n */\n readonly words?: readonly string[];\n /**\n * Mirrors the schema's `RoleSpec.valueShape`: the slot's surface form is\n * unambiguous on its own. Carried onto the pattern token because the value\n * reader needs it too, not just the confidence model (hyperscript's\n * `'keyword'` slots hold a fixed keyword phrase and are exempt from the\n * trailing-slot verb guard).\n */\n readonly valueShape?: 'time' | 'reference' | 'keyword' | 'object' | 'clause' | 'list';\n}\n\nexport interface GroupPatternToken {\n readonly type: 'group';\n readonly tokens: PatternToken[];\n readonly optional?: boolean;\n /**\n * The group is optional for PARSING but belongs in canonical output: the\n * marker-only groups a profile's optional case markers produce (Turkish case\n * suffixes may be dropped colloquially, so the parse accepts both forms).\n * The matcher's skeleton also requires such a group's marker after a role it\n * captures (`MatchSkeleton`).\n */\n readonly renderRequired?: boolean;\n}\n\nexport interface ExtractionRules {\n readonly [role: string]: ExtractionRule;\n}\n\nexport interface ExtractionRule {\n readonly position?: number;\n readonly marker?: string;\n readonly markerAlternatives?: string[];\n readonly transform?: (raw: string) => SemanticValue;\n readonly default?: SemanticValue;\n readonly value?: string;\n /**\n * The static `value` is an expression, as the English parse types the word\n * (hyperscript's `go back` destination), not a literal.\n */\n readonly valueIsExpression?: true;\n readonly fromRole?: string;\n}\n\nexport interface PatternConstraints {\n readonly requiredRoles?: SemanticRole[];\n readonly forbiddenRoles?: SemanticRole[];\n readonly validPatientTypes?: Array<SelectorValue['selectorKind']>;\n readonly conflictsWith?: string[];\n}\n\nexport interface PatternMatchResult {\n readonly pattern: LanguagePattern;\n readonly captured: ReadonlyMap<SemanticRole, SemanticValue>;\n readonly consumedTokens: number;\n readonly confidence: number;\n /**\n * Stream index at which each captured role's value STARTED, for callers that\n * need to re-read a slot's own span rather than the tail after it. Populated\n * on the same success path as `captured` (`MatchSkeleton`), so a role left\n * behind by a rolled-back group survives in both maps or in neither.\n */\n readonly roleStarts?: ReadonlyMap<SemanticRole, number>;\n /**\n * A source phrase hyperscript's reader found in an event HEAD (`from #btn`\n * right after the event) rather than in a pattern slot: kept out of\n * `captured`, so a fused pattern's own source group can neither overwrite it\n * nor be overwritten (`ValueReader.resultFields`).\n */\n readonly eventSource?: SemanticValue;\n}\n\nexport interface PatternMatchError {\n readonly message: string;\n readonly position: SourcePosition;\n readonly expectedPatterns?: string[];\n readonly partialMatch?: Partial<PatternMatchResult>;\n}\n","/**\n * Natural Language Renderer\n *\n * Interface and utilities for rendering SemanticNode → human-readable text\n * in any supported language. This is the inverse of parsing: it converts\n * a language-neutral semantic representation back to natural-language syntax.\n *\n * Every domain that supports `translate()` needs a renderer.\n */\n\nimport type { SemanticNode } from '../core/types';\nimport { extractRoleValue, extractValue } from '../core/types';\nimport type { CommandSchema } from '../schema';\nimport { sortRolesByWordOrder, type PatternGenLanguageProfile } from './pattern-generator';\n\n// =============================================================================\n// Renderer Interface\n// =============================================================================\n\n/**\n * Renders a SemanticNode to human-readable text in a target language.\n */\nexport interface NaturalLanguageRenderer {\n render(node: SemanticNode, language: string): string;\n}\n\n// =============================================================================\n// Renderer Helpers\n// =============================================================================\n\n/**\n * Keyword table: action → language → translated keyword.\n *\n * @example\n * ```typescript\n * const KEYWORDS: KeywordTable = {\n * select: { en: 'select', ja: '選択', es: 'seleccionar' },\n * insert: { en: 'insert', ja: '挿入', es: 'insertar' },\n * };\n * ```\n */\nexport type KeywordTable = Record<string, Record<string, string>>;\n\n/**\n * Marker table: marker name → language → translated marker.\n *\n * @example\n * ```typescript\n * const MARKERS: MarkerTable = {\n * from: { en: 'from', ja: 'から', es: 'de' },\n * into: { en: 'into', ja: 'に', es: 'en' },\n * };\n * ```\n */\nexport type MarkerTable = Record<string, Record<string, string>>;\n\n/**\n * Configuration for building a renderer from schemas and profiles.\n */\nexport interface RendererConfig {\n /** Command keyword translations per language */\n readonly keywords: KeywordTable;\n\n /** Role marker translations per language (prepositions/particles) */\n readonly markers: MarkerTable;\n\n /** Languages that use SOV word order */\n readonly sovLanguages: ReadonlySet<string>;\n\n /** Languages that use VSO word order (optional, defaults to empty) */\n readonly vsoLanguages?: ReadonlySet<string>;\n}\n\n/**\n * Look up a command keyword in the target language.\n * Falls back to the key itself if no translation found.\n */\nexport function lookupKeyword(keywords: KeywordTable, action: string, language: string): string {\n return keywords[action]?.[language] ?? action;\n}\n\n/**\n * Look up a role marker in the target language.\n * Falls back to the key itself if no translation found.\n */\nexport function lookupMarker(markers: MarkerTable, marker: string, language: string): string {\n return markers[marker]?.[language] ?? marker;\n}\n\n/**\n * Build a phrase from parts, filtering empty strings and joining with space.\n *\n * @example\n * ```typescript\n * buildPhrase('select', '', 'name', 'from', 'users')\n * // → 'select name from users'\n * ```\n */\nexport function buildPhrase(...parts: string[]): string {\n return parts.filter(Boolean).join(' ');\n}\n\n/**\n * Build keyword and marker tables from schemas and language profiles.\n * Extracts translations from the profile's keyword definitions and\n * role marker overrides.\n *\n * @example\n * ```typescript\n * const { keywords, markers } = buildTablesFromProfiles(schemas, profiles);\n * ```\n */\nexport function buildTablesFromProfiles(\n schemas: readonly CommandSchema[],\n profiles: readonly PatternGenLanguageProfile[]\n): { keywords: KeywordTable; markers: MarkerTable } {\n const keywords: KeywordTable = {};\n const markers: MarkerTable = {};\n\n // Build keyword table from profiles\n for (const profile of profiles) {\n for (const [action, kw] of Object.entries(profile.keywords)) {\n if (!keywords[action]) keywords[action] = {};\n keywords[action][profile.code] = kw.primary;\n }\n }\n\n // Build marker table from schema markerOverrides\n for (const schema of schemas) {\n for (const role of schema.roles) {\n if (role.markerOverride) {\n // Use role name as marker key\n const markerKey = role.role;\n if (!markers[markerKey]) markers[markerKey] = {};\n for (const [lang, markerText] of Object.entries(role.markerOverride)) {\n markers[markerKey][lang] = markerText;\n }\n }\n }\n }\n\n // Also extract role markers from profiles\n for (const profile of profiles) {\n if (profile.roleMarkers) {\n for (const [markerKey, markerDef] of Object.entries(profile.roleMarkers)) {\n if (!markers[markerKey]) markers[markerKey] = {};\n markers[markerKey][profile.code] = markerDef.primary;\n }\n }\n }\n\n return { keywords, markers };\n}\n\n/**\n * Detect word order from language profiles.\n * Returns sets of SOV and VSO language codes.\n */\nexport function detectWordOrders(profiles: readonly PatternGenLanguageProfile[]): {\n sovLanguages: Set<string>;\n vsoLanguages: Set<string>;\n} {\n const sovLanguages = new Set<string>();\n const vsoLanguages = new Set<string>();\n\n for (const profile of profiles) {\n if (profile.wordOrder === 'SOV') sovLanguages.add(profile.code);\n if (profile.wordOrder === 'VSO') vsoLanguages.add(profile.code);\n }\n\n return { sovLanguages, vsoLanguages };\n}\n\n/**\n * Create a basic renderer from schemas and profiles.\n *\n * This generates a renderer that handles word-order reordering automatically.\n * For each command, it constructs the output by placing the keyword and\n * role values in the correct order for the target language.\n *\n * For complex domain-specific rendering, implement `NaturalLanguageRenderer`\n * directly instead.\n *\n * @example\n * ```typescript\n * const renderer = createSchemaRenderer(schemas, profiles);\n * renderer.render(node, 'ja'); // → \"users から name 選択\"\n * ```\n */\nexport function createSchemaRenderer(\n schemas: readonly CommandSchema[],\n profiles: readonly PatternGenLanguageProfile[]\n): NaturalLanguageRenderer {\n const tables = buildRenderTables(schemas, profiles);\n\n return {\n render(node: SemanticNode, language: string): string {\n // An action with no schema still has a name — render that rather than\n // nothing. `createDomainRenderer` returns null for this case instead.\n return renderFromSchema(node, language, tables) ?? node.action;\n },\n };\n}\n\n// =============================================================================\n// Domain renderer (hand-written cases + schema fallthrough)\n// =============================================================================\n\n/**\n * Renders a SemanticNode, or returns `null` when the action cannot be rendered.\n *\n * The nullable counterpart to {@link NaturalLanguageRenderer}: `null` means \"I\n * do not know this action\", which callers can act on. A domain that signals the\n * same condition with a sentinel string forces consumers into string matching.\n */\nexport type DomainRenderFn = (node: SemanticNode, language: string) => string | null;\n\n/**\n * Configuration for {@link createDomainRenderer}.\n */\nexport interface DomainRendererConfig {\n /** Schemas for this domain's commands, including any extensions. */\n readonly schemas: readonly CommandSchema[];\n\n /** Language profiles supplying keywords and role markers. */\n readonly profiles: readonly PatternGenLanguageProfile[];\n\n /**\n * Hand-written renderers per action. These take absolute precedence over the\n * schema-driven path, so a domain's existing output is preserved byte for byte.\n *\n * An override returning `null` means \"this action cannot be rendered\" and is\n * passed straight through — it does not fall through to the schema path,\n * since a hand-written renderer knows more about its action than the schema does.\n */\n readonly overrides?: Readonly<Record<string, DomainRenderFn>>;\n}\n\n/**\n * Create a renderer that composes a domain's hand-written per-action renderers\n * with the schema-driven fallback.\n *\n * Resolution order:\n * 1. `overrides[node.action]` — the domain's own rendering, unchanged\n * 2. schema-driven rendering — any action with a schema but no hand-written case\n * 3. `null` — no override and no schema\n *\n * Step 2 is what makes a domain extensible: a consumer that adds a command\n * schema (with per-language keywords in the profiles) gets correct word order,\n * markers and keywords for free, without the domain package having to know\n * about that command.\n *\n * @example\n * ```typescript\n * const render = createDomainRenderer({\n * schemas: allSchemas,\n * profiles: allProfiles,\n * overrides: { select: renderSelect, insert: renderInsert },\n * });\n * render(node, 'ja'); // hand-written for `select`, schema-driven otherwise\n * render(bogusNode, 'en'); // → null\n * ```\n */\nexport function createDomainRenderer(config: DomainRendererConfig): DomainRenderFn {\n const { schemas, profiles, overrides } = config;\n\n // Built on first render — a domain module can construct its renderer at import\n // time without paying for table construction it may never use.\n let tables: RenderTables | undefined;\n\n return (node: SemanticNode, language: string): string | null => {\n const override = overrides?.[node.action];\n if (override) return override(node, language);\n\n tables ??= buildRenderTables(schemas, profiles);\n return renderFromSchema(node, language, tables);\n };\n}\n\n// =============================================================================\n// Shared schema-driven rendering\n// =============================================================================\n\ninterface RenderTables {\n readonly keywords: KeywordTable;\n readonly markers: MarkerTable;\n /** Marker side per role per language, from each profile's roleMarkers. */\n readonly markerPositions: Record<string, Record<string, 'before' | 'after'>>;\n readonly sovLanguages: ReadonlySet<string>;\n readonly schemaMap: ReadonlyMap<string, CommandSchema>;\n}\n\nfunction buildRenderTables(\n schemas: readonly CommandSchema[],\n profiles: readonly PatternGenLanguageProfile[]\n): RenderTables {\n const { keywords, markers } = buildTablesFromProfiles(schemas, profiles);\n const { sovLanguages } = detectWordOrders(profiles);\n\n const markerPositions: Record<string, Record<string, 'before' | 'after'>> = {};\n for (const profile of profiles) {\n for (const [role, markerDef] of Object.entries(profile.roleMarkers ?? {})) {\n if (!markerDef.position) continue;\n markerPositions[role] ??= {};\n markerPositions[role][profile.code] = markerDef.position;\n }\n }\n\n const schemaMap = new Map<string, CommandSchema>();\n for (const s of schemas) schemaMap.set(s.action, s);\n return { keywords, markers, markerPositions, sovLanguages, schemaMap };\n}\n\n/**\n * The one schema-driven rendering algorithm, shared by `createSchemaRenderer`\n * and `createDomainRenderer` so the two can never drift.\n *\n * Returns `null` when the action has no schema.\n */\nfunction renderFromSchema(\n node: SemanticNode,\n language: string,\n tables: RenderTables\n): string | null {\n const schema = tables.schemaMap.get(node.action);\n if (!schema) return null;\n\n const keyword = lookupKeyword(tables.keywords, node.action, language);\n const isSOV = tables.sovLanguages.has(language);\n\n // Order roles by their declared positions, using the SAME comparator pattern\n // generation uses. Rendering in declaration order instead would produce a\n // surface the generated pattern cannot re-parse whenever the two disagree.\n const ordered = sortRolesByWordOrder([...schema.roles], isSOV ? 'SOV' : 'SVO');\n\n // Roles rendered before the verb, and (SOV only) after it.\n const preVerb: string[] = [];\n const postVerb: string[] = [];\n\n for (const role of ordered) {\n let value = extractRoleValue(node, role.role);\n if (!value && role.default !== undefined) {\n value = String(extractValue(role.default));\n }\n // A role with no value is skipped entirely — including its marker. Emitting\n // the marker of an absent role produces dangling text (\"analyze #content as\",\n // \"#content として 分析\"), which is never valid surface syntax. This applies to\n // required roles too: a required role with no value is a malformed node, and\n // a dangling marker is a worse rendering of it than simply leaving it out.\n if (!value) continue;\n\n if (role.quoteMultiword && /\\s/.test(value) && !/^([\"']).*\\1$/.test(value)) {\n value = `\"${value}\"`;\n }\n\n // Marker resolution, most specific first. `renderOverride` for this exact\n // language is the most specific statement; `''` means \"render this role\n // bare\" (a marker that exists only to help the parser). The `'*'` key is a\n // blanket statement about the PROFILE default, so it ranks below a\n // per-language markerOverride — which is how SQL's `get` renders bare in\n // SVO languages while keeping its SOV source particles.\n const markerText =\n role.renderOverride?.[language] ??\n role.markerOverride?.[language] ??\n role.renderOverride?.['*'] ??\n tables.markers[role.role]?.[language];\n\n const markerPosition =\n role.markerPositionOverride?.[language] ??\n role.markerPosition ??\n tables.markerPositions[role.role]?.[language] ??\n (isSOV ? 'after' : 'before');\n\n const bucket = isSOV && role.sovSlot === 'postVerb' ? postVerb : preVerb;\n if (markerText && markerPosition === 'before') {\n bucket.push(markerText, value);\n } else if (markerText) {\n bucket.push(value, markerText);\n } else {\n bucket.push(value);\n }\n }\n\n return isSOV\n ? buildPhrase(...preVerb, keyword, ...postVerb)\n : buildPhrase(keyword, ...preVerb, ...postVerb);\n}\n","/**\n * Structured Error Diagnostics\n *\n * Re-exported from @lokascript/intent.\n * This module is the framework's re-export point for the diagnostic types\n * that live in the universal intent package.\n */\n\nexport type {\n DiagnosticSeverity,\n Diagnostic,\n DiagnosticResult,\n DiagnosticSummary,\n DiagnosticCollector,\n DiagnosticOptions,\n} from '@lokascript/intent';\n\nexport { createDiagnosticCollector, fromError, filterBySeverity } from '@lokascript/intent';\n","/**\n * Patterns from command schemas: the generator semantic's hyperscript parser\n * runs (domains rethink Phase 4.4, `docs-internal/DOMAINS_RETHINK.md`), moved\n * here from `@lokascript/semantic` beside the domains' own `generatePattern`\n * (`pattern-generator.ts`), which `createMultilingualDSL` still uses.\n *\n * Per command and language it builds the main pattern and its variants: the\n * simple variant (required roles only), the omit-role, widened-type and\n * required-role variants, an SOV language's verb-first fallback, and the\n * value-prefix-literal variants (`RoleSpec` / `CommandSchema` document each).\n * What differs between grammars is a hook (`SchemaPatternGrammar`); what a\n * grammar adds on top (hyperscript's fused event-handler patterns) stays in the\n * grammar's package.\n */\n\nimport type { ExtractionRule, LanguagePattern, PatternToken } from '../core/types';\nimport type { CommandSchema, RoleSpec } from '../schema';\n\n/** What differs between grammars in how a schema becomes patterns. */\nexport interface SchemaPatternGrammar {\n /**\n * How `svoPosition` / `sovPosition` sort: `'ascending'` puts the lowest first\n * (hyperscript's schemas, 1-based), `'descending'` the highest (a domain's\n * schemas, as framework's `generatePattern` reads them).\n */\n readonly positionOrder: 'ascending' | 'descending';\n}\n\n/** A role marker in a language profile. */\nexport interface SchemaPatternMarker {\n readonly primary: string;\n readonly alternatives?: string[];\n readonly position: 'before' | 'after';\n}\n\n/** What the generator reads of a language profile. */\nexport interface SchemaPatternProfile {\n readonly code: string;\n readonly wordOrder: string;\n readonly keywords: Readonly<\n Record<string, { readonly primary: string; readonly alternatives?: string[] } | undefined>\n >;\n readonly roleMarkers: Readonly<Partial<Record<string, SchemaPatternMarker>>>;\n /**\n * The language may drop its role markers colloquially (Turkish case\n * suffixes): each marker becomes an optional group that still renders.\n */\n readonly markersOptional?: boolean;\n}\n\n/** The generator, bound to a grammar (`createSchemaPatternGenerator`). */\nexport interface SchemaPatternGenerator {\n /** The main pattern for a command in a language. */\n generatePattern(\n schema: CommandSchema,\n profile: SchemaPatternProfile,\n config?: SchemaPatternConfig\n ): LanguagePattern;\n /** The command without its optional roles; null when it has none. */\n generateSimplePattern(\n schema: CommandSchema,\n profile: SchemaPatternProfile,\n config?: SchemaPatternConfig\n ): LanguagePattern | null;\n /** An SOV language's verb-first fallback; null for other word orders. */\n generateVerbFirstPattern(\n schema: CommandSchema,\n profile: SchemaPatternProfile,\n config?: SchemaPatternConfig\n ): LanguagePattern | null;\n /** The main pattern and every variant the schema and config ask for. */\n generatePatternVariants(\n schema: CommandSchema,\n profile: SchemaPatternProfile,\n config?: SchemaPatternConfig\n ): LanguagePattern[];\n /** The token(s) of one role: its value slot and marker, in the language's order. */\n buildRoleToken(roleSpec: RoleSpec, profile: SchemaPatternProfile): PatternToken[];\n}\n\n/** A generator for the grammar's schemas. */\nexport function createSchemaPatternGenerator(\n grammar: SchemaPatternGrammar\n): SchemaPatternGenerator {\n return {\n generatePattern: (schema, profile, config) => generatePattern(grammar, schema, profile, config),\n generateSimplePattern: (schema, profile, config) =>\n generateSimplePattern(grammar, schema, profile, config),\n generateVerbFirstPattern: (schema, profile, config) =>\n generateVerbFirstPattern(schema, profile, config),\n generatePatternVariants: (schema, profile, config) =>\n generatePatternVariants(grammar, schema, profile, config),\n buildRoleToken,\n };\n}\n\n/** The schema without its variant-only roles: what every pattern but a required-role variant is built from. */\nexport function withoutVariantOnlyRoles<S extends CommandSchema>(schema: S): S {\n return schema.roles.some(r => r.variantOnly)\n ? { ...schema, roles: schema.roles.filter(r => !r.variantOnly) }\n : schema;\n}\n\n/**\n * Roles in the grammar's position order for the word order (a stable sort).\n * Each order keeps the rule its generator always had for a role with no\n * position: 99 ascending (semantic's `sortRolesByWordOrder`), 0 descending\n * (framework's `sortRolesByWordOrder`).\n */\nfunction sortRolesByPosition<T extends Pick<RoleSpec, 'svoPosition' | 'sovPosition'>>(\n roles: readonly T[],\n wordOrder: string,\n order: SchemaPatternGrammar['positionOrder']\n): T[] {\n const sortKey = wordOrder === 'SOV' ? 'sovPosition' : 'svoPosition';\n return [...roles].sort((a, b) =>\n order === 'ascending'\n ? (a[sortKey] ?? 99) - (b[sortKey] ?? 99)\n : (b[sortKey] ?? 0) - (a[sortKey] ?? 0)\n );\n}\n\n/**\n * Minimum interface for role specs that can have marker resolution.\n * Compatible with the RoleSpec type from command-schemas.\n */\nexport interface RoleSpecWithMarker {\n role: string;\n markerOverride?: Record<string, string | undefined>;\n markerLegacy?: Record<string, readonly string[]>;\n markerVariants?: Record<string, readonly string[]>;\n methodCarrier?: string;\n}\n\n/**\n * Resolved marker information for a role.\n */\nexport interface ResolvedMarker {\n /** Primary marker string (may be empty string for no marker) */\n primary: string;\n /** Alternative markers */\n alternatives?: string[];\n /** Position relative to role value */\n position: 'before' | 'after';\n /** Whether this is an override marker */\n isOverride: boolean;\n}\n\n/**\n * Resolve the marker for a role in a specific language.\n *\n * Checks for command-specific marker overrides first,\n * then falls back to the default marker from the language profile.\n *\n * @param roleSpec Role specification with optional override\n * @param profile Language profile with role markers\n * @returns Resolved marker info, or null if no marker\n */\nexport function resolveMarkerForRole(\n roleSpec: RoleSpecWithMarker,\n profile: SchemaPatternProfile\n): ResolvedMarker | null {\n // Check for command-specific marker override first\n const overrideMarker = roleSpec.markerOverride?.[profile.code];\n const defaultMarker = profile.roleMarkers[roleSpec.role];\n\n if (overrideMarker !== undefined) {\n // Use override marker (can be empty string to suppress default marker).\n // markerLegacy entries stay accepted, so correcting an override does not\n // stop the marker a previous release rendered from parsing.\n const alternatives = legacyMarkerAlternatives(roleSpec, profile.code, overrideMarker);\n return {\n primary: overrideMarker,\n ...(alternatives && { alternatives }),\n position: defaultMarker?.position ?? 'before',\n isOverride: true,\n };\n }\n\n if (defaultMarker && defaultMarker.primary) {\n const result: ResolvedMarker = {\n primary: defaultMarker.primary,\n position: defaultMarker.position,\n isOverride: false,\n };\n if (defaultMarker.alternatives) {\n result.alternatives = defaultMarker.alternatives;\n }\n return result;\n }\n\n return null;\n}\n\n/**\n * Alternatives an OVERRIDE marker accepts: the role's {@link RoleSpecWithMarker.markerLegacy}\n * entries for this language, minus the override itself.\n *\n * Every generator that resolves a marker has its own override branch, and each\n * one used to drop alternatives entirely — so correcting a marker silently\n * stopped the previous one parsing. This is the single definition of what an\n * override still accepts; call it from each of those branches.\n *\n * Prefer {@link schemaMarkerAlternatives}, which also merges `markerVariants`.\n * This narrower entry point remains for callers that must exclude variants.\n */\nexport function legacyMarkerAlternatives(\n roleSpec: RoleSpecWithMarker,\n languageCode: string,\n overrideMarker: string\n): string[] | undefined {\n const legacy = roleSpec.markerLegacy?.[languageCode];\n if (!legacy?.length) return undefined;\n const alternatives = [...new Set(legacy)].filter(a => a && a !== overrideMarker);\n return alternatives.length ? alternatives : undefined;\n}\n\n/**\n * Every schema-declared alternative a role's marker accepts in this language:\n * `markerLegacy` ∪ `markerVariants`, minus the marker itself.\n *\n * **The single definition — call it from every branch of every generator.** The\n * two fields used to sit on DIFFERENT branches: the override branch read only\n * `markerLegacy`, the profile-default branch only `markerVariants`. So giving a\n * language a `markerOverride` silently deleted its `markerVariants`, and giving\n * it `markerVariants` did nothing at all wherever an override existed. Both\n * halves were live: tr `set`'s dative allomorphs (`e|a|ye|ya`) were declared as\n * variants but dropped by the tr override, so `… doğru ya ayarla` parsed only\n * inside an event handler — the one generator that happened to merge both.\n *\n * `markerVariants` are held out for a role with a {@link RoleSpecWithMarker.methodCarrier}:\n * there they are not synonyms but distinct command shapes recorded into another\n * role (`put`'s `into|before|after` → `method`), and merging them as synonyms is\n * what broke `put-before`/`put-after` in 23 languages at once. That flag is the\n * discriminator because it is set on exactly the role whose variants carry\n * meaning — pinned by `schema-consistency.test.ts`, which fails if a new\n * `markerVariants` appears without that decision being made.\n */\nexport function schemaMarkerAlternatives(\n roleSpec: RoleSpecWithMarker,\n languageCode: string,\n marker: string\n): string[] | undefined {\n const legacy = roleSpec.markerLegacy?.[languageCode] ?? [];\n const variants = roleSpec.methodCarrier ? [] : (roleSpec.markerVariants?.[languageCode] ?? []);\n const alternatives = [...new Set([...legacy, ...variants])].filter(a => a && a !== marker);\n return alternatives.length ? alternatives : undefined;\n}\n\n/**\n * Configuration for pattern generation.\n */\nexport interface SchemaPatternConfig {\n /** Base priority for generated patterns (higher = checked first) */\n basePriority?: number;\n /** Whether to generate simple patterns (without optional roles) */\n generateSimpleVariants?: boolean;\n /** Whether to generate alternative keyword patterns */\n generateAlternatives?: boolean;\n /**\n * Whether to generate verb-first fallback patterns for SOV languages\n * (`トグル .active` alongside the canonical `.active を トグル`). Default on.\n * These are strictly lower priority than the canonical patterns, so native\n * SOV order always wins; this only accepts bilingual/code-switched input.\n */\n generateVerbFirstVariants?: boolean;\n}\n\nconst defaultConfig: SchemaPatternConfig = {\n basePriority: 100,\n generateSimpleVariants: true,\n generateAlternatives: true,\n};\n\n/**\n * Generate a pattern for a command in a specific language.\n */\nfunction generatePattern(\n grammar: SchemaPatternGrammar,\n schema: CommandSchema,\n profile: SchemaPatternProfile,\n config: SchemaPatternConfig = defaultConfig\n): LanguagePattern {\n const id = `${schema.action}-${profile.code}-generated`;\n const priority = config.basePriority ?? 100;\n\n // Get keyword translation\n const keyword = profile.keywords[schema.action];\n if (!keyword) {\n throw new Error(`No keyword translation for '${schema.action}' in ${profile.code}`);\n }\n\n // Build tokens based on word order\n const tokens = buildTokens(grammar, schema, profile, keyword);\n\n // Build extraction rules with defaults for optional roles\n // This ensures defaults are applied even when optional groups don't match\n const extraction = buildExtractionRulesWithDefaults(schema, profile);\n\n // Build template format string (for documentation)\n const format = buildFormatString(grammar, schema, profile, keyword);\n\n return {\n id,\n language: profile.code,\n command: schema.action,\n priority,\n template: {\n format,\n tokens,\n },\n extraction,\n };\n}\n\n/**\n * Generate a simple variant pattern (without optional roles).\n */\nfunction generateSimplePattern(\n grammar: SchemaPatternGrammar,\n schema: CommandSchema,\n profile: SchemaPatternProfile,\n config: SchemaPatternConfig = defaultConfig\n): LanguagePattern | null {\n // Only generate simple variant if there are optional roles\n const optionalRoles = schema.roles.filter(r => !r.required);\n if (optionalRoles.length === 0) {\n return null;\n }\n\n const requiredRoles = schema.roles.filter(r => r.required);\n const simpleSchema: CommandSchema = {\n ...schema,\n roles: requiredRoles,\n };\n\n const pattern = generatePattern(grammar, simpleSchema, profile, config);\n\n // Adjust for simple variant\n return {\n ...pattern,\n id: `${schema.action}-${profile.code}-generated-simple`,\n priority: (config.basePriority ?? 100) - 5, // Lower priority than full pattern (was -10)\n extraction: buildExtractionRulesWithDefaults(schema, profile),\n };\n}\n\n/**\n * Generate a verb-first fallback pattern for an SOV language.\n *\n * Canonical SOV order is patient-then-verb (`.active を トグル`). Bilingual and\n * code-switching authors often write the English/loanword verb first\n * (`トグル .active`). This emits `[verb] [required role(s), UNMARKED]` at a lower\n * priority so the canonical pattern always wins for native input — the\n * verb-first form only matches when the input genuinely starts with the verb.\n *\n * Kept deliberately conservative: only commands with a single required role\n * (patient-focused: toggle/add/remove/show/hide/…) get this fallback, which\n * keeps the unmarked match unambiguous. Returns null otherwise.\n */\nfunction generateVerbFirstPattern(\n schema: CommandSchema,\n profile: SchemaPatternProfile,\n config: SchemaPatternConfig = defaultConfig\n): LanguagePattern | null {\n if (profile.wordOrder !== 'SOV') return null;\n\n const requiredRoles = schema.roles.filter(r => r.required);\n if (requiredRoles.length !== 1) return null;\n\n const keyword = profile.keywords[schema.action];\n if (!keyword) return null;\n\n const verbToken: PatternToken = keyword.alternatives\n ? { type: 'literal', value: keyword.primary, alternatives: keyword.alternatives }\n : { type: 'literal', value: keyword.primary };\n\n // Verb first, then the required role(s) with NO marker (the marker is what\n // disambiguates roles in canonical SOV; verb-first input typically omits it).\n // A valuePrefixLiteral (rolePrefixLiteralVariants clones only) still precedes\n // its role's value — the SOV transformer renders `移動 url \"/page\" に`\n // verb-first, which is exactly this shape (trailing particle tolerated).\n const roleTokens: PatternToken[] = requiredRoles.flatMap(r => {\n const prefix = r.valuePrefixLiteral?.[profile.code];\n const words = wordsFor(r, profile.code);\n const roleToken: PatternToken = {\n type: 'role',\n role: r.role,\n optional: false,\n expectedTypes: r.expectedTypes,\n ...(words ? { words } : {}),\n };\n return prefix ? [{ type: 'literal', value: prefix } as PatternToken, roleToken] : [roleToken];\n });\n\n return {\n id: `${schema.action}-${profile.code}-generated-verb-first`,\n language: profile.code,\n command: schema.action,\n // Strictly below the canonical (basePriority) and simple (basePriority - 5)\n // patterns so native order is always preferred.\n priority: (config.basePriority ?? 100) - 20,\n template: {\n format: `${keyword.primary} <${requiredRoles[0].role}>`,\n tokens: [verbToken, ...roleTokens],\n },\n extraction: buildExtractionRulesWithDefaults(schema, profile),\n };\n}\n\n/**\n * Generate all pattern variants for a command in a language.\n */\nfunction generatePatternVariants(\n grammar: SchemaPatternGrammar,\n schema: CommandSchema,\n profile: SchemaPatternProfile,\n config: SchemaPatternConfig = defaultConfig\n): LanguagePattern[] {\n const patterns: LanguagePattern[] = [];\n // A variant-only role is in the required-role variants alone.\n const full = schema;\n schema = withoutVariantOnlyRoles(schema);\n\n // Main pattern\n patterns.push(generatePattern(grammar, schema, profile, config));\n\n // Simple variant (without optional roles)\n if (config.generateSimpleVariants) {\n const simple = generateSimplePattern(grammar, schema, profile, config);\n if (simple) {\n patterns.push(simple);\n }\n }\n\n // Omit-role variants: an EXTRA pattern per schema-listed role with that\n // role (and its marker phrase) removed entirely. Covers a REQUIRED role\n // whose phrase is legitimately absent in valid hyperscript (transition's\n // goal: `transition *max-height over 300ms`, slide-toggle) — making the\n // role optional inside the main pattern is the verified skippable-group\n // re-binding regression (see the transition goal NOTE); a separate variant\n // has no skippable group at all. Priority sits below the simple variant so\n // any text carrying the role phrase always prefers the fuller patterns.\n for (const omitted of schema.omitRoleVariants ?? []) {\n const variantSchema: CommandSchema = {\n ...schema,\n roles: schema.roles.filter(r => r.role !== omitted),\n };\n const variant = generatePattern(grammar, variantSchema, profile, config);\n patterns.push({\n ...variant,\n id: `${schema.action}-${profile.code}-generated-no-${omitted}`,\n priority: (config.basePriority ?? 100) - 8,\n });\n }\n\n // Widened-type variants: an EXTRA pattern per entry whose named role accepts a\n // wider set of value types. Deliberately BELOW every command pattern, so it is\n // inert on any span a real command can claim — see the schema field's doc for\n // the ko `transition opacity to 0` collision that rules out widening the main\n // pattern in place.\n for (const widen of schema.widenTypeVariants ?? []) {\n if (widen.excludeLanguages?.includes(profile.code)) continue;\n const cloneSchema: CommandSchema = {\n ...schema,\n roles: schema.roles.map(r =>\n r.role === widen.role ? { ...r, expectedTypes: [...widen.types] } : r\n ),\n };\n const main = generatePattern(grammar, cloneSchema, profile, config);\n patterns.push({\n ...main,\n id: `${schema.action}-${profile.code}-generated-${widen.idSuffix}`,\n priority: (config.basePriority ?? 100) - (widen.priorityDelta ?? 15),\n });\n }\n\n // Required-role variants: inert unless the role's marker is present, so they\n // may outrank the command's other patterns (see the schema field).\n for (const v of full.requiredRoleVariants ?? []) {\n const variantSchema: CommandSchema = {\n ...full,\n roles: full.roles\n .filter(r => !v.omit?.includes(r.role))\n .map(r => {\n const required = r.role === v.role ? { ...r, required: true } : r;\n return r.role === v.widen?.role\n ? { ...required, expectedTypes: [...v.widen.types] }\n : required;\n }),\n };\n const variant = generatePattern(grammar, variantSchema, profile, config);\n patterns.push({\n ...variant,\n id: `${schema.action}-${profile.code}-generated-${v.idSuffix}`,\n priority: (config.basePriority ?? 100) + (v.priorityDelta ?? 5),\n });\n }\n\n // Verb-first fallback for SOV languages (lower priority than the above).\n if (config.generateVerbFirstVariants !== false) {\n const verbFirst = generateVerbFirstPattern(schema, profile, config);\n if (verbFirst) {\n patterns.push(verbFirst);\n }\n }\n\n // Value-prefix-literal variants: an EXTRA pattern per entry with a REQUIRED\n // literal keyword immediately before the named role's value (`go [to] url\n // {destination}`). Higher priority than the counterpart pattern, but inert\n // unless the keyword is present — base patterns above stay byte-identical,\n // so forms riding on them (`go back`) cannot regress. The matched keyword is\n // recorded as a fixed-value literal in the variant's methodCarrier role.\n for (const v of schema.rolePrefixLiteralVariants ?? []) {\n const literal = v.literal[profile.code];\n if (!literal) continue;\n const { rolePrefixLiteralVariants: _omitted, ...baseSchema } = schema;\n const cloneSchema: CommandSchema = {\n ...baseSchema,\n roles: schema.roles.map(r =>\n r.role === v.role ? { ...r, valuePrefixLiteral: { [profile.code]: literal } } : r\n ),\n };\n const delta = v.priorityDelta ?? 5;\n const carrier: Record<string, ExtractionRule> = v.methodCarrier\n ? { [v.methodCarrier]: { value: literal } }\n : {};\n const main = generatePattern(grammar, cloneSchema, profile, config);\n patterns.push({\n ...main,\n id: `${schema.action}-${profile.code}-generated-${v.idSuffix}`,\n priority: (config.basePriority ?? 100) + delta,\n extraction: { ...main.extraction, ...carrier },\n });\n if (config.generateVerbFirstVariants !== false) {\n const verbFirstUrl = generateVerbFirstPattern(cloneSchema, profile, config);\n if (verbFirstUrl) {\n patterns.push({\n ...verbFirstUrl,\n id: `${schema.action}-${profile.code}-generated-verb-first-${v.idSuffix}`,\n priority: (config.basePriority ?? 100) - 20 + delta,\n extraction: { ...verbFirstUrl.extraction, ...carrier },\n });\n }\n }\n }\n\n return patterns;\n}\n\n/**\n * Build pattern tokens based on word order.\n */\nfunction buildTokens(\n grammar: SchemaPatternGrammar,\n schema: CommandSchema,\n profile: SchemaPatternProfile,\n keyword: { primary: string; alternatives?: string[] }\n): PatternToken[] {\n const tokens: PatternToken[] = [];\n\n // Get verb token\n const verbToken: PatternToken = keyword.alternatives\n ? { type: 'literal', value: keyword.primary, alternatives: keyword.alternatives }\n : { type: 'literal', value: keyword.primary };\n\n // Get role tokens sorted by position. In SOV a role with `sovSlot: 'postVerb'`\n // follows the verb (a domain's summarize format: `content 要約 として format`).\n const postVerbRoles =\n profile.wordOrder === 'SOV' ? schema.roles.filter(r => r.sovSlot === 'postVerb') : [];\n const roleTokens = buildRoleTokens(\n grammar,\n postVerbRoles.length\n ? { ...schema, roles: schema.roles.filter(r => r.sovSlot !== 'postVerb') }\n : schema,\n profile\n );\n const postVerbTokens = postVerbRoles.length\n ? buildRoleTokens(grammar, { ...schema, roles: postVerbRoles }, profile)\n : [];\n\n // Arrange based on word order\n switch (profile.wordOrder) {\n case 'SVO':\n // Verb first, then roles in order\n tokens.push(verbToken);\n tokens.push(...roleTokens);\n break;\n\n case 'SOV':\n // Roles first (reversed for SOV), then verb\n tokens.push(...roleTokens);\n tokens.push(verbToken);\n tokens.push(...postVerbTokens);\n break;\n\n case 'VSO':\n // Verb first, then subject, then object\n tokens.push(verbToken);\n tokens.push(...roleTokens);\n break;\n\n default:\n // Default to SVO\n tokens.push(verbToken);\n tokens.push(...roleTokens);\n }\n\n return collapseAdjacentLiterals(tokens);\n}\n\n/**\n * Collapse adjacent identical literal tokens into one.\n *\n * For the event-handler trigger (`on`) schema, a handful of languages use the\n * same word for the trigger keyword (the `on` verb) and the event role's marker —\n * bn `তে`, hi `पर`, th `เมื่อ`. `buildTokens` then emits it twice (`<event> তে তে`),\n * which the renderer prints verbatim; on re-parse the duplicate pairs with the\n * following token as a phantom command (e.g. `তে আমি` → a spurious `on me`). No\n * trigger pattern needs to match the same literal twice in a row, so fold the\n * duplicate, preserving any `alternatives` from either side. Verified to affect\n * only the `on` patterns of bn/hi/th — no other command/language has adjacent\n * duplicate literals. See MULTILINGUAL_BEHAVIORS_PLAN.md Phase 2.\n */\nfunction collapseAdjacentLiterals(tokens: PatternToken[]): PatternToken[] {\n const out: PatternToken[] = [];\n for (const tok of tokens) {\n const prev = out[out.length - 1];\n if (prev && prev.type === 'literal' && tok.type === 'literal' && prev.value === tok.value) {\n const alts = [...(prev.alternatives ?? []), ...(tok.alternatives ?? [])];\n if (alts.length) out[out.length - 1] = { ...prev, alternatives: [...new Set(alts)] };\n continue;\n }\n out.push(tok);\n }\n return out;\n}\n\n/**\n * Build tokens for roles.\n */\nfunction buildRoleTokens(\n grammar: SchemaPatternGrammar,\n schema: CommandSchema,\n profile: SchemaPatternProfile\n): PatternToken[] {\n const tokens: PatternToken[] = [];\n\n // Sort roles by position using shared utility\n const sortedRoles = sortRolesByPosition(schema.roles, profile.wordOrder, grammar.positionOrder);\n\n for (const roleSpec of sortedRoles) {\n const roleToken = buildRoleToken(roleSpec, profile);\n\n if (!roleSpec.required) {\n // Wrap optional roles in a group\n tokens.push({\n type: 'group',\n optional: true,\n tokens: roleToken,\n });\n } else {\n tokens.push(...roleToken);\n }\n }\n\n return tokens;\n}\n\n/**\n * Build token(s) for a single role.\n *\n * Exported so the fused event-handler generators can build a wrapped command's\n * optional-role slots from the very same code the standalone command patterns\n * use — a hand-rolled copy there is what let the two drift apart in the first\n * place (see `appendRemainingOptionalRoles` in event-handlers-sov.ts).\n */\n/** The words a role reads in `language` (`RoleSpec.words`: its `'*'` list and the language's own). */\nfunction wordsFor(roleSpec: RoleSpec, language: string): readonly string[] | undefined {\n if (!roleSpec.words) return undefined;\n const words = [...(roleSpec.words['*'] ?? []), ...(roleSpec.words[language] ?? [])];\n return words.length > 0 ? words : undefined;\n}\n\nfunction buildRoleToken(roleSpec: RoleSpec, profile: SchemaPatternProfile): PatternToken[] {\n const tokens: PatternToken[] = [];\n\n // Check for command-specific marker override first\n const overrideMarker = roleSpec.markerOverride?.[profile.code];\n const defaultMarker = profile.roleMarkers[roleSpec.role];\n\n // A role whose renderOverride is the empty string parses WITH its marker but\n // renders WITHOUT it (e.g. fetch's `from`: `fetch from /api` must parse, yet\n // canonical _hyperscript rejects `fetch from \"/api\"` while accepting\n // `fetch \"/api\"`). Tag the emitted marker literal so the renderer skips it;\n // the pattern matcher ignores the flag, so parsing is unchanged.\n const suppressMarker = roleSpec.renderOverride?.[profile.code] === '';\n const words = wordsFor(roleSpec, profile.code);\n\n // Role value token\n const roleValueToken: PatternToken = {\n type: 'role',\n role: roleSpec.role,\n optional: !roleSpec.required,\n expectedTypes: roleSpec.expectedTypes,\n // The matcher reads this too — a `'keyword'`-shaped slot holds a fixed\n // keyword phrase (`using view transition`) and must not be skipped by the\n // trailing-slot verb guard.\n ...(roleSpec.valueShape !== undefined ? { valueShape: roleSpec.valueShape } : {}),\n // A greedy role reads up to the next marker the pattern owes (a domain's\n // SQL condition); its value reader does the reading.\n ...(roleSpec.greedy ? { greedy: true } : {}),\n // A role with a word list reads only one of its words.\n ...(words ? { words } : {}),\n };\n\n // Required literal immediately before the role VALUE (rolePrefixLiteralVariants\n // clones only): `[to] url {destination}`, `url {destination} に`. Deliberately\n // NOT an optional group — the variant must only match when the keyword is\n // present, so base patterns keep winning everywhere else.\n const prefixLiteral = roleSpec.valuePrefixLiteral?.[profile.code];\n const pushPrefixed = (): void => {\n if (prefixLiteral) tokens.push({ type: 'literal', value: prefixLiteral });\n tokens.push(roleValueToken);\n };\n\n // Use override marker if available, otherwise use default\n if (overrideMarker !== undefined) {\n // Command-specific marker override. Multi-word markers (e.g. \"partials in\",\n // \"with title\") split into one literal token per word so the matcher\n // consumes them sequentially. A per-command markerOptional wraps each word\n // in an optional group (`go to /page` and `go back` both parse — the\n // render side drops the preposition, so the parse side can't require it).\n const markerWords = overrideMarker ? overrideMarker.split(/\\s+/).filter(Boolean) : [];\n // Where the profile carries no RoleMarker for this role there is nothing to\n // take a side from, and 'before' is wrong in a verb-final language: ja\n // rendered `opacity を に 0` and bn `opacity কে তে 0`, the override marker\n // stranded AHEAD of its own value. Default to 'after' for SOV.\n //\n // EXEMPT a PASSTHROUGH override — one whose marker is the same string en\n // uses (`scope`, `manner`). Those are English words carried verbatim into\n // every language, so they keep English's prepositional side; without the\n // exemption ja/ko/qu lose `set`'s scope.\n const isPassthroughOverride =\n overrideMarker !== undefined && overrideMarker === roleSpec.markerOverride?.en;\n const position =\n roleSpec.markerPositionOverride?.[profile.code] ??\n roleSpec.markerPosition ??\n defaultMarker?.position ??\n (profile.wordOrder === 'SOV' && !isPassthroughOverride ? 'after' : 'before');\n const optionalMarker = roleSpec.markerOptional?.[profile.code] === true;\n // Single-word overrides also accept every schema-declared alternative\n // (markerLegacy ∪ markerVariants), so correcting an override's marker does\n // not stop the previous one parsing, and declaring an override does not\n // silently delete that language's variants. schemaMarkerAlternatives holds\n // variants out for a methodCarrier role (`put`'s before/after) — see its doc.\n const pushWord = (word: string): void => {\n const alternatives =\n markerWords.length === 1\n ? (schemaMarkerAlternatives(roleSpec, profile.code, word) ?? [])\n : [];\n const literal: PatternToken = {\n type: 'literal',\n value: word,\n ...(alternatives.length ? { alternatives } : {}),\n ...(suppressMarker ? { renderSuppress: true } : {}),\n };\n tokens.push(optionalMarker ? { type: 'group', optional: true, tokens: [literal] } : literal);\n };\n if (position === 'before') {\n for (const word of markerWords) pushWord(word);\n pushPrefixed();\n } else {\n pushPrefixed();\n for (const word of markerWords) pushWord(word);\n }\n } else if (defaultMarker) {\n // When the profile allows colloquial marker-dropping, the marker becomes an\n // optional group so `.active değiştir` parses as well as `.active i değiştir`.\n // The marked form still matches the marker literal directly (higher\n // confidence); the unmarked form falls back through the optional group.\n // The schema's markerVariants/markerLegacy merge in as extra alternatives:\n // the transformer can render a role with a particle the profile default\n // doesn't cover (zh 把 before go's destination in `go back`).\n const asMarker = (): PatternToken => {\n const alternatives = [\n ...new Set([\n ...(defaultMarker.alternatives ?? []),\n ...(schemaMarkerAlternatives(roleSpec, profile.code, defaultMarker.primary) ?? []),\n ]),\n ].filter(a => a !== defaultMarker.primary);\n return {\n type: 'literal',\n value: defaultMarker.primary,\n ...(alternatives.length ? { alternatives } : {}),\n ...(suppressMarker ? { renderSuppress: true } : {}),\n };\n };\n const pushMarker = (marker: PatternToken): void => {\n if (!profile.markersOptional && !roleSpec.markerOptional?.[profile.code]) {\n tokens.push(marker);\n return;\n }\n // A profile-wide `markersOptional` says the marker may be DROPPED\n // colloquially, not that it is absent from canonical output — so the group\n // still renders. A per-role `markerOptional` is the opposite: the render\n // side genuinely omits that marker (`go to /page` vs `go back`), so it\n // stays render-optional too.\n tokens.push({\n type: 'group',\n optional: true,\n ...(profile.markersOptional && !roleSpec.markerOptional?.[profile.code]\n ? { renderRequired: true }\n : {}),\n tokens: [marker],\n });\n };\n // A schema's own side for the role (a domain's `markerPosition`) outranks the profile's.\n if ((roleSpec.markerPosition ?? defaultMarker.position) === 'before') {\n // Preposition: \"on #button\"\n if (defaultMarker.primary) {\n pushMarker(asMarker());\n }\n pushPrefixed();\n } else {\n // Postposition/particle: \"#button に\"\n pushPrefixed();\n pushMarker(asMarker());\n }\n } else {\n // No marker, just the role value\n pushPrefixed();\n }\n\n return tokens;\n}\n\n// =============================================================================\n// Extraction Rules Building\n// =============================================================================\n\n/**\n * Build extraction rules for a pattern.\n */\nfunction buildExtractionRules(\n schema: CommandSchema,\n profile: SchemaPatternProfile\n): Record<string, ExtractionRule> {\n const rules: Record<string, ExtractionRule> = {};\n\n for (const roleSpec of schema.roles) {\n // Check for command-specific marker override first\n const overrideMarker = roleSpec.markerOverride?.[profile.code];\n const defaultMarker = profile.roleMarkers[roleSpec.role];\n\n if (roleSpec.valuePrefixLiteral?.[profile.code]) {\n // The prefix literal sits immediately before the value on every surface,\n // so it is the extraction anchor (push/replace's proven `url` shape) —\n // it wins over the role's own marker (`to`), which may be optional/absent.\n rules[roleSpec.role] = { marker: roleSpec.valuePrefixLiteral[profile.code] };\n } else if (overrideMarker !== undefined) {\n // Use the override marker, accepting the schema's declared alternatives\n // so a corrected marker does not stop the previous one parsing and an\n // override does not delete that language's variants (mirrors\n // buildRoleToken; single-word overrides only, as a multi-word marker has\n // no single token to swap).\n if (!overrideMarker) {\n rules[roleSpec.role] = {};\n } else {\n const isSingleWord = !/\\s/.test(overrideMarker.trim());\n const markerAlternatives = isSingleWord\n ? (schemaMarkerAlternatives(roleSpec, profile.code, overrideMarker) ?? [])\n : [];\n rules[roleSpec.role] = markerAlternatives.length\n ? { marker: overrideMarker, markerAlternatives }\n : { marker: overrideMarker };\n }\n } else if (defaultMarker && defaultMarker.primary) {\n // Merge the schema's declared alternatives (mirrors buildRoleToken)\n const markerAlternatives = [\n ...new Set([\n ...(defaultMarker.alternatives ?? []),\n ...(schemaMarkerAlternatives(roleSpec, profile.code, defaultMarker.primary) ?? []),\n ]),\n ].filter(a => a !== defaultMarker.primary);\n rules[roleSpec.role] = markerAlternatives.length\n ? { marker: defaultMarker.primary, markerAlternatives }\n : { marker: defaultMarker.primary };\n } else {\n rules[roleSpec.role] = {};\n }\n }\n\n return rules;\n}\n\n/**\n * Build extraction rules with defaults for optional roles.\n */\nfunction buildExtractionRulesWithDefaults(\n schema: CommandSchema,\n profile: SchemaPatternProfile\n): Record<string, ExtractionRule> {\n const baseRules = buildExtractionRules(schema, profile);\n const rules: Record<string, ExtractionRule> = {};\n\n // Copy base rules and add defaults for optional roles\n for (const roleSpec of schema.roles) {\n const baseRule = baseRules[roleSpec.role] || {};\n\n if (!roleSpec.required && roleSpec.default) {\n rules[roleSpec.role] = { ...baseRule, default: roleSpec.default };\n } else {\n rules[roleSpec.role] = baseRule;\n }\n }\n\n return rules;\n}\n\n// =============================================================================\n// Format String Building\n// =============================================================================\n\n/**\n * Build a human-readable format string for documentation.\n */\nfunction buildFormatString(\n grammar: SchemaPatternGrammar,\n schema: CommandSchema,\n profile: SchemaPatternProfile,\n keyword: { primary: string }\n): string {\n const parts: string[] = [];\n\n // Sort roles by position using shared utility\n const sortedRoles = sortRolesByPosition(schema.roles, profile.wordOrder, grammar.positionOrder);\n\n // Build role parts\n const roleParts = sortedRoles.map(roleSpec => {\n // Use shared marker resolution utility\n const resolved = resolveMarkerForRole(roleSpec, profile);\n let part = '';\n\n if (resolved && resolved.primary) {\n // Has a marker\n if (resolved.position === 'before') {\n part = `${resolved.primary} {${roleSpec.role}}`;\n } else {\n part = `{${roleSpec.role}} ${resolved.primary}`;\n }\n } else {\n // No marker\n part = `{${roleSpec.role}}`;\n }\n\n return roleSpec.required ? part : `[${part}]`;\n });\n\n // Arrange based on word order\n switch (profile.wordOrder) {\n case 'SVO':\n case 'VSO':\n parts.push(keyword.primary, ...roleParts);\n break;\n case 'SOV':\n parts.push(...roleParts, keyword.primary);\n break;\n default:\n parts.push(keyword.primary, ...roleParts);\n }\n\n return parts.join(' ');\n}\n","/**\n * Rendering a command through a language's own patterns: the renderer core\n * semantic's hyperscript renderer runs (domains rethink Phase 4.5,\n * `docs-internal/DOMAINS_RETHINK.md`), moved here from `@lokascript/semantic`.\n *\n * A node renders with the pattern its parser would read it back through:\n * `selectRenderPattern` scores a language's patterns for the node (the roles it\n * carries, the slots each pattern has, the values a pattern pins), and\n * `renderPattern` walks the chosen pattern's tokens. What a value looks like in\n * the language, and the grammar's preferences, are `PatternRenderHooks`.\n * (The domains' `renderer.ts` renders from the schema instead, for\n * `createMultilingualDSL`.)\n */\n\nimport type {\n ExtractionRule,\n GroupPatternToken,\n LanguagePattern,\n PatternToken,\n RolePatternToken,\n SemanticNode,\n} from '../core/types';\n\n/**\n * What the core reads of a node: its roles. A grammar's own node type (semantic's\n * `SemanticNode`) qualifies as it is; the hooks receive it unchanged.\n */\nexport interface RenderableNode {\n readonly roles: ReadonlyMap<string, { readonly type: string }>;\n}\n\n/** A grammar's part of rendering through patterns, for its node type `N`. */\nexport interface PatternRenderHooks<N extends RenderableNode = SemanticNode> {\n /**\n * The patterns a node may render with, from those that are not parse-only\n * (hyperscript: an event handler renders only with a trigger pattern, never a\n * fused `<command>-event-*` one).\n */\n candidates?(node: N, patterns: readonly LanguagePattern[]): readonly LanguagePattern[];\n /** Whether the node carries `role` as written, not as a default its parser filled in. */\n hasRealRole(node: N, role: string): boolean;\n /** The grammar's own preference between patterns, added to the score. */\n adjustScore?(pattern: LanguagePattern, node: N): number;\n /**\n * Text for token `i` and the tokens after it it covers, when the grammar\n * writes them as one (hyperscript: a reference in its case, es `a mí`);\n * undefined renders the token as usual.\n */\n span?(\n tokens: readonly PatternToken[],\n i: number,\n node: N,\n language: string,\n topLevel: boolean\n ): { text: string; tokens: number } | undefined;\n /** A role slot's text; null writes nothing. */\n writeRole(token: RolePatternToken, node: N, language: string): string | null;\n /**\n * Whether an optional group whose required roles the node carries is written\n * (hyperscript: not for the implicit `me` its parser filled in). Default yes.\n */\n writeGroup?(token: GroupPatternToken, node: N, language: string): boolean;\n /**\n * Add a token's text to `parts` (hyperscript: a marker written onto its\n * word, ko `#out에`). Default: a part of its own.\n */\n pushPart?(\n parts: string[],\n text: string,\n token: PatternToken,\n previous: PatternToken | undefined,\n node: N,\n language: string\n ): void;\n /** Before top-level token `i` (hyperscript: a scroll's direction word before its amount). */\n beforeToken?(\n tokens: readonly PatternToken[],\n i: number,\n parts: string[],\n node: N,\n language: string\n ): void;\n /** After a top-level token wrote `parts[part]` (hyperscript: where the event went). */\n afterToken?(token: PatternToken, part: number, node: N): void;\n}\n\n/**\n * Score a role slot nested inside an OPTIONAL group. Lower than the top-level\n * bonus on purpose: it must break a tie between two patterns that are otherwise\n * equal (the handcrafted `toggle-{L}-full` versus the generated pattern that\n * also carries `[{duration}]`) without ever outweighing a top-level difference.\n */\nconst NESTED_ROLE_BONUS = 5;\n\n/**\n * Score against a pattern that has no slot for a role the node carries. Larger\n * than any priority gap between a command's patterns (80–100), so rendering\n * the role always beats a more idiomatic form that drops it.\n */\nconst UNCOVERED_ROLE_PENALTY = 30;\n\n/**\n * The literal a pattern pins a role to, normalized for comparison: an\n * extraction default, or a fixed value the pattern records when it matches.\n * The second is how `go`'s url variant says what it means (`go url /page`\n * records `method: 'url'`); reading only defaults let that variant render every\n * `go`, so `go back` came out as `go url back`: a navigation to a page named\n * \"back\" in every language.\n */\nfunction pinnedLiteral(rule: ExtractionRule | undefined): string | undefined {\n if (rule?.default?.type === 'literal') return String(rule.default.value).trim().toLowerCase();\n if (rule?.value !== undefined) return String(rule.value).trim().toLowerCase();\n return undefined;\n}\n\n/**\n * The pattern to render `node` with, or null when there is none.\n */\nexport function selectRenderPattern<N extends RenderableNode>(\n node: N,\n patterns: readonly LanguagePattern[],\n hooks: PatternRenderHooks<N>\n): LanguagePattern | null {\n let candidates: readonly LanguagePattern[] = patterns.filter(pattern => !pattern.parseOnly);\n if (candidates.length === 0) candidates = patterns;\n if (hooks.candidates) candidates = hooks.candidates(node, candidates);\n\n // Which literal values does the candidate set pin, per role? A value that is\n // pinned by SOME candidate is a real alternative the pattern set distinguishes\n // (put's manner: before / after / at end of), so choosing a pattern pinned to a\n // different one would silently change meaning. A value nothing pins is not an\n // alternative — it is just the value that came out of the parse — and must not\n // disqualify anything. That distinction is what keeps `repeat until event X`\n // renderable: a zh parse yields loopType `until` while the English pattern that\n // carries the event pins `until-event`, and nothing pins bare `until`.\n const pinnedValues = new Map<string, Set<string>>();\n for (const pattern of candidates) {\n for (const [role, rule] of Object.entries(pattern.extraction ?? {})) {\n const key = pinnedLiteral(rule);\n if (key === undefined) continue;\n const set = pinnedValues.get(role) ?? new Set<string>();\n set.add(key);\n pinnedValues.set(role, set);\n }\n }\n\n // Score patterns by how well they match our roles\n const scored = candidates.map(pattern => {\n let score = pattern.priority;\n\n // Check each role token in the pattern, INCLUDING the ones nested inside\n // optional groups. Scoring only the top level made a slot the pattern\n // really has invisible: every `[for {duration}]` / `[with {style}]` group\n // lives one level down, so a handcrafted pattern without the slot tied\n // with the generated one that has it and won on order — `toggle .loading\n // for 2s` rendered as `alternar .loading` in es/it/pl/ru/uk/vi/zh, the\n // duration dropped in silence.\n //\n // A role inside a group is scored as PRESENT-only: its absence is what\n // \"optional\" means, and the group's own role tokens are not consistently\n // flagged `optional` (a handcrafted `[en {destination}]` writes the role\n // bare), so reading the flag there would apply the missing-role penalty to\n // a slot that is optional by construction.\n const hasRealRole = (role: string): boolean => hooks.hasRealRole(node, role);\n const scoreTokens = (tokens: readonly PatternToken[], inGroup: boolean): void => {\n for (const token of tokens) {\n if (token.type === 'group') {\n scoreTokens(token.tokens, true);\n } else if (token.type === 'role') {\n if (hasRealRole(token.role)) {\n // Bonus for patterns that use roles we have. A nested slot scores\n // LESS than a top-level one, so carrying an extra optional slot\n // breaks a tie without ever outweighing a top-level difference —\n // measured: at equal weight it also re-ordered the pl behavior\n // handler and three qu positional rows.\n score += inGroup ? NESTED_ROLE_BONUS : 10;\n } else if (!inGroup && !token.optional) {\n // Heavy penalty for patterns that require roles we DON'T have\n // This prevents selecting \"source\" patterns when there's no source\n score -= 50;\n }\n }\n }\n };\n scoreTokens(pattern.template.tokens, false);\n\n // A pattern with no slot for a role the node really carries drops it in\n // silence, so it loses to one that renders it. The bonuses above only\n // reward coverage, which let a slot-less pattern win on a top-level-vs-\n // nested difference: once show's patient became optional, zh `显示\n // {patient}` beat the generated `显示 [把 {patient}] [用 {style}]` and\n // `show #modal with *opacity` rendered without its strategy (bn/hi/zh).\n const slots = new Set<string>();\n const collectSlots = (tokens: readonly PatternToken[]): void => {\n for (const token of tokens) {\n if (token.type === 'group') collectSlots(token.tokens);\n else if (token.type === 'role') slots.add(token.role);\n }\n };\n collectSlots(pattern.template.tokens);\n for (const role of node.roles.keys()) {\n if (hasRealRole(role) && !slots.has(role)) score -= UNCOVERED_ROLE_PENALTY;\n }\n\n // Value-pinned variants. A positional pattern (`put X before Y`, `at end\n // of`, `after`) carries its position as a baked-in literal plus an\n // extraction default that records which value it means:\n // put-es-before -> extraction.manner.default = 'before'\n // put-es-at-end -> extraction.manner.default = 'at end of'\n // while the neutral `put-es-full` pins nothing. So the pattern set already\n // says which surface each value selects; scoring just has to read it.\n //\n // The rule: a pattern that pins a role to a literal may be chosen ONLY when\n // the node carries that exact value. Matching is a strong preference (the\n // pinned form is the whole reason the value exists); mismatching — or the\n // node not carrying the role at all — disqualifies it, so a plain\n // `put X into Y` can never render as `poner X en fin de Y`.\n //\n // This replaces an id-regex that penalized every `-at-end|-before|-after`\n // pattern unconditionally. That kept plain puts safe but made the positional\n // forms unreachable: `put \"<p>\" before me` rendered with the into-pattern in\n // all 23 languages, losing the distinction the source drew.\n for (const [role, rule] of Object.entries(pattern.extraction ?? {})) {\n const pinnedKey = pinnedLiteral(rule);\n if (pinnedKey === undefined) continue;\n const actual = node.roles.get(role);\n // The value as the pattern would produce it: a literal, or an\n // expression where the rule says so (`go back`).\n const actualKey =\n actual?.type === (rule.valueIsExpression ? 'expression' : 'literal')\n ? String(\n actual.type === 'expression'\n ? (actual as { raw?: unknown }).raw\n : (actual as { value?: unknown }).value\n )\n .trim()\n .toLowerCase()\n : undefined;\n\n if (actualKey === pinnedKey) {\n // The pinned form is the whole reason this value exists — prefer it\n // decisively over the neutral pattern, whatever the parse priorities say.\n score += 60;\n } else if (actualKey === undefined || pinnedValues.get(role)?.has(actualKey)) {\n // Either the node has no such value (so this pattern would invent one:\n // a plain `put X into Y` must never render as `put X at end of Y`), or it\n // has a DIFFERENT value that the pattern set treats as an alternative.\n // Both are wrong surfaces; disqualify.\n score -= 200;\n }\n // Otherwise the node's value is not one of the pinned alternatives, so this\n // pattern is still the best available carrier for it — leave the score alone\n // and let priority and role coverage decide.\n }\n\n score += hooks.adjustScore?.(pattern, node) ?? 0;\n\n return { pattern, score };\n });\n\n scored.sort((a, b) => b.score - a.score);\n\n return scored.length > 0 ? scored[0]!.pattern : null;\n}\n\n/**\n * The parts `node` renders to through `pattern`'s tokens, in order: each\n * literal (unless parse-only), each role's text, each group that is written.\n * The grammar joins them (and adds what the pattern does not model).\n */\nexport function renderPattern<N extends RenderableNode>(\n node: N,\n pattern: LanguagePattern,\n hooks: PatternRenderHooks<N>\n): string[] {\n const parts: string[] = [];\n const language = pattern.language;\n const tokens = pattern.template.tokens;\n for (let i = 0; i < tokens.length; i++) {\n hooks.beforeToken?.(tokens, i, parts, node, language);\n const span = hooks.span?.(tokens, i, node, language, true);\n if (span !== undefined) {\n parts.push(span.text);\n i += span.tokens - 1;\n continue;\n }\n const token = tokens[i]!;\n const rendered = renderPatternToken(token, node, language, hooks);\n if (rendered !== null) {\n pushPart(hooks, parts, rendered, token, tokens[i - 1], node, language);\n hooks.afterToken?.(token, parts.length - 1, node);\n }\n }\n return parts;\n}\n\nfunction pushPart<N extends RenderableNode>(\n hooks: PatternRenderHooks<N>,\n parts: string[],\n text: string,\n token: PatternToken,\n previous: PatternToken | undefined,\n node: N,\n language: string\n): void {\n if (hooks.pushPart) hooks.pushPart(parts, text, token, previous, node, language);\n else parts.push(text);\n}\n\n/**\n * Render a single pattern token.\n */\nfunction renderPatternToken<N extends RenderableNode>(\n token: PatternToken,\n node: N,\n language: string,\n hooks: PatternRenderHooks<N>\n): string | null {\n switch (token.type) {\n case 'literal':\n // Parse-only markers (renderSuppress) consume input but never render —\n // e.g. fetch's `from`, which parses `fetch from /api` yet must be absent\n // from output (`fetch from \"/api\"` is invalid canonical _hyperscript).\n return token.renderSuppress ? null : token.value;\n\n case 'role':\n return hooks.writeRole(token, node, language);\n\n case 'group': {\n // Check if we have all required roles in the group\n const hasRequired = token.tokens\n .filter(t => t.type === 'role' && !t.optional)\n .every(t => node.roles.has((t as RolePatternToken).role));\n\n if (!hasRequired && token.optional) {\n return null;\n }\n\n if (hooks.writeGroup && !hooks.writeGroup(token, node, language)) return null;\n\n const groupParts: string[] = [];\n let hasRoleValue = false;\n for (let i = 0; i < token.tokens.length; i++) {\n const span = hooks.span?.(token.tokens, i, node, language, false);\n if (span !== undefined) {\n groupParts.push(span.text);\n hasRoleValue = true;\n i += span.tokens - 1;\n continue;\n }\n const subToken = token.tokens[i]!;\n const rendered = renderPatternToken(subToken, node, language, hooks);\n if (rendered !== null) {\n pushPart(hooks, groupParts, rendered, subToken, token.tokens[i - 1], node, language);\n if (subToken.type === 'role') hasRoleValue = true;\n }\n }\n\n // Don't emit an optional group that DECLARES a role slot and did not\n // fill it — e.g. don't emit a dangling \"with\" when the style role is\n // absent from \"hide #output\".\n //\n // …unless the group is `renderRequired`: a MARKER wrapped on its own by\n // `profile.markersOptional` (tr, where the case suffix may be dropped\n // colloquially, so the parse side has to accept both forms). Dropping\n // those cost tr every role marker in every rendered command —\n // `add .selected to #item` came out `#item .selected ekle` where the\n // corpus has `#item e .selected i ekle`, and the marker-less surface\n // re-parses as a one-role `add` with the destination defaulted to `me`.\n if (token.optional && !hasRoleValue && !token.renderRequired) return null;\n\n return groupParts.length > 0 ? groupParts.join(' ') : null;\n }\n\n default:\n return null;\n }\n}\n"],"mappings":"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","names":["generatePattern","generatePatternVariants","defaultConfig","buildTokens","buildFormatString","buildExtractionRules"]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rendering a command through a language's own patterns: the renderer core
|
|
3
|
+
* semantic's hyperscript renderer runs (domains rethink Phase 4.5,
|
|
4
|
+
* `docs-internal/DOMAINS_RETHINK.md`), moved here from `@lokascript/semantic`.
|
|
5
|
+
*
|
|
6
|
+
* A node renders with the pattern its parser would read it back through:
|
|
7
|
+
* `selectRenderPattern` scores a language's patterns for the node (the roles it
|
|
8
|
+
* carries, the slots each pattern has, the values a pattern pins), and
|
|
9
|
+
* `renderPattern` walks the chosen pattern's tokens. What a value looks like in
|
|
10
|
+
* the language, and the grammar's preferences, are `PatternRenderHooks`.
|
|
11
|
+
* (The domains' `renderer.ts` renders from the schema instead, for
|
|
12
|
+
* `createMultilingualDSL`.)
|
|
13
|
+
*/
|
|
14
|
+
import type { GroupPatternToken, LanguagePattern, PatternToken, RolePatternToken, SemanticNode } from '../core/types';
|
|
15
|
+
/**
|
|
16
|
+
* What the core reads of a node: its roles. A grammar's own node type (semantic's
|
|
17
|
+
* `SemanticNode`) qualifies as it is; the hooks receive it unchanged.
|
|
18
|
+
*/
|
|
19
|
+
export interface RenderableNode {
|
|
20
|
+
readonly roles: ReadonlyMap<string, {
|
|
21
|
+
readonly type: string;
|
|
22
|
+
}>;
|
|
23
|
+
}
|
|
24
|
+
/** A grammar's part of rendering through patterns, for its node type `N`. */
|
|
25
|
+
export interface PatternRenderHooks<N extends RenderableNode = SemanticNode> {
|
|
26
|
+
/**
|
|
27
|
+
* The patterns a node may render with, from those that are not parse-only
|
|
28
|
+
* (hyperscript: an event handler renders only with a trigger pattern, never a
|
|
29
|
+
* fused `<command>-event-*` one).
|
|
30
|
+
*/
|
|
31
|
+
candidates?(node: N, patterns: readonly LanguagePattern[]): readonly LanguagePattern[];
|
|
32
|
+
/** Whether the node carries `role` as written, not as a default its parser filled in. */
|
|
33
|
+
hasRealRole(node: N, role: string): boolean;
|
|
34
|
+
/** The grammar's own preference between patterns, added to the score. */
|
|
35
|
+
adjustScore?(pattern: LanguagePattern, node: N): number;
|
|
36
|
+
/**
|
|
37
|
+
* Text for token `i` and the tokens after it it covers, when the grammar
|
|
38
|
+
* writes them as one (hyperscript: a reference in its case, es `a mí`);
|
|
39
|
+
* undefined renders the token as usual.
|
|
40
|
+
*/
|
|
41
|
+
span?(tokens: readonly PatternToken[], i: number, node: N, language: string, topLevel: boolean): {
|
|
42
|
+
text: string;
|
|
43
|
+
tokens: number;
|
|
44
|
+
} | undefined;
|
|
45
|
+
/** A role slot's text; null writes nothing. */
|
|
46
|
+
writeRole(token: RolePatternToken, node: N, language: string): string | null;
|
|
47
|
+
/**
|
|
48
|
+
* Whether an optional group whose required roles the node carries is written
|
|
49
|
+
* (hyperscript: not for the implicit `me` its parser filled in). Default yes.
|
|
50
|
+
*/
|
|
51
|
+
writeGroup?(token: GroupPatternToken, node: N, language: string): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Add a token's text to `parts` (hyperscript: a marker written onto its
|
|
54
|
+
* word, ko `#out에`). Default: a part of its own.
|
|
55
|
+
*/
|
|
56
|
+
pushPart?(parts: string[], text: string, token: PatternToken, previous: PatternToken | undefined, node: N, language: string): void;
|
|
57
|
+
/** Before top-level token `i` (hyperscript: a scroll's direction word before its amount). */
|
|
58
|
+
beforeToken?(tokens: readonly PatternToken[], i: number, parts: string[], node: N, language: string): void;
|
|
59
|
+
/** After a top-level token wrote `parts[part]` (hyperscript: where the event went). */
|
|
60
|
+
afterToken?(token: PatternToken, part: number, node: N): void;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The pattern to render `node` with, or null when there is none.
|
|
64
|
+
*/
|
|
65
|
+
export declare function selectRenderPattern<N extends RenderableNode>(node: N, patterns: readonly LanguagePattern[], hooks: PatternRenderHooks<N>): LanguagePattern | null;
|
|
66
|
+
/**
|
|
67
|
+
* The parts `node` renders to through `pattern`'s tokens, in order: each
|
|
68
|
+
* literal (unless parse-only), each role's text, each group that is written.
|
|
69
|
+
* The grammar joins them (and adds what the pattern does not model).
|
|
70
|
+
*/
|
|
71
|
+
export declare function renderPattern<N extends RenderableNode>(node: N, pattern: LanguagePattern, hooks: PatternRenderHooks<N>): string[];
|
|
72
|
+
//# sourceMappingURL=pattern-render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-render.d.ts","sourceRoot":"","sources":["../../src/generation/pattern-render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAEV,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACb,MAAM,eAAe,CAAC;AAEvB;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChE;AAED,6EAA6E;AAC7E,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,cAAc,GAAG,YAAY;IACzE;;;;OAIG;IACH,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,SAAS,eAAe,EAAE,GAAG,SAAS,eAAe,EAAE,CAAC;IACvF,yFAAyF;IACzF,WAAW,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5C,yEAAyE;IACzE,WAAW,CAAC,CAAC,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC;IACxD;;;;OAIG;IACH,IAAI,CAAC,CACH,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,CAAC,EAAE,MAAM,EACT,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,OAAO,GAChB;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IAChD,+CAA+C;IAC/C,SAAS,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC7E;;;OAGG;IACH,UAAU,CAAC,CAAC,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1E;;;OAGG;IACH,QAAQ,CAAC,CACP,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,YAAY,GAAG,SAAS,EAClC,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,MAAM,GACf,IAAI,CAAC;IACR,6FAA6F;IAC7F,WAAW,CAAC,CACV,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,CAAC,EAAE,MAAM,EACT,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,MAAM,GACf,IAAI,CAAC;IACR,uFAAuF;IACvF,UAAU,CAAC,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;CAC/D;AA+BD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,cAAc,EAC1D,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,SAAS,eAAe,EAAE,EACpC,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC3B,eAAe,GAAG,IAAI,CA6IxB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,cAAc,EACpD,IAAI,EAAE,CAAC,EACP,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC3B,MAAM,EAAE,CAoBV"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patterns from command schemas: the generator semantic's hyperscript parser
|
|
3
|
+
* runs (domains rethink Phase 4.4, `docs-internal/DOMAINS_RETHINK.md`), moved
|
|
4
|
+
* here from `@lokascript/semantic` beside the domains' own `generatePattern`
|
|
5
|
+
* (`pattern-generator.ts`), which `createMultilingualDSL` still uses.
|
|
6
|
+
*
|
|
7
|
+
* Per command and language it builds the main pattern and its variants: the
|
|
8
|
+
* simple variant (required roles only), the omit-role, widened-type and
|
|
9
|
+
* required-role variants, an SOV language's verb-first fallback, and the
|
|
10
|
+
* value-prefix-literal variants (`RoleSpec` / `CommandSchema` document each).
|
|
11
|
+
* What differs between grammars is a hook (`SchemaPatternGrammar`); what a
|
|
12
|
+
* grammar adds on top (hyperscript's fused event-handler patterns) stays in the
|
|
13
|
+
* grammar's package.
|
|
14
|
+
*/
|
|
15
|
+
import type { LanguagePattern, PatternToken } from '../core/types';
|
|
16
|
+
import type { CommandSchema, RoleSpec } from '../schema';
|
|
17
|
+
/** What differs between grammars in how a schema becomes patterns. */
|
|
18
|
+
export interface SchemaPatternGrammar {
|
|
19
|
+
/**
|
|
20
|
+
* How `svoPosition` / `sovPosition` sort: `'ascending'` puts the lowest first
|
|
21
|
+
* (hyperscript's schemas, 1-based), `'descending'` the highest (a domain's
|
|
22
|
+
* schemas, as framework's `generatePattern` reads them).
|
|
23
|
+
*/
|
|
24
|
+
readonly positionOrder: 'ascending' | 'descending';
|
|
25
|
+
}
|
|
26
|
+
/** A role marker in a language profile. */
|
|
27
|
+
export interface SchemaPatternMarker {
|
|
28
|
+
readonly primary: string;
|
|
29
|
+
readonly alternatives?: string[];
|
|
30
|
+
readonly position: 'before' | 'after';
|
|
31
|
+
}
|
|
32
|
+
/** What the generator reads of a language profile. */
|
|
33
|
+
export interface SchemaPatternProfile {
|
|
34
|
+
readonly code: string;
|
|
35
|
+
readonly wordOrder: string;
|
|
36
|
+
readonly keywords: Readonly<Record<string, {
|
|
37
|
+
readonly primary: string;
|
|
38
|
+
readonly alternatives?: string[];
|
|
39
|
+
} | undefined>>;
|
|
40
|
+
readonly roleMarkers: Readonly<Partial<Record<string, SchemaPatternMarker>>>;
|
|
41
|
+
/**
|
|
42
|
+
* The language may drop its role markers colloquially (Turkish case
|
|
43
|
+
* suffixes): each marker becomes an optional group that still renders.
|
|
44
|
+
*/
|
|
45
|
+
readonly markersOptional?: boolean;
|
|
46
|
+
}
|
|
47
|
+
/** The generator, bound to a grammar (`createSchemaPatternGenerator`). */
|
|
48
|
+
export interface SchemaPatternGenerator {
|
|
49
|
+
/** The main pattern for a command in a language. */
|
|
50
|
+
generatePattern(schema: CommandSchema, profile: SchemaPatternProfile, config?: SchemaPatternConfig): LanguagePattern;
|
|
51
|
+
/** The command without its optional roles; null when it has none. */
|
|
52
|
+
generateSimplePattern(schema: CommandSchema, profile: SchemaPatternProfile, config?: SchemaPatternConfig): LanguagePattern | null;
|
|
53
|
+
/** An SOV language's verb-first fallback; null for other word orders. */
|
|
54
|
+
generateVerbFirstPattern(schema: CommandSchema, profile: SchemaPatternProfile, config?: SchemaPatternConfig): LanguagePattern | null;
|
|
55
|
+
/** The main pattern and every variant the schema and config ask for. */
|
|
56
|
+
generatePatternVariants(schema: CommandSchema, profile: SchemaPatternProfile, config?: SchemaPatternConfig): LanguagePattern[];
|
|
57
|
+
/** The token(s) of one role: its value slot and marker, in the language's order. */
|
|
58
|
+
buildRoleToken(roleSpec: RoleSpec, profile: SchemaPatternProfile): PatternToken[];
|
|
59
|
+
}
|
|
60
|
+
/** A generator for the grammar's schemas. */
|
|
61
|
+
export declare function createSchemaPatternGenerator(grammar: SchemaPatternGrammar): SchemaPatternGenerator;
|
|
62
|
+
/** The schema without its variant-only roles: what every pattern but a required-role variant is built from. */
|
|
63
|
+
export declare function withoutVariantOnlyRoles<S extends CommandSchema>(schema: S): S;
|
|
64
|
+
/**
|
|
65
|
+
* Minimum interface for role specs that can have marker resolution.
|
|
66
|
+
* Compatible with the RoleSpec type from command-schemas.
|
|
67
|
+
*/
|
|
68
|
+
export interface RoleSpecWithMarker {
|
|
69
|
+
role: string;
|
|
70
|
+
markerOverride?: Record<string, string | undefined>;
|
|
71
|
+
markerLegacy?: Record<string, readonly string[]>;
|
|
72
|
+
markerVariants?: Record<string, readonly string[]>;
|
|
73
|
+
methodCarrier?: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Resolved marker information for a role.
|
|
77
|
+
*/
|
|
78
|
+
export interface ResolvedMarker {
|
|
79
|
+
/** Primary marker string (may be empty string for no marker) */
|
|
80
|
+
primary: string;
|
|
81
|
+
/** Alternative markers */
|
|
82
|
+
alternatives?: string[];
|
|
83
|
+
/** Position relative to role value */
|
|
84
|
+
position: 'before' | 'after';
|
|
85
|
+
/** Whether this is an override marker */
|
|
86
|
+
isOverride: boolean;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Resolve the marker for a role in a specific language.
|
|
90
|
+
*
|
|
91
|
+
* Checks for command-specific marker overrides first,
|
|
92
|
+
* then falls back to the default marker from the language profile.
|
|
93
|
+
*
|
|
94
|
+
* @param roleSpec Role specification with optional override
|
|
95
|
+
* @param profile Language profile with role markers
|
|
96
|
+
* @returns Resolved marker info, or null if no marker
|
|
97
|
+
*/
|
|
98
|
+
export declare function resolveMarkerForRole(roleSpec: RoleSpecWithMarker, profile: SchemaPatternProfile): ResolvedMarker | null;
|
|
99
|
+
/**
|
|
100
|
+
* Alternatives an OVERRIDE marker accepts: the role's {@link RoleSpecWithMarker.markerLegacy}
|
|
101
|
+
* entries for this language, minus the override itself.
|
|
102
|
+
*
|
|
103
|
+
* Every generator that resolves a marker has its own override branch, and each
|
|
104
|
+
* one used to drop alternatives entirely — so correcting a marker silently
|
|
105
|
+
* stopped the previous one parsing. This is the single definition of what an
|
|
106
|
+
* override still accepts; call it from each of those branches.
|
|
107
|
+
*
|
|
108
|
+
* Prefer {@link schemaMarkerAlternatives}, which also merges `markerVariants`.
|
|
109
|
+
* This narrower entry point remains for callers that must exclude variants.
|
|
110
|
+
*/
|
|
111
|
+
export declare function legacyMarkerAlternatives(roleSpec: RoleSpecWithMarker, languageCode: string, overrideMarker: string): string[] | undefined;
|
|
112
|
+
/**
|
|
113
|
+
* Every schema-declared alternative a role's marker accepts in this language:
|
|
114
|
+
* `markerLegacy` ∪ `markerVariants`, minus the marker itself.
|
|
115
|
+
*
|
|
116
|
+
* **The single definition — call it from every branch of every generator.** The
|
|
117
|
+
* two fields used to sit on DIFFERENT branches: the override branch read only
|
|
118
|
+
* `markerLegacy`, the profile-default branch only `markerVariants`. So giving a
|
|
119
|
+
* language a `markerOverride` silently deleted its `markerVariants`, and giving
|
|
120
|
+
* it `markerVariants` did nothing at all wherever an override existed. Both
|
|
121
|
+
* halves were live: tr `set`'s dative allomorphs (`e|a|ye|ya`) were declared as
|
|
122
|
+
* variants but dropped by the tr override, so `… doğru ya ayarla` parsed only
|
|
123
|
+
* inside an event handler — the one generator that happened to merge both.
|
|
124
|
+
*
|
|
125
|
+
* `markerVariants` are held out for a role with a {@link RoleSpecWithMarker.methodCarrier}:
|
|
126
|
+
* there they are not synonyms but distinct command shapes recorded into another
|
|
127
|
+
* role (`put`'s `into|before|after` → `method`), and merging them as synonyms is
|
|
128
|
+
* what broke `put-before`/`put-after` in 23 languages at once. That flag is the
|
|
129
|
+
* discriminator because it is set on exactly the role whose variants carry
|
|
130
|
+
* meaning — pinned by `schema-consistency.test.ts`, which fails if a new
|
|
131
|
+
* `markerVariants` appears without that decision being made.
|
|
132
|
+
*/
|
|
133
|
+
export declare function schemaMarkerAlternatives(roleSpec: RoleSpecWithMarker, languageCode: string, marker: string): string[] | undefined;
|
|
134
|
+
/**
|
|
135
|
+
* Configuration for pattern generation.
|
|
136
|
+
*/
|
|
137
|
+
export interface SchemaPatternConfig {
|
|
138
|
+
/** Base priority for generated patterns (higher = checked first) */
|
|
139
|
+
basePriority?: number;
|
|
140
|
+
/** Whether to generate simple patterns (without optional roles) */
|
|
141
|
+
generateSimpleVariants?: boolean;
|
|
142
|
+
/** Whether to generate alternative keyword patterns */
|
|
143
|
+
generateAlternatives?: boolean;
|
|
144
|
+
/**
|
|
145
|
+
* Whether to generate verb-first fallback patterns for SOV languages
|
|
146
|
+
* (`トグル .active` alongside the canonical `.active を トグル`). Default on.
|
|
147
|
+
* These are strictly lower priority than the canonical patterns, so native
|
|
148
|
+
* SOV order always wins; this only accepts bilingual/code-switched input.
|
|
149
|
+
*/
|
|
150
|
+
generateVerbFirstVariants?: boolean;
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=schema-patterns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-patterns.d.ts","sourceRoot":"","sources":["../../src/generation/schema-patterns.ts"],"names":[],"mappings":"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"}
|