wyreframe 0.1.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/README.md +123 -0
- package/dist/index.d.ts +267 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +195 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -0
- package/src/parser/Core/Bounds.mjs +61 -0
- package/src/parser/Core/Bounds.res +65 -0
- package/src/parser/Core/Grid.mjs +268 -0
- package/src/parser/Core/Grid.res +265 -0
- package/src/parser/Core/Position.mjs +83 -0
- package/src/parser/Core/Position.res +54 -0
- package/src/parser/Core/Types.mjs +435 -0
- package/src/parser/Core/Types.res +331 -0
- package/src/parser/Core/__tests__/Bounds_test.mjs +326 -0
- package/src/parser/Core/__tests__/Bounds_test.res +412 -0
- package/src/parser/Core/__tests__/Grid_test.mjs +322 -0
- package/src/parser/Core/__tests__/Grid_test.res +319 -0
- package/src/parser/Core/__tests__/Types_test.mjs +614 -0
- package/src/parser/Core/__tests__/Types_test.res +650 -0
- package/src/parser/Detector/BoxTracer.mjs +302 -0
- package/src/parser/Detector/BoxTracer.res +374 -0
- package/src/parser/Detector/HierarchyBuilder.mjs +158 -0
- package/src/parser/Detector/HierarchyBuilder.res +315 -0
- package/src/parser/Detector/ShapeDetector.mjs +134 -0
- package/src/parser/Detector/ShapeDetector.res +236 -0
- package/src/parser/Detector/__tests__/BoxTracer_test.mjs +70 -0
- package/src/parser/Detector/__tests__/BoxTracer_test.res +92 -0
- package/src/parser/Detector/__tests__/HierarchyBuilder_test.mjs +489 -0
- package/src/parser/Detector/__tests__/HierarchyBuilder_test.res +849 -0
- package/src/parser/Detector/__tests__/ShapeDetector_test.mjs +377 -0
- package/src/parser/Detector/__tests__/ShapeDetector_test.res +563 -0
- package/src/parser/Errors/ErrorContext.mjs +106 -0
- package/src/parser/Errors/ErrorContext.res +191 -0
- package/src/parser/Errors/ErrorMessages.mjs +289 -0
- package/src/parser/Errors/ErrorMessages.res +303 -0
- package/src/parser/Errors/ErrorTypes.mjs +105 -0
- package/src/parser/Errors/ErrorTypes.res +169 -0
- package/src/parser/Interactions/InteractionMerger.mjs +266 -0
- package/src/parser/Interactions/InteractionMerger.res +450 -0
- package/src/parser/Interactions/InteractionParser.mjs +88 -0
- package/src/parser/Interactions/InteractionParser.res +127 -0
- package/src/parser/Interactions/SimpleInteractionParser.mjs +278 -0
- package/src/parser/Interactions/SimpleInteractionParser.res +262 -0
- package/src/parser/Interactions/__tests__/InteractionMerger_test.mjs +576 -0
- package/src/parser/Interactions/__tests__/InteractionMerger_test.res +646 -0
- package/src/parser/Parser.gen.tsx +96 -0
- package/src/parser/Parser.mjs +212 -0
- package/src/parser/Parser.res +481 -0
- package/src/parser/Scanner/__tests__/Grid_manual.mjs +214 -0
- package/src/parser/Scanner/__tests__/Grid_manual.res +141 -0
- package/src/parser/Semantic/ASTBuilder.mjs +197 -0
- package/src/parser/Semantic/ASTBuilder.res +288 -0
- package/src/parser/Semantic/AlignmentCalc.mjs +41 -0
- package/src/parser/Semantic/AlignmentCalc.res +104 -0
- package/src/parser/Semantic/Elements/ButtonParser.mjs +58 -0
- package/src/parser/Semantic/Elements/ButtonParser.res +131 -0
- package/src/parser/Semantic/Elements/CheckboxParser.mjs +58 -0
- package/src/parser/Semantic/Elements/CheckboxParser.res +79 -0
- package/src/parser/Semantic/Elements/CodeTextParser.mjs +50 -0
- package/src/parser/Semantic/Elements/CodeTextParser.res +111 -0
- package/src/parser/Semantic/Elements/ElementParser.mjs +15 -0
- package/src/parser/Semantic/Elements/ElementParser.res +83 -0
- package/src/parser/Semantic/Elements/EmphasisParser.mjs +46 -0
- package/src/parser/Semantic/Elements/EmphasisParser.res +67 -0
- package/src/parser/Semantic/Elements/InputParser.mjs +41 -0
- package/src/parser/Semantic/Elements/InputParser.res +97 -0
- package/src/parser/Semantic/Elements/LinkParser.mjs +60 -0
- package/src/parser/Semantic/Elements/LinkParser.res +156 -0
- package/src/parser/Semantic/Elements/TextParser.mjs +19 -0
- package/src/parser/Semantic/Elements/TextParser.res +42 -0
- package/src/parser/Semantic/Elements/__tests__/ButtonParser_test.mjs +189 -0
- package/src/parser/Semantic/Elements/__tests__/ButtonParser_test.res +257 -0
- package/src/parser/Semantic/Elements/__tests__/CheckboxParser_test.mjs +202 -0
- package/src/parser/Semantic/Elements/__tests__/CheckboxParser_test.res +250 -0
- package/src/parser/Semantic/Elements/__tests__/CodeTextParser_manual.mjs +293 -0
- package/src/parser/Semantic/Elements/__tests__/CodeTextParser_manual.res +134 -0
- package/src/parser/Semantic/Elements/__tests__/InputParser_test.mjs +253 -0
- package/src/parser/Semantic/Elements/__tests__/InputParser_test.res +304 -0
- package/src/parser/Semantic/Elements/__tests__/LinkParser_test.mjs +289 -0
- package/src/parser/Semantic/Elements/__tests__/LinkParser_test.res +402 -0
- package/src/parser/Semantic/Elements/__tests__/TextParser_test.mjs +149 -0
- package/src/parser/Semantic/Elements/__tests__/TextParser_test.res +167 -0
- package/src/parser/Semantic/ParserRegistry.mjs +82 -0
- package/src/parser/Semantic/ParserRegistry.res +145 -0
- package/src/parser/Semantic/SemanticParser.mjs +850 -0
- package/src/parser/Semantic/SemanticParser.res +1368 -0
- package/src/parser/Semantic/__tests__/ASTBuilder_test.mjs +187 -0
- package/src/parser/Semantic/__tests__/ASTBuilder_test.res +192 -0
- package/src/parser/Semantic/__tests__/ParserRegistry_test.mjs +154 -0
- package/src/parser/Semantic/__tests__/ParserRegistry_test.res +191 -0
- package/src/parser/Semantic/__tests__/SemanticParser_integration_test.mjs +768 -0
- package/src/parser/Semantic/__tests__/SemanticParser_integration_test.res +1069 -0
- package/src/parser/Semantic/__tests__/SemanticParser_manual.mjs +1329 -0
- package/src/parser/Semantic/__tests__/SemanticParser_manual.res +544 -0
- package/src/parser/TestMain.mjs +21 -0
- package/src/parser/TestMain.res +14 -0
- package/src/parser/TextExtractor.mjs +179 -0
- package/src/parser/TextExtractor.res +264 -0
- package/src/parser/__tests__/GridScanner_integration.test.mjs +632 -0
- package/src/parser/__tests__/GridScanner_integration.test.res +816 -0
- package/src/parser/__tests__/Performance.test.mjs +244 -0
- package/src/parser/__tests__/Performance.test.res +371 -0
- package/src/parser/__tests__/PerformanceFixtures.mjs +200 -0
- package/src/parser/__tests__/PerformanceFixtures.res +284 -0
- package/src/parser/__tests__/WyreframeParser_integration.test.mjs +770 -0
- package/src/parser/__tests__/WyreframeParser_integration.test.res +1008 -0
- package/src/parser/__tests__/fixtures/alignment-test.txt +9 -0
- package/src/parser/__tests__/fixtures/all-elements.txt +16 -0
- package/src/parser/__tests__/fixtures/login-scene.txt +17 -0
- package/src/parser/__tests__/fixtures/multi-scene.txt +25 -0
- package/src/parser/__tests__/fixtures/nested-boxes.txt +15 -0
- package/src/parser/__tests__/fixtures/simple-box.txt +5 -0
- package/src/parser/__tests__/fixtures/with-dividers.txt +14 -0
- package/src/renderer/Renderer.gen.tsx +32 -0
- package/src/renderer/Renderer.mjs +391 -0
- package/src/renderer/Renderer.res +558 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
// ErrorMessages.res
|
|
2
|
+
// Natural language error message templates for all parser error codes
|
|
3
|
+
|
|
4
|
+
// Import error types
|
|
5
|
+
open ErrorTypes
|
|
6
|
+
|
|
7
|
+
// Template type containing structured error message parts
|
|
8
|
+
type template = {
|
|
9
|
+
title: string,
|
|
10
|
+
message: string,
|
|
11
|
+
solution: string,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Helper function to format position as "row X, column Y" (1-indexed for user display)
|
|
15
|
+
let formatPosition = (pos: Types.Position.t): string => {
|
|
16
|
+
`row ${Int.toString(pos.row + 1)}, column ${Int.toString(pos.col + 1)}`
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Helper function to format optional box name
|
|
20
|
+
let formatBoxName = (name: option<string>): string => {
|
|
21
|
+
switch name {
|
|
22
|
+
| Some(n) => `"${n}"`
|
|
23
|
+
| None => "unnamed box"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Get error message template for a specific error code
|
|
28
|
+
let getTemplate = (code: errorCode): template => {
|
|
29
|
+
switch code {
|
|
30
|
+
// Structural Errors
|
|
31
|
+
| UncloseBox({corner, direction}) => {
|
|
32
|
+
title: "❌ Box is not closed",
|
|
33
|
+
message: `Box opened at ${formatPosition(corner)} but never closed on the ${direction} side.
|
|
34
|
+
|
|
35
|
+
The parser detected a '+' corner character that starts a box, but couldn't find the matching closing border. This usually happens when:
|
|
36
|
+
• The closing corner '+' is missing
|
|
37
|
+
• The border characters ('-' or '|') are broken or incomplete
|
|
38
|
+
• The box structure is malformed`,
|
|
39
|
+
solution: `💡 Solution:
|
|
40
|
+
Add the missing ${direction} border to close the box:
|
|
41
|
+
• If ${direction} is "top" or "bottom": use '+' corners and '-' characters
|
|
42
|
+
• If ${direction} is "left" or "right": use '+' corners and '|' characters
|
|
43
|
+
• Ensure all four corners are present and borders are continuous`,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
| MismatchedWidth({topLeft, topWidth, bottomWidth}) => {
|
|
47
|
+
title: "❌ Box width mismatch",
|
|
48
|
+
message: `Box starting at ${formatPosition(topLeft)} has different widths on top and bottom borders:
|
|
49
|
+
• Top border: ${Int.toString(topWidth)} characters wide
|
|
50
|
+
• Bottom border: ${Int.toString(bottomWidth)} characters wide
|
|
51
|
+
|
|
52
|
+
All boxes must have matching top and bottom border widths to form a valid rectangle.`,
|
|
53
|
+
solution: `💡 Solution:
|
|
54
|
+
Make both borders the same width. Adjust the ${topWidth > bottomWidth ? "bottom" : "top"} border to match:
|
|
55
|
+
• Add ${Int.toString(Js.Math.abs_int(topWidth - bottomWidth))} ${topWidth > bottomWidth ? "dashes" : "dashes"} to make them equal
|
|
56
|
+
• Count carefully: include both corner '+' characters in the width
|
|
57
|
+
• Example: "+----+" is 6 characters wide (including corners)`,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
| MisalignedPipe({position, expectedCol, actualCol}) => {
|
|
61
|
+
title: "❌ Vertical border misaligned",
|
|
62
|
+
message: `The '|' character at ${formatPosition(position)} is not aligned with the box edge:
|
|
63
|
+
• Expected column: ${Int.toString(expectedCol + 1)}
|
|
64
|
+
• Actual column: ${Int.toString(actualCol + 1)}
|
|
65
|
+
• Off by: ${Int.toString(Js.Math.abs_int(expectedCol - actualCol))} ${Js.Math.abs_int(expectedCol - actualCol) === 1 ? "space" : "spaces"}
|
|
66
|
+
|
|
67
|
+
Vertical borders must be perfectly aligned to form valid box sides.`,
|
|
68
|
+
solution: `💡 Solution:
|
|
69
|
+
Move the '|' character to column ${Int.toString(expectedCol + 1)}:
|
|
70
|
+
• ${expectedCol > actualCol ? "Add" : "Remove"} ${Int.toString(Js.Math.abs_int(expectedCol - actualCol))} space${Js.Math.abs_int(expectedCol - actualCol) === 1 ? "" : "s"} ${expectedCol > actualCol ? "before" : "after"} the '|' character
|
|
71
|
+
• Use a monospace font editor to ensure proper alignment
|
|
72
|
+
• Check that all '|' characters in this box are in the same column`,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
| OverlappingBoxes({box1Name, box2Name, position}) => {
|
|
76
|
+
title: "❌ Overlapping boxes detected",
|
|
77
|
+
message: `Two boxes overlap at ${formatPosition(position)} but neither completely contains the other:
|
|
78
|
+
• Box 1: ${formatBoxName(box1Name)}
|
|
79
|
+
• Box 2: ${formatBoxName(box2Name)}
|
|
80
|
+
|
|
81
|
+
Boxes must either:
|
|
82
|
+
• Be completely nested (one fully inside the other), OR
|
|
83
|
+
• Be completely separate (no overlap at all)`,
|
|
84
|
+
solution: `💡 Solution:
|
|
85
|
+
Fix the overlap by either:
|
|
86
|
+
1. Nesting: Make one box completely inside the other
|
|
87
|
+
• Ensure all four borders of the inner box are inside the outer box
|
|
88
|
+
2. Separating: Move the boxes so they don't touch
|
|
89
|
+
• Add space between the boxes
|
|
90
|
+
• Or place them on different rows
|
|
91
|
+
|
|
92
|
+
Partial overlaps are not allowed in the wireframe syntax.`,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Syntax Errors
|
|
96
|
+
| InvalidElement({content, position}) => {
|
|
97
|
+
title: "❌ Invalid element syntax",
|
|
98
|
+
message: `Unrecognized element syntax at ${formatPosition(position)}:
|
|
99
|
+
"${content}"
|
|
100
|
+
|
|
101
|
+
The parser couldn't match this content to any known element pattern:
|
|
102
|
+
• Buttons: [ Text ]
|
|
103
|
+
• Inputs: #fieldname
|
|
104
|
+
• Links: "Link Text"
|
|
105
|
+
• Checkboxes: [x] or [ ]
|
|
106
|
+
• Emphasis: * Text`,
|
|
107
|
+
solution: `💡 Solution:
|
|
108
|
+
Check the element syntax and fix any typos:
|
|
109
|
+
• Make sure brackets match: [ and ]
|
|
110
|
+
• Ensure quotes are paired: "text"
|
|
111
|
+
• Verify input fields start with #
|
|
112
|
+
• Use supported element patterns from the documentation
|
|
113
|
+
|
|
114
|
+
If this is plain text, it will be treated as a text element automatically.`,
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
| UnclosedBracket({opening}) => {
|
|
118
|
+
title: "❌ Unclosed bracket",
|
|
119
|
+
message: `Opening bracket '[' at ${formatPosition(opening)} is never closed.
|
|
120
|
+
|
|
121
|
+
This bracket starts a button or checkbox but has no matching closing ']' bracket.`,
|
|
122
|
+
solution: `💡 Solution:
|
|
123
|
+
Add the closing ']' bracket to complete the element:
|
|
124
|
+
• For buttons: [ Button Text ]
|
|
125
|
+
• For checkboxes: [x] or [ ]
|
|
126
|
+
|
|
127
|
+
Make sure both brackets are on the same line.`,
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
| EmptyButton({position}) => {
|
|
131
|
+
title: "❌ Empty button",
|
|
132
|
+
message: `Button at ${formatPosition(position)} has no text content.
|
|
133
|
+
|
|
134
|
+
Buttons must have descriptive text between the brackets: [ Text ]`,
|
|
135
|
+
solution: `💡 Solution:
|
|
136
|
+
Add text between the brackets:
|
|
137
|
+
• Bad: [ ]
|
|
138
|
+
• Good: [ Submit ]
|
|
139
|
+
• Good: [ Click Here ]
|
|
140
|
+
|
|
141
|
+
Button text should clearly describe the action.`,
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
| InvalidInteractionDSL({message, position}) => {
|
|
145
|
+
let posInfo = switch position {
|
|
146
|
+
| Some(pos) => ` at ${formatPosition(pos)}`
|
|
147
|
+
| None => ""
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
{
|
|
151
|
+
title: "❌ Invalid interaction syntax",
|
|
152
|
+
message: `Failed to parse interaction DSL${posInfo}:
|
|
153
|
+
${message}
|
|
154
|
+
|
|
155
|
+
The interaction definition doesn't match the expected YAML-like syntax.`,
|
|
156
|
+
solution: `💡 Solution:
|
|
157
|
+
Check your interaction syntax:
|
|
158
|
+
• Scene declarations: @scene: sceneName
|
|
159
|
+
• Element selectors: #input: or [ button ]:
|
|
160
|
+
• Properties: indent with 2 spaces, use "key: value"
|
|
161
|
+
• Actions: @click -> goto(target)
|
|
162
|
+
|
|
163
|
+
Refer to the interaction DSL documentation for examples.`,
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Warnings
|
|
168
|
+
| UnusualSpacing({position, issue}) => {
|
|
169
|
+
title: "⚠️ Unusual spacing detected",
|
|
170
|
+
message: `Spacing issue at ${formatPosition(position)}:
|
|
171
|
+
${issue}
|
|
172
|
+
|
|
173
|
+
While this may still parse correctly, it could cause alignment problems in some environments.`,
|
|
174
|
+
solution: `💡 Solution:
|
|
175
|
+
Normalize the spacing:
|
|
176
|
+
• Use spaces instead of tabs for alignment
|
|
177
|
+
• Use consistent spacing throughout the wireframe
|
|
178
|
+
• Use a monospace font to verify alignment visually
|
|
179
|
+
|
|
180
|
+
This is a warning - parsing will continue.`,
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
| DeepNesting({depth, position}) => {
|
|
184
|
+
title: "⚠️ Deep nesting detected",
|
|
185
|
+
message: `Box at ${formatPosition(position)} is nested ${Int.toString(depth)} levels deep.
|
|
186
|
+
|
|
187
|
+
While technically valid, deeply nested boxes can:
|
|
188
|
+
• Reduce readability
|
|
189
|
+
• Make maintenance difficult
|
|
190
|
+
• Indicate overly complex UI structure`,
|
|
191
|
+
solution: `💡 Solution:
|
|
192
|
+
Consider simplifying the structure:
|
|
193
|
+
• Flatten the hierarchy where possible
|
|
194
|
+
• Split complex sections into separate scenes
|
|
195
|
+
• Use dividers (===) instead of nested boxes for simple grouping
|
|
196
|
+
• Keep nesting to 3-4 levels maximum for best readability
|
|
197
|
+
|
|
198
|
+
This is a warning - parsing will continue.`,
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
| InvalidInput({message}) => {
|
|
202
|
+
title: "❌ Invalid input",
|
|
203
|
+
message: `${message}
|
|
204
|
+
|
|
205
|
+
The input could not be processed due to formatting or content issues.`,
|
|
206
|
+
solution: `💡 Solution:
|
|
207
|
+
Check your input format:
|
|
208
|
+
• Ensure the wireframe text is properly formatted
|
|
209
|
+
• Use ASCII characters for box drawing
|
|
210
|
+
• Check for encoding issues if pasting from external sources`,
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
| InvalidStartPosition(position) => {
|
|
214
|
+
title: "❌ Invalid starting position",
|
|
215
|
+
message: `Position ${formatPosition(position)} is not a valid corner for box tracing.
|
|
216
|
+
|
|
217
|
+
Box tracing must start from a '+' character that forms a valid corner.`,
|
|
218
|
+
solution: `💡 Solution:
|
|
219
|
+
Ensure the starting position:
|
|
220
|
+
• Contains a '+' character
|
|
221
|
+
• Is part of a complete box structure
|
|
222
|
+
• Has valid border characters adjacent to it`,
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Format complete error message from error code
|
|
228
|
+
let format = (code: errorCode): string => {
|
|
229
|
+
let template = getTemplate(code)
|
|
230
|
+
|
|
231
|
+
`${template.title}
|
|
232
|
+
|
|
233
|
+
${template.message}
|
|
234
|
+
|
|
235
|
+
${template.solution}`
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Format error message from ParseError type
|
|
239
|
+
let formatError = (error: t): string => {
|
|
240
|
+
format(error.code)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Format complete error message from ParseError with code snippet context
|
|
244
|
+
// Includes: title, message, code snippet (if available), and solution
|
|
245
|
+
let formatWithContext = (error: t): string => {
|
|
246
|
+
let template = getTemplate(error.code)
|
|
247
|
+
|
|
248
|
+
// Build the formatted message parts
|
|
249
|
+
let parts = []
|
|
250
|
+
|
|
251
|
+
// 1. Title
|
|
252
|
+
parts->Js.Array2.push(template.title)->ignore
|
|
253
|
+
parts->Js.Array2.push("")->ignore
|
|
254
|
+
|
|
255
|
+
// 2. Message
|
|
256
|
+
parts->Js.Array2.push(template.message)->ignore
|
|
257
|
+
parts->Js.Array2.push("")->ignore
|
|
258
|
+
|
|
259
|
+
// 3. Code Snippet (if context is available)
|
|
260
|
+
switch error.context {
|
|
261
|
+
| Some(ctx) => {
|
|
262
|
+
let snippet = ErrorContext.getSnippet(ctx)
|
|
263
|
+
parts->Js.Array2.push("📍 Location:")->ignore
|
|
264
|
+
parts->Js.Array2.push("")->ignore
|
|
265
|
+
parts->Js.Array2.push(snippet)->ignore
|
|
266
|
+
parts->Js.Array2.push("")->ignore
|
|
267
|
+
}
|
|
268
|
+
| None => ()
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// 4. Solution
|
|
272
|
+
parts->Js.Array2.push(template.solution)->ignore
|
|
273
|
+
|
|
274
|
+
// Join all parts with newlines
|
|
275
|
+
parts->Js.Array2.joinWith("\n")
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Format complete error message from ParseError type
|
|
279
|
+
// Uses formatWithContext if context is available, otherwise uses simple format
|
|
280
|
+
let formatComplete = (error: t): string => {
|
|
281
|
+
switch error.context {
|
|
282
|
+
| Some(_) => formatWithContext(error)
|
|
283
|
+
| None => formatError(error)
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Get just the title from an error code
|
|
288
|
+
let getTitle = (code: errorCode): string => {
|
|
289
|
+
let template = getTemplate(code)
|
|
290
|
+
template.title
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Get just the message from an error code
|
|
294
|
+
let getMessage = (code: errorCode): string => {
|
|
295
|
+
let template = getTemplate(code)
|
|
296
|
+
template.message
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Get just the solution from an error code
|
|
300
|
+
let getSolution = (code: errorCode): string => {
|
|
301
|
+
let template = getTemplate(code)
|
|
302
|
+
template.solution
|
|
303
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Types from "../Core/Types.mjs";
|
|
4
|
+
import * as ErrorContext from "./ErrorContext.mjs";
|
|
5
|
+
|
|
6
|
+
function getSeverity(code) {
|
|
7
|
+
switch (code.TAG) {
|
|
8
|
+
case "UnusualSpacing" :
|
|
9
|
+
case "DeepNesting" :
|
|
10
|
+
return "Warning";
|
|
11
|
+
default:
|
|
12
|
+
return "Error";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function make(code, context) {
|
|
17
|
+
return {
|
|
18
|
+
code: code,
|
|
19
|
+
severity: getSeverity(code),
|
|
20
|
+
context: context
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function makeSimple(code) {
|
|
25
|
+
return make(code, undefined);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function makeWithGrid(code, grid, position) {
|
|
29
|
+
let typesPosition = Types.Position.make(position.row, position.col);
|
|
30
|
+
let context = ErrorContext.make(grid, typesPosition, undefined);
|
|
31
|
+
return make(code, context);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function getPosition(code) {
|
|
35
|
+
switch (code.TAG) {
|
|
36
|
+
case "InvalidInput" :
|
|
37
|
+
return;
|
|
38
|
+
case "InvalidStartPosition" :
|
|
39
|
+
return code._0;
|
|
40
|
+
case "UncloseBox" :
|
|
41
|
+
return code.corner;
|
|
42
|
+
case "MismatchedWidth" :
|
|
43
|
+
return code.topLeft;
|
|
44
|
+
case "OverlappingBoxes" :
|
|
45
|
+
return code.position;
|
|
46
|
+
case "UnclosedBracket" :
|
|
47
|
+
return code.opening;
|
|
48
|
+
case "InvalidInteractionDSL" :
|
|
49
|
+
return code.position;
|
|
50
|
+
case "InvalidElement" :
|
|
51
|
+
case "DeepNesting" :
|
|
52
|
+
return code.position;
|
|
53
|
+
default:
|
|
54
|
+
return code.position;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function isWarning(error) {
|
|
59
|
+
return error.severity === "Warning";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function isError(error) {
|
|
63
|
+
return error.severity === "Error";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function getCodeName(code) {
|
|
67
|
+
switch (code.TAG) {
|
|
68
|
+
case "InvalidInput" :
|
|
69
|
+
return "InvalidInput";
|
|
70
|
+
case "InvalidStartPosition" :
|
|
71
|
+
return "InvalidStartPosition";
|
|
72
|
+
case "UncloseBox" :
|
|
73
|
+
return "UncloseBox";
|
|
74
|
+
case "MismatchedWidth" :
|
|
75
|
+
return "MismatchedWidth";
|
|
76
|
+
case "MisalignedPipe" :
|
|
77
|
+
return "MisalignedPipe";
|
|
78
|
+
case "OverlappingBoxes" :
|
|
79
|
+
return "OverlappingBoxes";
|
|
80
|
+
case "InvalidElement" :
|
|
81
|
+
return "InvalidElement";
|
|
82
|
+
case "UnclosedBracket" :
|
|
83
|
+
return "UnclosedBracket";
|
|
84
|
+
case "EmptyButton" :
|
|
85
|
+
return "EmptyButton";
|
|
86
|
+
case "InvalidInteractionDSL" :
|
|
87
|
+
return "InvalidInteractionDSL";
|
|
88
|
+
case "UnusualSpacing" :
|
|
89
|
+
return "UnusualSpacing";
|
|
90
|
+
case "DeepNesting" :
|
|
91
|
+
return "DeepNesting";
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export {
|
|
96
|
+
getSeverity,
|
|
97
|
+
make,
|
|
98
|
+
makeSimple,
|
|
99
|
+
makeWithGrid,
|
|
100
|
+
getPosition,
|
|
101
|
+
isWarning,
|
|
102
|
+
isError,
|
|
103
|
+
getCodeName,
|
|
104
|
+
}
|
|
105
|
+
/* Types Not a pure module */
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// ErrorTypes.res
|
|
2
|
+
// Structured error types for the Wyreframe parser
|
|
3
|
+
// Provides comprehensive error classification with contextual information
|
|
4
|
+
|
|
5
|
+
open Types
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Error severity levels for categorizing parser errors
|
|
9
|
+
*/
|
|
10
|
+
type severity =
|
|
11
|
+
| Error // Fatal errors that prevent parsing
|
|
12
|
+
| Warning // Non-fatal issues that should be addressed
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Comprehensive error code variants for all parser stages
|
|
16
|
+
* Each variant carries specific context for helpful error messages
|
|
17
|
+
*/
|
|
18
|
+
type errorCode =
|
|
19
|
+
// Grid Scanner Errors
|
|
20
|
+
| InvalidInput({message: string}) // Invalid input format
|
|
21
|
+
// Shape Detector Errors - Box Tracing (REQ-3, REQ-7)
|
|
22
|
+
| InvalidStartPosition(Position.t) // Starting position is not a corner
|
|
23
|
+
| UncloseBox({
|
|
24
|
+
corner: Position.t,
|
|
25
|
+
direction: string, // "top", "right", "bottom", or "left"
|
|
26
|
+
}) // Box edge not closed - consolidated variant
|
|
27
|
+
| MismatchedWidth({
|
|
28
|
+
topLeft: Position.t,
|
|
29
|
+
topWidth: int,
|
|
30
|
+
bottomWidth: int,
|
|
31
|
+
}) // Top and bottom widths don't match (REQ-7)
|
|
32
|
+
| MisalignedPipe({
|
|
33
|
+
position: Position.t,
|
|
34
|
+
expectedCol: int,
|
|
35
|
+
actualCol: int,
|
|
36
|
+
}) // Vertical pipe not aligned with box edge (REQ-7)
|
|
37
|
+
| OverlappingBoxes({
|
|
38
|
+
box1Name: option<string>,
|
|
39
|
+
box2Name: option<string>,
|
|
40
|
+
position: Position.t,
|
|
41
|
+
}) // Boxes overlap incorrectly (REQ-6)
|
|
42
|
+
// Semantic Parser Errors
|
|
43
|
+
| InvalidElement({
|
|
44
|
+
content: string,
|
|
45
|
+
position: Position.t,
|
|
46
|
+
}) // Unknown element syntax (REQ-19)
|
|
47
|
+
| UnclosedBracket({opening: Position.t}) // Bracket not closed (REQ-19)
|
|
48
|
+
| EmptyButton({position: Position.t}) // Button has no text (REQ-19)
|
|
49
|
+
| InvalidInteractionDSL({
|
|
50
|
+
message: string,
|
|
51
|
+
position: option<Position.t>,
|
|
52
|
+
}) // Interaction DSL parsing failed
|
|
53
|
+
// Warnings (REQ-19)
|
|
54
|
+
| UnusualSpacing({
|
|
55
|
+
position: Position.t,
|
|
56
|
+
issue: string,
|
|
57
|
+
}) // Tabs instead of spaces, etc.
|
|
58
|
+
| DeepNesting({
|
|
59
|
+
depth: int,
|
|
60
|
+
position: Position.t,
|
|
61
|
+
}) // Nesting depth exceeds recommended level
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Complete parse error with error code, severity, and context
|
|
65
|
+
*/
|
|
66
|
+
type t = {
|
|
67
|
+
code: errorCode,
|
|
68
|
+
severity: severity,
|
|
69
|
+
context: option<ErrorContext.t>,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Determine severity from error code
|
|
74
|
+
* Warnings start with "Unusual" or "Deep", all others are Errors
|
|
75
|
+
*/
|
|
76
|
+
let getSeverity = (code: errorCode): severity => {
|
|
77
|
+
switch code {
|
|
78
|
+
| UnusualSpacing(_) | DeepNesting(_) => Warning
|
|
79
|
+
| _ => Error
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Create a ParseError from an error code
|
|
85
|
+
* Automatically determines severity based on error type
|
|
86
|
+
*/
|
|
87
|
+
let make = (code: errorCode, context: option<ErrorContext.t>): t => {
|
|
88
|
+
{
|
|
89
|
+
code: code,
|
|
90
|
+
severity: getSeverity(code),
|
|
91
|
+
context: context,
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Create a ParseError without context (simple errors)
|
|
97
|
+
* Useful when grid context is not available or needed
|
|
98
|
+
* REQ-16: Structured error objects
|
|
99
|
+
*/
|
|
100
|
+
let makeSimple = (code: errorCode): t => {
|
|
101
|
+
make(code, None)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Create a ParseError from an error code with grid context
|
|
106
|
+
* Builds error context from grid and position
|
|
107
|
+
* REQ-18: Contextual code snippets
|
|
108
|
+
*/
|
|
109
|
+
let makeWithGrid = (code: errorCode, grid: Grid.t, position: Position.t): t => {
|
|
110
|
+
let typesPosition = Types.Position.make(position.row, position.col)
|
|
111
|
+
let context = ErrorContext.make(grid, typesPosition)
|
|
112
|
+
make(code, Some(context))
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Get position from error code if available
|
|
117
|
+
* Returns the primary position associated with the error
|
|
118
|
+
*/
|
|
119
|
+
let getPosition = (code: errorCode): option<Position.t> => {
|
|
120
|
+
switch code {
|
|
121
|
+
| InvalidInput(_) => None
|
|
122
|
+
| InvalidStartPosition(pos) => Some(pos)
|
|
123
|
+
| UncloseBox({corner}) => Some(corner)
|
|
124
|
+
| MismatchedWidth({topLeft}) => Some(topLeft)
|
|
125
|
+
| MisalignedPipe({position}) => Some(position)
|
|
126
|
+
| OverlappingBoxes({position}) => Some(position)
|
|
127
|
+
| InvalidElement({position}) => Some(position)
|
|
128
|
+
| UnclosedBracket({opening}) => Some(opening)
|
|
129
|
+
| EmptyButton({position}) => Some(position)
|
|
130
|
+
| InvalidInteractionDSL({position}) => position
|
|
131
|
+
| UnusualSpacing({position}) => Some(position)
|
|
132
|
+
| DeepNesting({position}) => Some(position)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Check if error is a warning
|
|
138
|
+
*/
|
|
139
|
+
let isWarning = (error: t): bool => {
|
|
140
|
+
error.severity == Warning
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Check if error is an error (not a warning)
|
|
145
|
+
*/
|
|
146
|
+
let isError = (error: t): bool => {
|
|
147
|
+
error.severity == Error
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get error code name as string (useful for logging/debugging)
|
|
152
|
+
* REQ-16: Error codes for different types of problems
|
|
153
|
+
*/
|
|
154
|
+
let getCodeName = (code: errorCode): string => {
|
|
155
|
+
switch code {
|
|
156
|
+
| InvalidInput(_) => "InvalidInput"
|
|
157
|
+
| InvalidStartPosition(_) => "InvalidStartPosition"
|
|
158
|
+
| UncloseBox(_) => "UncloseBox"
|
|
159
|
+
| MismatchedWidth(_) => "MismatchedWidth"
|
|
160
|
+
| MisalignedPipe(_) => "MisalignedPipe"
|
|
161
|
+
| OverlappingBoxes(_) => "OverlappingBoxes"
|
|
162
|
+
| InvalidElement(_) => "InvalidElement"
|
|
163
|
+
| UnclosedBracket(_) => "UnclosedBracket"
|
|
164
|
+
| EmptyButton(_) => "EmptyButton"
|
|
165
|
+
| InvalidInteractionDSL(_) => "InvalidInteractionDSL"
|
|
166
|
+
| UnusualSpacing(_) => "UnusualSpacing"
|
|
167
|
+
| DeepNesting(_) => "DeepNesting"
|
|
168
|
+
}
|
|
169
|
+
}
|