@lokascript/framework 2.0.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.
Files changed (181) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +142 -0
  3. package/dist/aot/aot-orchestrator.d.ts +75 -0
  4. package/dist/aot/aot-orchestrator.d.ts.map +1 -0
  5. package/dist/aot/domain-scanner.d.ts +27 -0
  6. package/dist/aot/domain-scanner.d.ts.map +1 -0
  7. package/dist/aot/index.d.ts +8 -0
  8. package/dist/aot/index.d.ts.map +1 -0
  9. package/dist/aot/types.d.ts +103 -0
  10. package/dist/aot/types.d.ts.map +1 -0
  11. package/dist/api/create-dsl.d.ts +91 -0
  12. package/dist/api/create-dsl.d.ts.map +1 -0
  13. package/dist/api/dispatcher.d.ts +108 -0
  14. package/dist/api/dispatcher.d.ts.map +1 -0
  15. package/dist/api/domain-registry.d.ts +152 -0
  16. package/dist/api/domain-registry.d.ts.map +1 -0
  17. package/dist/api/index.d.ts +7 -0
  18. package/dist/api/index.d.ts.map +1 -0
  19. package/dist/api/index.js +2082 -0
  20. package/dist/api/index.js.map +1 -0
  21. package/dist/core/index.d.ts +7 -0
  22. package/dist/core/index.d.ts.map +1 -0
  23. package/dist/core/index.js +2674 -0
  24. package/dist/core/index.js.map +1 -0
  25. package/dist/core/logger.d.ts +32 -0
  26. package/dist/core/logger.d.ts.map +1 -0
  27. package/dist/core/pattern-matching/index.d.ts +6 -0
  28. package/dist/core/pattern-matching/index.d.ts.map +1 -0
  29. package/dist/core/pattern-matching/index.js +1239 -0
  30. package/dist/core/pattern-matching/index.js.map +1 -0
  31. package/dist/core/pattern-matching/pattern-matcher.d.ts +239 -0
  32. package/dist/core/pattern-matching/pattern-matcher.d.ts.map +1 -0
  33. package/dist/core/pattern-matching/utils/index.d.ts +6 -0
  34. package/dist/core/pattern-matching/utils/index.d.ts.map +1 -0
  35. package/dist/core/pattern-matching/utils/possessive-keywords.d.ts +38 -0
  36. package/dist/core/pattern-matching/utils/possessive-keywords.d.ts.map +1 -0
  37. package/dist/core/pattern-matching/utils/type-validation.d.ts +63 -0
  38. package/dist/core/pattern-matching/utils/type-validation.d.ts.map +1 -0
  39. package/dist/core/tokenization/base-tokenizer.d.ts +344 -0
  40. package/dist/core/tokenization/base-tokenizer.d.ts.map +1 -0
  41. package/dist/core/tokenization/char-classifiers.d.ts +56 -0
  42. package/dist/core/tokenization/char-classifiers.d.ts.map +1 -0
  43. package/dist/core/tokenization/default-extractors.d.ts +48 -0
  44. package/dist/core/tokenization/default-extractors.d.ts.map +1 -0
  45. package/dist/core/tokenization/extractors/index.d.ts +9 -0
  46. package/dist/core/tokenization/extractors/index.d.ts.map +1 -0
  47. package/dist/core/tokenization/extractors/operator.d.ts +23 -0
  48. package/dist/core/tokenization/extractors/operator.d.ts.map +1 -0
  49. package/dist/core/tokenization/extractors/punctuation.d.ts +22 -0
  50. package/dist/core/tokenization/extractors/punctuation.d.ts.map +1 -0
  51. package/dist/core/tokenization/extractors.d.ts +61 -0
  52. package/dist/core/tokenization/extractors.d.ts.map +1 -0
  53. package/dist/core/tokenization/index.d.ts +11 -0
  54. package/dist/core/tokenization/index.d.ts.map +1 -0
  55. package/dist/core/tokenization/index.js +1345 -0
  56. package/dist/core/tokenization/index.js.map +1 -0
  57. package/dist/core/tokenization/morphology/index.d.ts +5 -0
  58. package/dist/core/tokenization/morphology/index.d.ts.map +1 -0
  59. package/dist/core/tokenization/morphology/types.d.ts +110 -0
  60. package/dist/core/tokenization/morphology/types.d.ts.map +1 -0
  61. package/dist/core/tokenization/token-utils.d.ts +111 -0
  62. package/dist/core/tokenization/token-utils.d.ts.map +1 -0
  63. package/dist/core/types.d.ts +382 -0
  64. package/dist/core/types.d.ts.map +1 -0
  65. package/dist/core/types.js +108 -0
  66. package/dist/core/types.js.map +1 -0
  67. package/dist/generation/diagnostics.d.ts +120 -0
  68. package/dist/generation/diagnostics.d.ts.map +1 -0
  69. package/dist/generation/index.d.ts +7 -0
  70. package/dist/generation/index.d.ts.map +1 -0
  71. package/dist/generation/index.js +339 -0
  72. package/dist/generation/index.js.map +1 -0
  73. package/dist/generation/pattern-generator.d.ts +48 -0
  74. package/dist/generation/pattern-generator.d.ts.map +1 -0
  75. package/dist/generation/renderer.d.ts +115 -0
  76. package/dist/generation/renderer.d.ts.map +1 -0
  77. package/dist/grammar/index.d.ts +10 -0
  78. package/dist/grammar/index.d.ts.map +1 -0
  79. package/dist/grammar/index.js +391 -0
  80. package/dist/grammar/index.js.map +1 -0
  81. package/dist/grammar/transformer.d.ts +56 -0
  82. package/dist/grammar/transformer.d.ts.map +1 -0
  83. package/dist/grammar/types.d.ts +236 -0
  84. package/dist/grammar/types.d.ts.map +1 -0
  85. package/dist/index.cjs +4454 -0
  86. package/dist/index.cjs.map +1 -0
  87. package/dist/index.d.ts +46 -0
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/index.js +4336 -0
  90. package/dist/index.js.map +1 -0
  91. package/dist/interfaces/dictionary.d.ts +82 -0
  92. package/dist/interfaces/dictionary.d.ts.map +1 -0
  93. package/dist/interfaces/index.d.ts +10 -0
  94. package/dist/interfaces/index.d.ts.map +1 -0
  95. package/dist/interfaces/profile-provider.d.ts +67 -0
  96. package/dist/interfaces/profile-provider.d.ts.map +1 -0
  97. package/dist/interfaces/value-extractor.d.ts +168 -0
  98. package/dist/interfaces/value-extractor.d.ts.map +1 -0
  99. package/dist/multilingual/index.d.ts +8 -0
  100. package/dist/multilingual/index.d.ts.map +1 -0
  101. package/dist/multilingual/index.js +1 -0
  102. package/dist/multilingual/index.js.map +1 -0
  103. package/dist/parsing/index.d.ts +8 -0
  104. package/dist/parsing/index.d.ts.map +1 -0
  105. package/dist/parsing/index.js +1415 -0
  106. package/dist/parsing/index.js.map +1 -0
  107. package/dist/parsing/multi-statement.d.ts +265 -0
  108. package/dist/parsing/multi-statement.d.ts.map +1 -0
  109. package/dist/schema/command-schema.d.ts +78 -0
  110. package/dist/schema/command-schema.d.ts.map +1 -0
  111. package/dist/schema/index.d.ts +5 -0
  112. package/dist/schema/index.d.ts.map +1 -0
  113. package/dist/schema/index.js +25 -0
  114. package/dist/schema/index.js.map +1 -0
  115. package/dist/test-setup.d.ts +9 -0
  116. package/dist/test-setup.d.ts.map +1 -0
  117. package/dist/testing/index.d.ts +50 -0
  118. package/dist/testing/index.d.ts.map +1 -0
  119. package/dist/testing/index.js +16969 -0
  120. package/dist/testing/index.js.map +1 -0
  121. package/package.json +122 -0
  122. package/src/__test__/fixtures/sql-dsl.ts +232 -0
  123. package/src/__test__/sql-integration.test.ts +189 -0
  124. package/src/__test__/test-utils.ts +260 -0
  125. package/src/aot/aot-orchestrator.test.ts +413 -0
  126. package/src/aot/aot-orchestrator.ts +238 -0
  127. package/src/aot/domain-scanner.ts +178 -0
  128. package/src/aot/index.ts +8 -0
  129. package/src/aot/types.ts +124 -0
  130. package/src/api/create-dsl.ts +367 -0
  131. package/src/api/dispatcher.test.ts +336 -0
  132. package/src/api/dispatcher.ts +222 -0
  133. package/src/api/domain-registry.test.ts +336 -0
  134. package/src/api/domain-registry.ts +500 -0
  135. package/src/api/index.ts +7 -0
  136. package/src/core/index.ts +7 -0
  137. package/src/core/logger.ts +130 -0
  138. package/src/core/pattern-matching/index.ts +6 -0
  139. package/src/core/pattern-matching/pattern-matcher.test.ts +900 -0
  140. package/src/core/pattern-matching/pattern-matcher.ts +1548 -0
  141. package/src/core/pattern-matching/pattern-matcher.ts.backup +1267 -0
  142. package/src/core/pattern-matching/utils/index.ts +6 -0
  143. package/src/core/pattern-matching/utils/possessive-keywords.ts +55 -0
  144. package/src/core/pattern-matching/utils/type-validation.test.ts +316 -0
  145. package/src/core/pattern-matching/utils/type-validation.ts +134 -0
  146. package/src/core/tokenization/base-tokenizer.ts +916 -0
  147. package/src/core/tokenization/char-classifiers.ts +79 -0
  148. package/src/core/tokenization/create-simple-tokenizer.test.ts +260 -0
  149. package/src/core/tokenization/default-extractors.ts +69 -0
  150. package/src/core/tokenization/extractors/index.ts +9 -0
  151. package/src/core/tokenization/extractors/operator.ts +75 -0
  152. package/src/core/tokenization/extractors/punctuation.ts +39 -0
  153. package/src/core/tokenization/extractors.ts +452 -0
  154. package/src/core/tokenization/index.ts +11 -0
  155. package/src/core/tokenization/morphology/index.ts +5 -0
  156. package/src/core/tokenization/morphology/types.ts +211 -0
  157. package/src/core/tokenization/token-utils.ts +252 -0
  158. package/src/core/types.ts +589 -0
  159. package/src/generation/diagnostics.test.ts +171 -0
  160. package/src/generation/diagnostics.ts +239 -0
  161. package/src/generation/index.ts +7 -0
  162. package/src/generation/pattern-generator.test.ts +430 -0
  163. package/src/generation/pattern-generator.ts +315 -0
  164. package/src/generation/renderer.test.ts +266 -0
  165. package/src/generation/renderer.ts +244 -0
  166. package/src/grammar/index.ts +12 -0
  167. package/src/grammar/transformer.ts +159 -0
  168. package/src/grammar/types.ts +630 -0
  169. package/src/index.ts +157 -0
  170. package/src/interfaces/dictionary.ts +123 -0
  171. package/src/interfaces/index.ts +10 -0
  172. package/src/interfaces/profile-provider.ts +88 -0
  173. package/src/interfaces/value-extractor.ts +435 -0
  174. package/src/multilingual/index.ts +9 -0
  175. package/src/parsing/index.ts +27 -0
  176. package/src/parsing/multi-statement.test.ts +480 -0
  177. package/src/parsing/multi-statement.ts +648 -0
  178. package/src/schema/command-schema.ts +118 -0
  179. package/src/schema/index.ts +5 -0
  180. package/src/test-setup.ts +45 -0
  181. package/src/testing/index.ts +137 -0
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Generalized AOT Orchestrator
3
+ *
4
+ * Coordinates scan → parse → compile → collect for any domain.
5
+ * Each domain provides a DomainCompilationBackend (DSL + CodeGenerator + scan config),
6
+ * and the orchestrator handles the rest.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { AOTOrchestrator } from '@lokascript/framework';
11
+ *
12
+ * const orchestrator = new AOTOrchestrator();
13
+ *
14
+ * orchestrator.registerBackend({
15
+ * domain: 'sql',
16
+ * dsl: createSQLDSL(),
17
+ * codeGenerator: sqlCodeGenerator,
18
+ * scanConfig: {
19
+ * domain: 'sql',
20
+ * attributes: ['data-sql'],
21
+ * scriptTypes: ['text/sql-dsl'],
22
+ * },
23
+ * });
24
+ *
25
+ * const result = await orchestrator.compileFiles(
26
+ * ['index.html', 'about.html'],
27
+ * (path) => fs.promises.readFile(path, 'utf-8')
28
+ * );
29
+ * ```
30
+ */
31
+
32
+ import type { MultilingualDSL, CodeGenerator } from '../api/create-dsl';
33
+ import type {
34
+ DomainScanConfig,
35
+ ExtractedSnippet,
36
+ CompiledSnippet,
37
+ AOTBatchResult,
38
+ GeneralizedAOTOptions,
39
+ OutputOptions,
40
+ } from './types';
41
+ import { DomainAwareScanner } from './domain-scanner';
42
+
43
+ // =============================================================================
44
+ // Types
45
+ // =============================================================================
46
+
47
+ /**
48
+ * Per-domain compilation backend.
49
+ * Provides everything needed to scan, parse, and compile a domain's syntax.
50
+ */
51
+ export interface DomainCompilationBackend {
52
+ /** Domain name (must match scanConfig.domain) */
53
+ readonly domain: string;
54
+ /** The DSL instance for parsing and compilation */
55
+ readonly dsl: MultilingualDSL;
56
+ /** Code generator for producing target code from semantic nodes */
57
+ readonly codeGenerator: CodeGenerator;
58
+ /** Scan configuration declaring HTML attribute patterns */
59
+ readonly scanConfig: DomainScanConfig;
60
+ }
61
+
62
+ // =============================================================================
63
+ // AOTOrchestrator
64
+ // =============================================================================
65
+
66
+ /**
67
+ * Generalized AOT orchestrator for any domain.
68
+ */
69
+ export class AOTOrchestrator {
70
+ private backends = new Map<string, DomainCompilationBackend>();
71
+ private options: Required<GeneralizedAOTOptions>;
72
+
73
+ constructor(options?: GeneralizedAOTOptions) {
74
+ this.options = {
75
+ confidenceThreshold: options?.confidenceThreshold ?? 0.7,
76
+ continueOnError: options?.continueOnError ?? true,
77
+ debug: options?.debug ?? false,
78
+ };
79
+ }
80
+
81
+ /**
82
+ * Register a domain compilation backend.
83
+ * @throws if a backend with the same domain name is already registered
84
+ */
85
+ registerBackend(backend: DomainCompilationBackend): void {
86
+ if (this.backends.has(backend.domain)) {
87
+ throw new Error(`Backend already registered for domain: ${backend.domain}`);
88
+ }
89
+ this.backends.set(backend.domain, backend);
90
+ }
91
+
92
+ /**
93
+ * Scan source files and compile all domain snippets.
94
+ */
95
+ async compileFiles(
96
+ files: string[],
97
+ readFile: (path: string) => Promise<string>
98
+ ): Promise<AOTBatchResult> {
99
+ // Build scanner from all backends' scan configs
100
+ const configs = Array.from(this.backends.values()).map(b => b.scanConfig);
101
+ const scanner = new DomainAwareScanner(configs);
102
+
103
+ // Extract all snippets
104
+ const snippets = await scanner.extractFromFiles(files, readFile);
105
+
106
+ if (this.options.debug) {
107
+ console.log(`[aot] Extracted ${snippets.length} snippets from ${files.length} files`);
108
+ }
109
+
110
+ // Compile each snippet
111
+ const compiled: CompiledSnippet[] = [];
112
+ const errors: AOTBatchResult['errors'][number][] = [];
113
+ const domainBreakdown: Record<string, number> = {};
114
+
115
+ for (const snippet of snippets) {
116
+ domainBreakdown[snippet.domain] = (domainBreakdown[snippet.domain] ?? 0) + 1;
117
+
118
+ const result = this.compileSnippet(snippet);
119
+ if ('error' in result) {
120
+ errors.push({
121
+ domain: snippet.domain,
122
+ source: snippet.code,
123
+ file: snippet.file,
124
+ line: snippet.line,
125
+ message: result.error,
126
+ });
127
+ if (!this.options.continueOnError) break;
128
+ } else {
129
+ compiled.push(result);
130
+ }
131
+ }
132
+
133
+ return {
134
+ compiled,
135
+ errors,
136
+ stats: {
137
+ totalSnippets: snippets.length,
138
+ compiledCount: compiled.length,
139
+ errorCount: errors.length,
140
+ domainBreakdown,
141
+ },
142
+ };
143
+ }
144
+
145
+ /**
146
+ * Compile a single extracted snippet.
147
+ * Returns the compiled result or an error object.
148
+ */
149
+ compileSnippet(snippet: ExtractedSnippet): CompiledSnippet | { error: string } {
150
+ const backend = this.backends.get(snippet.domain);
151
+ if (!backend) {
152
+ return { error: `No backend registered for domain: ${snippet.domain}` };
153
+ }
154
+
155
+ try {
156
+ const result = backend.dsl.compile(snippet.code, snippet.language);
157
+ if (!result.ok || !result.code) {
158
+ return { error: result.errors?.join('; ') ?? 'Compilation failed' };
159
+ }
160
+
161
+ return {
162
+ domain: snippet.domain,
163
+ source: snippet.code,
164
+ compiled: result.code,
165
+ language: snippet.language,
166
+ file: snippet.file,
167
+ line: snippet.line,
168
+ };
169
+ } catch (err) {
170
+ return { error: err instanceof Error ? err.message : String(err) };
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Generate combined output from compilation results.
176
+ */
177
+ generateOutput(result: AOTBatchResult, options?: OutputOptions): string {
178
+ const format = options?.format ?? 'esm';
179
+ const includeComments = options?.includeComments ?? true;
180
+ const groupByDomain = options?.groupByDomain ?? true;
181
+
182
+ const sections: string[] = [];
183
+
184
+ if (includeComments) {
185
+ sections.push(`// Generated by @lokascript/framework AOT compiler`);
186
+ sections.push(
187
+ `// ${result.stats.compiledCount} snippets compiled, ${result.stats.errorCount} errors`
188
+ );
189
+ sections.push('');
190
+ }
191
+
192
+ if (groupByDomain) {
193
+ // Group by domain
194
+ const grouped = new Map<string, CompiledSnippet[]>();
195
+ for (const snippet of result.compiled) {
196
+ const list = grouped.get(snippet.domain) ?? [];
197
+ list.push(snippet);
198
+ grouped.set(snippet.domain, list);
199
+ }
200
+
201
+ for (const [domain, snippets] of grouped) {
202
+ if (includeComments) {
203
+ sections.push(`// === Domain: ${domain} ===`);
204
+ sections.push('');
205
+ }
206
+
207
+ for (const snippet of snippets) {
208
+ if (includeComments) {
209
+ sections.push(`// Source: ${snippet.file}:${snippet.line}`);
210
+ sections.push(`// Language: ${snippet.language}`);
211
+ }
212
+ sections.push(snippet.compiled);
213
+ sections.push('');
214
+ }
215
+ }
216
+ } else {
217
+ for (const snippet of result.compiled) {
218
+ if (includeComments) {
219
+ sections.push(`// [${snippet.domain}] ${snippet.file}:${snippet.line}`);
220
+ }
221
+ sections.push(snippet.compiled);
222
+ sections.push('');
223
+ }
224
+ }
225
+
226
+ const body = sections.join('\n').trimEnd();
227
+
228
+ switch (format) {
229
+ case 'cjs':
230
+ return `'use strict';\n\n${body}\n`;
231
+ case 'iife':
232
+ return `(function() {\n${body}\n})();\n`;
233
+ case 'esm':
234
+ default:
235
+ return `${body}\n`;
236
+ }
237
+ }
238
+ }
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Domain-Aware Scanner
3
+ *
4
+ * Extracts DSL snippets from HTML/template files based on domain-declared
5
+ * attribute patterns and script types. Unlike the hyperscript-specific
6
+ * HTMLScanner, this scanner is configured dynamically from DomainScanConfig.
7
+ */
8
+
9
+ import type { DomainScanConfig, ExtractedSnippet } from './types';
10
+
11
+ // =============================================================================
12
+ // Helpers
13
+ // =============================================================================
14
+
15
+ /**
16
+ * Build regex patterns for extracting attribute values.
17
+ * Handles double-quoted, single-quoted, and backtick-quoted values.
18
+ */
19
+ function buildAttributePatterns(attributes: readonly string[]): RegExp[] {
20
+ const patterns: RegExp[] = [];
21
+ for (const attr of attributes) {
22
+ const escaped = attr.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
23
+ // Match: attr="value", attr='value', attr=`value`
24
+ patterns.push(new RegExp(`${escaped}\\s*=\\s*"([^"]+)"`, 'g'));
25
+ patterns.push(new RegExp(`${escaped}\\s*=\\s*'([^']+)'`, 'g'));
26
+ patterns.push(new RegExp(`${escaped}\\s*=\\s*\`([^\`]+)\``, 'g'));
27
+ }
28
+ return patterns;
29
+ }
30
+
31
+ /**
32
+ * Build regex patterns for extracting script tag contents.
33
+ */
34
+ function buildScriptPatterns(scriptTypes: readonly string[]): RegExp[] {
35
+ return scriptTypes.map(type => {
36
+ const escaped = type.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
37
+ return new RegExp(`<script[^>]*type=["']?${escaped}["']?[^>]*>([\\s\\S]*?)<\\/script>`, 'gi');
38
+ });
39
+ }
40
+
41
+ /**
42
+ * Count newlines before a position to determine line number.
43
+ */
44
+ function getLineNumber(source: string, position: number): number {
45
+ let line = 1;
46
+ for (let i = 0; i < position && i < source.length; i++) {
47
+ if (source[i] === '\n') line++;
48
+ }
49
+ return line;
50
+ }
51
+
52
+ /**
53
+ * Try to extract an element ID near the matched attribute.
54
+ * Looks backward in the source for an id="..." on the same element.
55
+ */
56
+ function extractElementId(source: string, matchIndex: number): string | undefined {
57
+ // Find the opening < before this attribute
58
+ const before = source.lastIndexOf('<', matchIndex);
59
+ if (before === -1) return undefined;
60
+
61
+ const tagChunk = source.slice(before, matchIndex + 200);
62
+ const idMatch = tagChunk.match(/\bid=["']([^"']+)["']/);
63
+ return idMatch?.[1];
64
+ }
65
+
66
+ /**
67
+ * Try to extract a lang attribute from the element.
68
+ */
69
+ function extractLangAttribute(source: string, matchIndex: number): string | undefined {
70
+ const before = source.lastIndexOf('<', matchIndex);
71
+ if (before === -1) return undefined;
72
+
73
+ const tagChunk = source.slice(before, matchIndex + 200);
74
+ const langMatch = tagChunk.match(/\blang=["']([^"']+)["']/);
75
+ return langMatch?.[1];
76
+ }
77
+
78
+ // =============================================================================
79
+ // DomainAwareScanner
80
+ // =============================================================================
81
+
82
+ /**
83
+ * Scans HTML/template files for domain-specific snippets.
84
+ *
85
+ * Configured by DomainScanConfig objects, each declaring which
86
+ * HTML attributes and script types a domain uses.
87
+ */
88
+ export class DomainAwareScanner {
89
+ private configs: readonly DomainScanConfig[];
90
+
91
+ constructor(configs: readonly DomainScanConfig[]) {
92
+ this.configs = configs;
93
+ }
94
+
95
+ /**
96
+ * Extract all domain snippets from an HTML source string.
97
+ */
98
+ extract(source: string, filename: string): ExtractedSnippet[] {
99
+ const snippets: ExtractedSnippet[] = [];
100
+
101
+ for (const config of this.configs) {
102
+ const defaultLang = config.defaultLanguage ?? 'en';
103
+
104
+ // Extract from attributes
105
+ const attrPatterns = buildAttributePatterns(config.attributes);
106
+ for (const pattern of attrPatterns) {
107
+ pattern.lastIndex = 0;
108
+ let match: RegExpExecArray | null;
109
+ while ((match = pattern.exec(source))) {
110
+ const code = match[1].trim();
111
+ if (!code) continue;
112
+
113
+ const line = getLineNumber(source, match.index);
114
+ const elementId = extractElementId(source, match.index);
115
+ const langAttr = extractLangAttribute(source, match.index);
116
+
117
+ snippets.push({
118
+ domain: config.domain,
119
+ code,
120
+ language: langAttr ?? defaultLang,
121
+ file: filename,
122
+ line,
123
+ column: 1,
124
+ ...(elementId != null && { elementId }),
125
+ });
126
+ }
127
+ }
128
+
129
+ // Extract from script tags
130
+ if (config.scriptTypes) {
131
+ const scriptPatterns = buildScriptPatterns(config.scriptTypes);
132
+ for (const pattern of scriptPatterns) {
133
+ pattern.lastIndex = 0;
134
+ let match: RegExpExecArray | null;
135
+ while ((match = pattern.exec(source))) {
136
+ const code = match[1].trim();
137
+ if (!code) continue;
138
+
139
+ const line = getLineNumber(source, match.index);
140
+
141
+ snippets.push({
142
+ domain: config.domain,
143
+ code,
144
+ language: defaultLang,
145
+ file: filename,
146
+ line,
147
+ column: 1,
148
+ });
149
+ }
150
+ }
151
+ }
152
+ }
153
+
154
+ return snippets;
155
+ }
156
+
157
+ /**
158
+ * Extract snippets from multiple files.
159
+ */
160
+ async extractFromFiles(
161
+ files: string[],
162
+ readFile: (path: string) => Promise<string>
163
+ ): Promise<ExtractedSnippet[]> {
164
+ const allSnippets: ExtractedSnippet[] = [];
165
+
166
+ for (const file of files) {
167
+ try {
168
+ const source = await readFile(file);
169
+ const snippets = this.extract(source, file);
170
+ allSnippets.push(...snippets);
171
+ } catch {
172
+ // Skip files that can't be read
173
+ }
174
+ }
175
+
176
+ return allSnippets;
177
+ }
178
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Generalized AOT compilation for any domain.
3
+ */
4
+
5
+ export * from './types';
6
+ export { DomainAwareScanner } from './domain-scanner';
7
+ export { AOTOrchestrator } from './aot-orchestrator';
8
+ export type { DomainCompilationBackend } from './aot-orchestrator';
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Generalized AOT Type Definitions
3
+ *
4
+ * Types for the domain-agnostic Ahead-of-Time compilation system.
5
+ * Any domain that provides a MultilingualDSL and CodeGenerator can use this.
6
+ */
7
+
8
+ // =============================================================================
9
+ // Scan Configuration
10
+ // =============================================================================
11
+
12
+ /**
13
+ * How a domain declares its HTML attribute patterns for scanning.
14
+ */
15
+ export interface DomainScanConfig {
16
+ /** Domain name (should match DomainDescriptor.name) */
17
+ readonly domain: string;
18
+ /** Attribute names to scan for (e.g., ['data-sql', '_sql']) */
19
+ readonly attributes: readonly string[];
20
+ /** Script tag types to scan for (e.g., ['text/sql-dsl']) */
21
+ readonly scriptTypes?: readonly string[];
22
+ /** Default language when not specified on element (default: 'en') */
23
+ readonly defaultLanguage?: string;
24
+ }
25
+
26
+ // =============================================================================
27
+ // Extraction Results
28
+ // =============================================================================
29
+
30
+ /**
31
+ * A snippet extracted from a source file, tagged with its domain.
32
+ */
33
+ export interface ExtractedSnippet {
34
+ /** Domain this snippet belongs to */
35
+ readonly domain: string;
36
+ /** The DSL code */
37
+ readonly code: string;
38
+ /** Language code (from element's lang attribute or default) */
39
+ readonly language: string;
40
+ /** Source file path */
41
+ readonly file: string;
42
+ /** Line number in source file (1-based) */
43
+ readonly line: number;
44
+ /** Column number in source file (1-based) */
45
+ readonly column: number;
46
+ /** Element ID if available */
47
+ readonly elementId?: string;
48
+ /** CSS selector for the element */
49
+ readonly elementSelector?: string;
50
+ }
51
+
52
+ // =============================================================================
53
+ // Compilation Results
54
+ // =============================================================================
55
+
56
+ /**
57
+ * Result of compiling a single snippet.
58
+ */
59
+ export interface CompiledSnippet {
60
+ /** Domain that compiled this snippet */
61
+ readonly domain: string;
62
+ /** Original source code */
63
+ readonly source: string;
64
+ /** Compiled output */
65
+ readonly compiled: string;
66
+ /** Source language */
67
+ readonly language: string;
68
+ /** Source file path */
69
+ readonly file: string;
70
+ /** Line number in source file */
71
+ readonly line: number;
72
+ }
73
+
74
+ /**
75
+ * Result of batch-compiling all snippets from a project.
76
+ */
77
+ export interface AOTBatchResult {
78
+ /** Successfully compiled snippets */
79
+ readonly compiled: readonly CompiledSnippet[];
80
+ /** Snippets that failed compilation */
81
+ readonly errors: ReadonlyArray<{
82
+ readonly domain: string;
83
+ readonly source: string;
84
+ readonly file: string;
85
+ readonly line: number;
86
+ readonly message: string;
87
+ }>;
88
+ /** Summary statistics */
89
+ readonly stats: {
90
+ readonly totalSnippets: number;
91
+ readonly compiledCount: number;
92
+ readonly errorCount: number;
93
+ /** Number of snippets per domain */
94
+ readonly domainBreakdown: Record<string, number>;
95
+ };
96
+ }
97
+
98
+ // =============================================================================
99
+ // Options
100
+ // =============================================================================
101
+
102
+ /**
103
+ * Options for the generalized AOT compiler.
104
+ */
105
+ export interface GeneralizedAOTOptions {
106
+ /** Minimum confidence for semantic parsing (default: 0.7) */
107
+ readonly confidenceThreshold?: number;
108
+ /** Continue compiling other snippets on individual errors (default: true) */
109
+ readonly continueOnError?: boolean;
110
+ /** Debug mode — log extraction and compilation details */
111
+ readonly debug?: boolean;
112
+ }
113
+
114
+ /**
115
+ * Options for generating combined output.
116
+ */
117
+ export interface OutputOptions {
118
+ /** Module format (default: 'esm') */
119
+ readonly format?: 'esm' | 'cjs' | 'iife';
120
+ /** Include source location comments (default: true) */
121
+ readonly includeComments?: boolean;
122
+ /** Group output by domain (default: true) */
123
+ readonly groupByDomain?: boolean;
124
+ }