@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,171 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { createDiagnosticCollector, fromError, filterBySeverity } from './diagnostics';
3
+ import type { Diagnostic } from './diagnostics';
4
+
5
+ // =============================================================================
6
+ // DiagnosticCollector
7
+ // =============================================================================
8
+
9
+ describe('createDiagnosticCollector', () => {
10
+ it('starts with no diagnostics', () => {
11
+ const collector = createDiagnosticCollector();
12
+ expect(collector.getDiagnostics()).toHaveLength(0);
13
+ expect(collector.hasErrors()).toBe(false);
14
+ });
15
+
16
+ it('collects errors', () => {
17
+ const collector = createDiagnosticCollector();
18
+ collector.error('Something went wrong', { code: 'parse-error', line: 3 });
19
+
20
+ const diags = collector.getDiagnostics();
21
+ expect(diags).toHaveLength(1);
22
+ expect(diags[0].severity).toBe('error');
23
+ expect(diags[0].message).toBe('Something went wrong');
24
+ expect(diags[0].code).toBe('parse-error');
25
+ expect(diags[0].line).toBe(3);
26
+ });
27
+
28
+ it('collects warnings', () => {
29
+ const collector = createDiagnosticCollector();
30
+ collector.warning('Low confidence', { code: 'low-confidence' });
31
+
32
+ const diags = collector.getDiagnostics();
33
+ expect(diags).toHaveLength(1);
34
+ expect(diags[0].severity).toBe('warning');
35
+ });
36
+
37
+ it('collects info', () => {
38
+ const collector = createDiagnosticCollector();
39
+ collector.info('Consider using alternative', { suggestions: ['use select instead'] });
40
+
41
+ const diags = collector.getDiagnostics();
42
+ expect(diags).toHaveLength(1);
43
+ expect(diags[0].severity).toBe('info');
44
+ expect(diags[0].suggestions).toEqual(['use select instead']);
45
+ });
46
+
47
+ it('adds raw diagnostics', () => {
48
+ const collector = createDiagnosticCollector();
49
+ collector.add({
50
+ message: 'Custom diagnostic',
51
+ severity: 'warning',
52
+ code: 'custom',
53
+ line: 5,
54
+ column: 10,
55
+ source: 'some code',
56
+ });
57
+
58
+ const diags = collector.getDiagnostics();
59
+ expect(diags).toHaveLength(1);
60
+ expect(diags[0].column).toBe(10);
61
+ expect(diags[0].source).toBe('some code');
62
+ });
63
+
64
+ it('hasErrors returns true when errors exist', () => {
65
+ const collector = createDiagnosticCollector();
66
+ collector.warning('just a warning');
67
+ expect(collector.hasErrors()).toBe(false);
68
+
69
+ collector.error('oops');
70
+ expect(collector.hasErrors()).toBe(true);
71
+ });
72
+
73
+ it('toResult produces correct summary', () => {
74
+ const collector = createDiagnosticCollector();
75
+ collector.error('err1');
76
+ collector.error('err2');
77
+ collector.warning('warn1');
78
+ collector.info('info1');
79
+ collector.info('info2');
80
+ collector.info('info3');
81
+
82
+ const result = collector.toResult();
83
+ expect(result.ok).toBe(false);
84
+ expect(result.summary).toEqual({ errors: 2, warnings: 1, infos: 3 });
85
+ expect(result.diagnostics).toHaveLength(6);
86
+ });
87
+
88
+ it('toResult.ok is true when no errors', () => {
89
+ const collector = createDiagnosticCollector();
90
+ collector.warning('just a warning');
91
+ collector.info('just info');
92
+
93
+ const result = collector.toResult();
94
+ expect(result.ok).toBe(true);
95
+ expect(result.summary.errors).toBe(0);
96
+ });
97
+
98
+ it('omits undefined optional fields', () => {
99
+ const collector = createDiagnosticCollector();
100
+ collector.error('bare error');
101
+
102
+ const diag = collector.getDiagnostics()[0];
103
+ expect(diag.code).toBeUndefined();
104
+ expect(diag.line).toBeUndefined();
105
+ expect(diag.column).toBeUndefined();
106
+ expect(diag.source).toBeUndefined();
107
+ expect(diag.suggestions).toBeUndefined();
108
+ });
109
+
110
+ it('omits suggestions when empty array', () => {
111
+ const collector = createDiagnosticCollector();
112
+ collector.error('msg', { suggestions: [] });
113
+
114
+ const diag = collector.getDiagnostics()[0];
115
+ expect(diag.suggestions).toBeUndefined();
116
+ });
117
+ });
118
+
119
+ // =============================================================================
120
+ // fromError
121
+ // =============================================================================
122
+
123
+ describe('fromError', () => {
124
+ it('converts Error to diagnostic', () => {
125
+ const diag = fromError(new Error('Something broke'), { code: 'runtime-error', line: 42 });
126
+ expect(diag.message).toBe('Something broke');
127
+ expect(diag.severity).toBe('error');
128
+ expect(diag.code).toBe('runtime-error');
129
+ expect(diag.line).toBe(42);
130
+ });
131
+
132
+ it('converts string to diagnostic', () => {
133
+ const diag = fromError('string error');
134
+ expect(diag.message).toBe('string error');
135
+ expect(diag.severity).toBe('error');
136
+ });
137
+
138
+ it('converts unknown to diagnostic', () => {
139
+ const diag = fromError(12345);
140
+ expect(diag.message).toBe('12345');
141
+ });
142
+ });
143
+
144
+ // =============================================================================
145
+ // filterBySeverity
146
+ // =============================================================================
147
+
148
+ describe('filterBySeverity', () => {
149
+ const diagnostics: Diagnostic[] = [
150
+ { message: 'e1', severity: 'error' },
151
+ { message: 'w1', severity: 'warning' },
152
+ { message: 'e2', severity: 'error' },
153
+ { message: 'i1', severity: 'info' },
154
+ ];
155
+
156
+ it('filters errors', () => {
157
+ const errors = filterBySeverity(diagnostics, 'error');
158
+ expect(errors).toHaveLength(2);
159
+ expect(errors.every(d => d.severity === 'error')).toBe(true);
160
+ });
161
+
162
+ it('filters warnings', () => {
163
+ const warnings = filterBySeverity(diagnostics, 'warning');
164
+ expect(warnings).toHaveLength(1);
165
+ });
166
+
167
+ it('filters info', () => {
168
+ const infos = filterBySeverity(diagnostics, 'info');
169
+ expect(infos).toHaveLength(1);
170
+ });
171
+ });
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Structured Error Diagnostics
3
+ *
4
+ * Framework-level diagnostic types for reporting errors, warnings, and hints
5
+ * during parsing, validation, and compilation. These provide richer feedback
6
+ * than simple error strings, enabling:
7
+ *
8
+ * - Severity levels (error, warning, info)
9
+ * - Machine-readable error codes
10
+ * - Source location tracking
11
+ * - Actionable suggestions
12
+ * - Programmatic fix lookup
13
+ */
14
+
15
+ // =============================================================================
16
+ // Diagnostic Types
17
+ // =============================================================================
18
+
19
+ /**
20
+ * Severity level for a diagnostic.
21
+ */
22
+ export type DiagnosticSeverity = 'error' | 'warning' | 'info';
23
+
24
+ /**
25
+ * A structured diagnostic message.
26
+ *
27
+ * Diagnostics provide rich error information beyond simple strings.
28
+ * They're used for parser errors, validation warnings, and hints.
29
+ */
30
+ export interface Diagnostic {
31
+ /** Human-readable message */
32
+ readonly message: string;
33
+
34
+ /** Severity level */
35
+ readonly severity: DiagnosticSeverity;
36
+
37
+ /** Machine-readable code for programmatic handling (e.g., 'parse-error', 'missing-role') */
38
+ readonly code?: string;
39
+
40
+ /** 1-based line number in source */
41
+ readonly line?: number;
42
+
43
+ /** 0-based column offset in line */
44
+ readonly column?: number;
45
+
46
+ /** Original source text that triggered the diagnostic */
47
+ readonly source?: string;
48
+
49
+ /** Actionable suggestions for fixing the issue */
50
+ readonly suggestions?: readonly string[];
51
+ }
52
+
53
+ /**
54
+ * Result of a diagnostic-aware validation.
55
+ */
56
+ export interface DiagnosticResult {
57
+ /** Whether validation passed (no errors, though warnings/info may exist) */
58
+ readonly ok: boolean;
59
+
60
+ /** All diagnostics, including errors, warnings, and info */
61
+ readonly diagnostics: readonly Diagnostic[];
62
+
63
+ /** Convenience: count of each severity level */
64
+ readonly summary: DiagnosticSummary;
65
+ }
66
+
67
+ /**
68
+ * Summary counts by severity.
69
+ */
70
+ export interface DiagnosticSummary {
71
+ readonly errors: number;
72
+ readonly warnings: number;
73
+ readonly infos: number;
74
+ }
75
+
76
+ // =============================================================================
77
+ // Diagnostic Collector
78
+ // =============================================================================
79
+
80
+ /**
81
+ * Collects diagnostics during a parsing/validation/compilation pass.
82
+ *
83
+ * Use this in your domain's validate() or parse() to accumulate
84
+ * structured feedback instead of throwing on the first error.
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * const collector = createDiagnosticCollector();
89
+ *
90
+ * // During parsing:
91
+ * collector.error('Unknown command: foo', { code: 'unknown-command', line: 3 });
92
+ * collector.warning('Low confidence match', { code: 'low-confidence', line: 5 });
93
+ * collector.info('Consider using "select" instead of "get"', { line: 5 });
94
+ *
95
+ * // Get result:
96
+ * const result = collector.toResult();
97
+ * // { ok: false, diagnostics: [...], summary: { errors: 1, warnings: 1, infos: 1 } }
98
+ * ```
99
+ */
100
+ export interface DiagnosticCollector {
101
+ /** Add an error diagnostic */
102
+ error(message: string, options?: DiagnosticOptions): void;
103
+
104
+ /** Add a warning diagnostic */
105
+ warning(message: string, options?: DiagnosticOptions): void;
106
+
107
+ /** Add an info diagnostic */
108
+ info(message: string, options?: DiagnosticOptions): void;
109
+
110
+ /** Add a diagnostic with explicit severity */
111
+ add(diagnostic: Diagnostic): void;
112
+
113
+ /** Whether any errors have been collected */
114
+ hasErrors(): boolean;
115
+
116
+ /** Get all collected diagnostics */
117
+ getDiagnostics(): readonly Diagnostic[];
118
+
119
+ /** Build a DiagnosticResult from collected diagnostics */
120
+ toResult(): DiagnosticResult;
121
+ }
122
+
123
+ /**
124
+ * Options for adding a diagnostic via the collector's convenience methods.
125
+ */
126
+ export interface DiagnosticOptions {
127
+ readonly code?: string;
128
+ readonly line?: number;
129
+ readonly column?: number;
130
+ readonly source?: string;
131
+ readonly suggestions?: readonly string[];
132
+ }
133
+
134
+ // =============================================================================
135
+ // Factory
136
+ // =============================================================================
137
+
138
+ /**
139
+ * Create a new diagnostic collector.
140
+ */
141
+ export function createDiagnosticCollector(): DiagnosticCollector {
142
+ const diagnostics: Diagnostic[] = [];
143
+
144
+ function addWithSeverity(
145
+ severity: DiagnosticSeverity,
146
+ message: string,
147
+ options?: DiagnosticOptions
148
+ ): void {
149
+ const diag: Diagnostic = {
150
+ message,
151
+ severity,
152
+ ...(options?.code != null && { code: options.code }),
153
+ ...(options?.line != null && { line: options.line }),
154
+ ...(options?.column != null && { column: options.column }),
155
+ ...(options?.source != null && { source: options.source }),
156
+ ...(options?.suggestions != null &&
157
+ options.suggestions.length > 0 && { suggestions: options.suggestions }),
158
+ };
159
+ diagnostics.push(diag);
160
+ }
161
+
162
+ return {
163
+ error(message, options) {
164
+ addWithSeverity('error', message, options);
165
+ },
166
+
167
+ warning(message, options) {
168
+ addWithSeverity('warning', message, options);
169
+ },
170
+
171
+ info(message, options) {
172
+ addWithSeverity('info', message, options);
173
+ },
174
+
175
+ add(diagnostic) {
176
+ diagnostics.push(diagnostic);
177
+ },
178
+
179
+ hasErrors() {
180
+ return diagnostics.some(d => d.severity === 'error');
181
+ },
182
+
183
+ getDiagnostics() {
184
+ return diagnostics;
185
+ },
186
+
187
+ toResult(): DiagnosticResult {
188
+ let errors = 0;
189
+ let warnings = 0;
190
+ let infos = 0;
191
+ for (const d of diagnostics) {
192
+ if (d.severity === 'error') errors++;
193
+ else if (d.severity === 'warning') warnings++;
194
+ else infos++;
195
+ }
196
+
197
+ return {
198
+ ok: errors === 0,
199
+ diagnostics,
200
+ summary: { errors, warnings, infos },
201
+ };
202
+ },
203
+ };
204
+ }
205
+
206
+ // =============================================================================
207
+ // Helpers
208
+ // =============================================================================
209
+
210
+ /**
211
+ * Create a diagnostic from an Error object.
212
+ * Useful for converting caught exceptions into structured diagnostics.
213
+ */
214
+ export function fromError(
215
+ error: unknown,
216
+ options?: Omit<DiagnosticOptions, 'code'> & { code?: string }
217
+ ): Diagnostic {
218
+ const message = error instanceof Error ? error.message : String(error);
219
+ return {
220
+ message,
221
+ severity: 'error',
222
+ ...(options?.code != null && { code: options.code }),
223
+ ...(options?.line != null && { line: options.line }),
224
+ ...(options?.column != null && { column: options.column }),
225
+ ...(options?.source != null && { source: options.source }),
226
+ ...(options?.suggestions != null &&
227
+ options.suggestions.length > 0 && { suggestions: options.suggestions }),
228
+ };
229
+ }
230
+
231
+ /**
232
+ * Filter diagnostics by severity.
233
+ */
234
+ export function filterBySeverity(
235
+ diagnostics: readonly Diagnostic[],
236
+ severity: DiagnosticSeverity
237
+ ): readonly Diagnostic[] {
238
+ return diagnostics.filter(d => d.severity === severity);
239
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Pattern generation, rendering, and diagnostics
3
+ */
4
+
5
+ export * from './pattern-generator';
6
+ export * from './renderer';
7
+ export * from './diagnostics';