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,167 @@
|
|
|
1
|
+
// TextParser_test.res
|
|
2
|
+
// Unit tests for the TextParser fallback module
|
|
3
|
+
|
|
4
|
+
open Vitest
|
|
5
|
+
|
|
6
|
+
// Create a test parser instance
|
|
7
|
+
let parser = TextParser.make()
|
|
8
|
+
|
|
9
|
+
// Helper to create a test position
|
|
10
|
+
let makePosition = (row: int, col: int): Types.Position.t => Types.Position.make(row, col)
|
|
11
|
+
|
|
12
|
+
// Helper to create test bounds
|
|
13
|
+
let makeBounds = (~top: int, ~left: int, ~bottom: int, ~right: int): Types.Bounds.t => {
|
|
14
|
+
top: top,
|
|
15
|
+
left: left,
|
|
16
|
+
bottom: bottom,
|
|
17
|
+
right: right,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe("TextParser", () => {
|
|
21
|
+
describe("priority", () => {
|
|
22
|
+
test("should have lowest priority (1)", t => {
|
|
23
|
+
t->expect(parser.priority)->Expect.toBe(1)
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
describe("canParse", () => {
|
|
28
|
+
test("should always return true for any content", t => {
|
|
29
|
+
t->expect(parser.canParse("hello world"))->Expect.toBe(true)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test("should return true for empty string", t => {
|
|
33
|
+
t->expect(parser.canParse(""))->Expect.toBe(true)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test("should return true for special characters", t => {
|
|
37
|
+
t->expect(parser.canParse("!@#$%^&*()"))->Expect.toBe(true)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test("should return true for numbers", t => {
|
|
41
|
+
t->expect(parser.canParse("12345"))->Expect.toBe(true)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test("should return true for content that looks like other elements", t => {
|
|
45
|
+
// Even if content matches other patterns, TextParser accepts it
|
|
46
|
+
// (though it would normally be caught by higher-priority parsers first)
|
|
47
|
+
t->expect(parser.canParse("[ Button ]"))->Expect.toBe(true)
|
|
48
|
+
t->expect(parser.canParse("#input"))->Expect.toBe(true)
|
|
49
|
+
t->expect(parser.canParse("\"Link\""))->Expect.toBe(true)
|
|
50
|
+
t->expect(parser.canParse("[x] Checkbox"))->Expect.toBe(true)
|
|
51
|
+
t->expect(parser.canParse("* Emphasis"))->Expect.toBe(true)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test("should return true for whitespace-only content", t => {
|
|
55
|
+
t->expect(parser.canParse(" "))->Expect.toBe(true)
|
|
56
|
+
t->expect(parser.canParse("\t"))->Expect.toBe(true)
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
describe("parse", () => {
|
|
61
|
+
let pos = makePosition(5, 10)
|
|
62
|
+
let bounds = makeBounds(~top=0, ~left=0, ~bottom=10, ~right=20)
|
|
63
|
+
|
|
64
|
+
test("should parse plain text content", t => {
|
|
65
|
+
let result = parser.parse("Hello World", pos, bounds)
|
|
66
|
+
|
|
67
|
+
switch result {
|
|
68
|
+
| Some(Types.Text({content, emphasis, position, align})) => {
|
|
69
|
+
t->expect(content)->Expect.toBe("Hello World")
|
|
70
|
+
t->expect(emphasis)->Expect.toBe(false)
|
|
71
|
+
t->expect(position)->Expect.toEqual(pos)
|
|
72
|
+
t->expect(align)->Expect.toBe(Types.Left)
|
|
73
|
+
}
|
|
74
|
+
| _ => t->expect(true)->Expect.toBe(false) // fail: Expected Text element
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test("should set emphasis to false by default", t => {
|
|
79
|
+
let result = parser.parse("Some text", pos, bounds)
|
|
80
|
+
|
|
81
|
+
switch result {
|
|
82
|
+
| Some(Types.Text({emphasis})) => t->expect(emphasis)->Expect.toBe(false)
|
|
83
|
+
| _ => t->expect(true)->Expect.toBe(false) // fail: Expected Text element
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
test("should preserve the exact content without modification", t => {
|
|
88
|
+
let testCases = [
|
|
89
|
+
"plain text",
|
|
90
|
+
" whitespace preserved ",
|
|
91
|
+
"UPPERCASE",
|
|
92
|
+
"123numbers",
|
|
93
|
+
"special!@#chars",
|
|
94
|
+
"",
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
testCases->Array.forEach(content => {
|
|
98
|
+
let result = parser.parse(content, pos, bounds)
|
|
99
|
+
|
|
100
|
+
switch result {
|
|
101
|
+
| Some(Types.Text({content: parsed})) =>
|
|
102
|
+
t->expect(parsed)->Expect.toBe(content)
|
|
103
|
+
| _ => t->expect(true)->Expect.toBe(false) // fail: Expected Text element
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
test("should capture unrecognized patterns", t => {
|
|
109
|
+
// These patterns don't match standard element syntax
|
|
110
|
+
let unrecognizedPatterns = [
|
|
111
|
+
"This is just text",
|
|
112
|
+
"No special syntax here",
|
|
113
|
+
"Random content 123",
|
|
114
|
+
"Unmatched [ bracket",
|
|
115
|
+
"Partial #",
|
|
116
|
+
"Quote without end\"",
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
unrecognizedPatterns->Array.forEach(content => {
|
|
120
|
+
let result = parser.parse(content, pos, bounds)
|
|
121
|
+
|
|
122
|
+
switch result {
|
|
123
|
+
| Some(Types.Text(_)) => () // Success - pattern matched
|
|
124
|
+
| _ => t->expect(true)->Expect.toBe(false) // fail: Should parse unrecognized pattern
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
test("should use provided position", t => {
|
|
130
|
+
let customPos = makePosition(42, 17)
|
|
131
|
+
let result = parser.parse("test", customPos, bounds)
|
|
132
|
+
|
|
133
|
+
switch result {
|
|
134
|
+
| Some(Types.Text({position})) => {
|
|
135
|
+
t->expect(position.row)->Expect.toBe(42)
|
|
136
|
+
t->expect(position.col)->Expect.toBe(17)
|
|
137
|
+
}
|
|
138
|
+
| _ => t->expect(true)->Expect.toBe(false) // fail: Expected Text element
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
test("should always use Left alignment for fallback text", t => {
|
|
143
|
+
// TextParser uses Left alignment by default for simplicity
|
|
144
|
+
// More sophisticated alignment is handled by specific parsers
|
|
145
|
+
let result = parser.parse("centered text", pos, bounds)
|
|
146
|
+
|
|
147
|
+
switch result {
|
|
148
|
+
| Some(Types.Text({align})) => t->expect(align)->Expect.toBe(Types.Left)
|
|
149
|
+
| _ => t->expect(true)->Expect.toBe(false) // fail: Expected Text element
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
describe("integration with ParserRegistry", () => {
|
|
155
|
+
test("should act as fallback when no other parser matches", t => {
|
|
156
|
+
// Simulate content that no specific parser would recognize
|
|
157
|
+
let unknownContent = "This is completely unstructured text"
|
|
158
|
+
let result = parser.parse(unknownContent, makePosition(0, 0), makeBounds(~top=0, ~left=0, ~bottom=10, ~right=50))
|
|
159
|
+
|
|
160
|
+
switch result {
|
|
161
|
+
| Some(Types.Text({content})) =>
|
|
162
|
+
t->expect(content)->Expect.toBe(unknownContent)
|
|
163
|
+
| _ => t->expect(true)->Expect.toBe(false) // fail: TextParser should catch unrecognized content
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
})
|
|
167
|
+
})
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Types from "../Core/Types.mjs";
|
|
4
|
+
import * as LinkParser from "./Elements/LinkParser.mjs";
|
|
5
|
+
import * as TextParser from "./Elements/TextParser.mjs";
|
|
6
|
+
import * as InputParser from "./Elements/InputParser.mjs";
|
|
7
|
+
import * as ButtonParser from "./Elements/ButtonParser.mjs";
|
|
8
|
+
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
9
|
+
import * as CheckboxParser from "./Elements/CheckboxParser.mjs";
|
|
10
|
+
import * as CodeTextParser from "./Elements/CodeTextParser.mjs";
|
|
11
|
+
import * as EmphasisParser from "./Elements/EmphasisParser.mjs";
|
|
12
|
+
|
|
13
|
+
function make() {
|
|
14
|
+
return {
|
|
15
|
+
parsers: []
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function register(registry, parser) {
|
|
20
|
+
registry.parsers.push(parser);
|
|
21
|
+
registry.parsers = registry.parsers.toSorted((a, b) => Primitive_int.compare(b.priority, a.priority));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function parse(registry, content, position, bounds) {
|
|
25
|
+
let result;
|
|
26
|
+
for (let i = 0, i_finish = registry.parsers.length; i < i_finish; ++i) {
|
|
27
|
+
let match = result;
|
|
28
|
+
if (match === undefined) {
|
|
29
|
+
let parser = registry.parsers[i];
|
|
30
|
+
if (parser.canParse(content)) {
|
|
31
|
+
let element = parser.parse(content, position, bounds);
|
|
32
|
+
if (element !== undefined) {
|
|
33
|
+
result = element;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
let element$1 = result;
|
|
39
|
+
if (element$1 !== undefined) {
|
|
40
|
+
return element$1;
|
|
41
|
+
} else {
|
|
42
|
+
return {
|
|
43
|
+
TAG: "Text",
|
|
44
|
+
content: content,
|
|
45
|
+
emphasis: false,
|
|
46
|
+
position: Types.Position.make(position.row, position.col),
|
|
47
|
+
align: "Left"
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function makeDefault() {
|
|
53
|
+
let registry = {
|
|
54
|
+
parsers: []
|
|
55
|
+
};
|
|
56
|
+
register(registry, ButtonParser.make());
|
|
57
|
+
register(registry, InputParser.make());
|
|
58
|
+
register(registry, CheckboxParser.make());
|
|
59
|
+
register(registry, LinkParser.make());
|
|
60
|
+
register(registry, CodeTextParser.make());
|
|
61
|
+
register(registry, EmphasisParser.make());
|
|
62
|
+
register(registry, TextParser.make());
|
|
63
|
+
return registry;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function count(registry) {
|
|
67
|
+
return registry.parsers.length;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function getParsers(registry) {
|
|
71
|
+
return registry.parsers;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export {
|
|
75
|
+
make,
|
|
76
|
+
register,
|
|
77
|
+
parse,
|
|
78
|
+
makeDefault,
|
|
79
|
+
count,
|
|
80
|
+
getParsers,
|
|
81
|
+
}
|
|
82
|
+
/* Types Not a pure module */
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// ParserRegistry.res
|
|
2
|
+
// Registry for element parsers with priority-based ordering
|
|
3
|
+
|
|
4
|
+
open Types
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The parser registry type.
|
|
8
|
+
* Contains a mutable array of element parsers sorted by priority (descending).
|
|
9
|
+
*/
|
|
10
|
+
type t = {
|
|
11
|
+
mutable parsers: array<ElementParser.elementParser>,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Create a new empty parser registry.
|
|
16
|
+
*
|
|
17
|
+
* @return A new registry instance with no registered parsers
|
|
18
|
+
*/
|
|
19
|
+
let make = (): t => {
|
|
20
|
+
{parsers: []}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Register an element parser in the registry.
|
|
25
|
+
* Parsers are automatically sorted by priority (highest first).
|
|
26
|
+
*
|
|
27
|
+
* @param registry - The registry to add the parser to
|
|
28
|
+
* @param parser - The element parser to register
|
|
29
|
+
*/
|
|
30
|
+
let register = (registry: t, parser: ElementParser.elementParser): unit => {
|
|
31
|
+
// Add parser to array
|
|
32
|
+
registry.parsers->Array.push(parser)->ignore
|
|
33
|
+
|
|
34
|
+
// Re-sort by priority (descending - highest priority first)
|
|
35
|
+
registry.parsers = registry.parsers->Array.toSorted((a, b) => {
|
|
36
|
+
Int.toFloat(compare(b.priority, a.priority))
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Parse content using registered parsers.
|
|
42
|
+
*
|
|
43
|
+
* Tries each parser in priority order until one succeeds.
|
|
44
|
+
* The first parser whose canParse() returns true AND whose parse() returns Some(element)
|
|
45
|
+
* will be used, and remaining parsers will be skipped.
|
|
46
|
+
*
|
|
47
|
+
* If no parser succeeds, returns a default Text element (fallback).
|
|
48
|
+
*
|
|
49
|
+
* @param registry - The registry containing registered parsers
|
|
50
|
+
* @param content - The text content to parse
|
|
51
|
+
* @param position - Grid position where content appears
|
|
52
|
+
* @param bounds - Bounding box of containing box
|
|
53
|
+
* @return A parsed element (never None because of fallback)
|
|
54
|
+
*/
|
|
55
|
+
let parse = (
|
|
56
|
+
registry: t,
|
|
57
|
+
content: string,
|
|
58
|
+
position: Position.t,
|
|
59
|
+
bounds: Bounds.t,
|
|
60
|
+
): Types.element => {
|
|
61
|
+
// Try each parser in priority order
|
|
62
|
+
let result = ref(None)
|
|
63
|
+
|
|
64
|
+
for i in 0 to Array.length(registry.parsers) - 1 {
|
|
65
|
+
switch result.contents {
|
|
66
|
+
| Some(_) => () // Already found a match, skip remaining
|
|
67
|
+
| None => {
|
|
68
|
+
let parser = registry.parsers->Array.getUnsafe(i)
|
|
69
|
+
|
|
70
|
+
// First check if parser can handle this content
|
|
71
|
+
if parser.canParse(content) {
|
|
72
|
+
// Try to parse
|
|
73
|
+
switch parser.parse(content, position, bounds) {
|
|
74
|
+
| Some(element) => result := Some(element)
|
|
75
|
+
| None => () // This parser couldn't parse it, try next
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Return result or fallback to plain text
|
|
83
|
+
switch result.contents {
|
|
84
|
+
| Some(element) => element
|
|
85
|
+
| None =>
|
|
86
|
+
// Fallback: create a plain text element if no parser matched
|
|
87
|
+
// This shouldn't happen if TextParser is registered, but provides safety
|
|
88
|
+
Types.Text({
|
|
89
|
+
content: content,
|
|
90
|
+
emphasis: false,
|
|
91
|
+
position: Types.Position.make(position.row, position.col),
|
|
92
|
+
align: Types.Left,
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Create a registry with all default parsers pre-registered.
|
|
99
|
+
*
|
|
100
|
+
* Registers parsers in this priority order:
|
|
101
|
+
* 1. ButtonParser (priority 100)
|
|
102
|
+
* 2. InputParser (priority 90)
|
|
103
|
+
* 3. CheckboxParser (priority 85)
|
|
104
|
+
* 4. LinkParser (priority 80)
|
|
105
|
+
* 5. CodeTextParser (priority 75) - backtick-wrapped text with position-based alignment
|
|
106
|
+
* 6. EmphasisParser (priority 70)
|
|
107
|
+
* 7. TextParser (priority 1) - fallback
|
|
108
|
+
*
|
|
109
|
+
* @return A registry with all standard parsers registered
|
|
110
|
+
*/
|
|
111
|
+
let makeDefault = (): t => {
|
|
112
|
+
let registry = make()
|
|
113
|
+
|
|
114
|
+
// Register all standard parsers
|
|
115
|
+
// They'll be automatically sorted by priority
|
|
116
|
+
registry->register(ButtonParser.make())
|
|
117
|
+
registry->register(InputParser.make())
|
|
118
|
+
registry->register(CheckboxParser.make())
|
|
119
|
+
registry->register(LinkParser.make())
|
|
120
|
+
registry->register(CodeTextParser.make())
|
|
121
|
+
registry->register(EmphasisParser.make())
|
|
122
|
+
registry->register(TextParser.make()) // Fallback with priority 1
|
|
123
|
+
|
|
124
|
+
registry
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Get the number of registered parsers.
|
|
129
|
+
*
|
|
130
|
+
* @param registry - The registry to query
|
|
131
|
+
* @return The number of parsers registered
|
|
132
|
+
*/
|
|
133
|
+
let count = (registry: t): int => {
|
|
134
|
+
Array.length(registry.parsers)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Get all registered parsers (sorted by priority).
|
|
139
|
+
*
|
|
140
|
+
* @param registry - The registry to query
|
|
141
|
+
* @return Array of registered parsers in priority order
|
|
142
|
+
*/
|
|
143
|
+
let getParsers = (registry: t): array<ElementParser.elementParser> => {
|
|
144
|
+
registry.parsers
|
|
145
|
+
}
|