wyreframe 0.7.3 → 0.7.5
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/package.json
CHANGED
|
@@ -87,7 +87,24 @@ function findBottomRightCorner(grid, topLeft, topRight) {
|
|
|
87
87
|
switch (match) {
|
|
88
88
|
case "Corner" :
|
|
89
89
|
lastCorner = pos;
|
|
90
|
-
|
|
90
|
+
let nextRow = row + 1 | 0;
|
|
91
|
+
if (nextRow < grid.height) {
|
|
92
|
+
let nextPos = Types.Position.make(nextRow, topRight.col);
|
|
93
|
+
let match$1 = Grid.get(grid, nextPos);
|
|
94
|
+
if (match$1 === "Corner" && typeof match$1 !== "object") {
|
|
95
|
+
let nextLeftPos = Types.Position.make(nextRow, topLeft.col);
|
|
96
|
+
let match$2 = Grid.get(grid, nextLeftPos);
|
|
97
|
+
if (match$2 === "Corner" && typeof match$2 !== "object") {
|
|
98
|
+
$$continue = false;
|
|
99
|
+
} else {
|
|
100
|
+
row = row + 1 | 0;
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
row = row + 1 | 0;
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
row = row + 1 | 0;
|
|
107
|
+
}
|
|
91
108
|
break;
|
|
92
109
|
case "VLine" :
|
|
93
110
|
row = row + 1 | 0;
|
|
@@ -135,6 +152,57 @@ function traceBox(grid, topLeft) {
|
|
|
135
152
|
})
|
|
136
153
|
};
|
|
137
154
|
}
|
|
155
|
+
let nextRow = topLeft.row + 1 | 0;
|
|
156
|
+
let isValidTopEdge;
|
|
157
|
+
if (nextRow < grid.height) {
|
|
158
|
+
let nextLeftPos = Types.Position.make(nextRow, topLeft.col);
|
|
159
|
+
let nextRightPos = Types.Position.make(nextRow, topRightOpt.col);
|
|
160
|
+
let leftChar = Grid.get(grid, nextLeftPos);
|
|
161
|
+
let rightChar = Grid.get(grid, nextRightPos);
|
|
162
|
+
if (leftChar !== undefined && typeof leftChar !== "object") {
|
|
163
|
+
switch (leftChar) {
|
|
164
|
+
case "Corner" :
|
|
165
|
+
if (rightChar !== undefined && typeof rightChar !== "object") {
|
|
166
|
+
switch (rightChar) {
|
|
167
|
+
case "Corner" :
|
|
168
|
+
isValidTopEdge = false;
|
|
169
|
+
break;
|
|
170
|
+
default:
|
|
171
|
+
isValidTopEdge = true;
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
isValidTopEdge = true;
|
|
175
|
+
}
|
|
176
|
+
break;
|
|
177
|
+
case "VLine" :
|
|
178
|
+
if (rightChar !== undefined && typeof rightChar !== "object") {
|
|
179
|
+
switch (rightChar) {
|
|
180
|
+
default:
|
|
181
|
+
isValidTopEdge = true;
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
isValidTopEdge = true;
|
|
185
|
+
}
|
|
186
|
+
break;
|
|
187
|
+
default:
|
|
188
|
+
isValidTopEdge = true;
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
isValidTopEdge = true;
|
|
192
|
+
}
|
|
193
|
+
} else {
|
|
194
|
+
isValidTopEdge = false;
|
|
195
|
+
}
|
|
196
|
+
if (!isValidTopEdge) {
|
|
197
|
+
return {
|
|
198
|
+
TAG: "Error",
|
|
199
|
+
_0: ErrorTypes.makeSimple({
|
|
200
|
+
TAG: "InvalidElement",
|
|
201
|
+
content: "Not a valid box top-left corner (adjacent box detected)",
|
|
202
|
+
position: topLeft
|
|
203
|
+
})
|
|
204
|
+
};
|
|
205
|
+
}
|
|
138
206
|
let topEdgeChars = topEdgeScan.map(param => param[1]);
|
|
139
207
|
if (isDividerOnlyEdge(topEdgeChars)) {
|
|
140
208
|
return {
|
|
@@ -114,6 +114,7 @@ let rowHasVLineInRange = (grid: Grid.t, row: int, leftCol: int, rightCol: int):
|
|
|
114
114
|
* - Continues through rows with misaligned VLines (records for warnings)
|
|
115
115
|
* - Stops at rows with no VLine at all in the box's column range (box boundary)
|
|
116
116
|
* - Handles internal dividers (+=====+) correctly by finding the last corner
|
|
117
|
+
* - IMPORTANT: Stops when detecting vertically adjacent boxes (Issue #18)
|
|
117
118
|
*
|
|
118
119
|
* @param grid - The 2D character grid
|
|
119
120
|
* @param topLeft - Position of top-left corner (for determining left boundary)
|
|
@@ -132,7 +133,40 @@ let findBottomRightCorner = (grid: Grid.t, topLeft: Position.t, topRight: Positi
|
|
|
132
133
|
| Some(Corner) => {
|
|
133
134
|
// Found a corner at the expected column - remember it
|
|
134
135
|
lastCorner := Some(pos)
|
|
135
|
-
|
|
136
|
+
|
|
137
|
+
// Issue #18 fix: Check if the NEXT row also has a Corner at the same column.
|
|
138
|
+
// If so, we've found the bottom of THIS box and the top of ANOTHER box.
|
|
139
|
+
// We should stop scanning here to avoid merging adjacent boxes.
|
|
140
|
+
let nextRow = row.contents + 1
|
|
141
|
+
if nextRow < grid.height {
|
|
142
|
+
let nextPos = Position.make(nextRow, topRight.col)
|
|
143
|
+
switch Grid.get(grid, nextPos) {
|
|
144
|
+
| Some(Corner) => {
|
|
145
|
+
// Next row also has a corner - this indicates adjacent boxes
|
|
146
|
+
// Also check if the next row starts a new box by checking left column
|
|
147
|
+
let nextLeftPos = Position.make(nextRow, topLeft.col)
|
|
148
|
+
switch Grid.get(grid, nextLeftPos) {
|
|
149
|
+
| Some(Corner) => {
|
|
150
|
+
// Both corners present in next row = new box starting
|
|
151
|
+
// Stop scanning - current corner is our bottom-right
|
|
152
|
+
continue := false
|
|
153
|
+
}
|
|
154
|
+
| _ => {
|
|
155
|
+
// Only right corner in next row - might be internal structure
|
|
156
|
+
// Continue scanning
|
|
157
|
+
row := row.contents + 1
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
| _ => {
|
|
162
|
+
// Next row doesn't have a corner - continue normally
|
|
163
|
+
row := row.contents + 1
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
// No more rows - we're done
|
|
168
|
+
row := row.contents + 1
|
|
169
|
+
}
|
|
136
170
|
}
|
|
137
171
|
| Some(VLine) => {
|
|
138
172
|
// Found a VLine at the expected column - continue scanning
|
|
@@ -198,6 +232,41 @@ let traceBox = (grid: Grid.t, topLeft: Position.t): traceResult => {
|
|
|
198
232
|
),
|
|
199
233
|
)
|
|
200
234
|
| Some(topRight) => {
|
|
235
|
+
// Issue #18 fix: Validate this is a TRUE top edge, not a bottom edge
|
|
236
|
+
// of another box. A valid top edge should have VLine characters (|)
|
|
237
|
+
// in the next row at the left and right columns, NOT Corner characters (+).
|
|
238
|
+
// If the next row has corners at both positions, this is likely the
|
|
239
|
+
// bottom edge of one box immediately followed by the top edge of another.
|
|
240
|
+
let nextRow = topLeft.row + 1
|
|
241
|
+
let isValidTopEdge = if nextRow < grid.height {
|
|
242
|
+
let nextLeftPos = Position.make(nextRow, topLeft.col)
|
|
243
|
+
let nextRightPos = Position.make(nextRow, topRight.col)
|
|
244
|
+
let leftChar = Grid.get(grid, nextLeftPos)
|
|
245
|
+
let rightChar = Grid.get(grid, nextRightPos)
|
|
246
|
+
// Valid top edge: next row has VLine on both sides (content row)
|
|
247
|
+
// Invalid: next row has Corner on both sides (another box edge)
|
|
248
|
+
switch (leftChar, rightChar) {
|
|
249
|
+
| (Some(Corner), Some(Corner)) => false // This is a bottom edge, not a top
|
|
250
|
+
| (Some(VLine), Some(VLine)) => true // This is a valid top edge
|
|
251
|
+
| (Some(VLine), Some(Corner)) => true // Could be valid with internal structure
|
|
252
|
+
| (Some(Corner), Some(VLine)) => true // Could be valid with internal structure
|
|
253
|
+
| _ => true // Be permissive for other cases
|
|
254
|
+
}
|
|
255
|
+
} else {
|
|
256
|
+
false // No next row means this can't be a valid box top
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if !isValidTopEdge {
|
|
260
|
+
// This corner is likely a bottom edge of another box, not a valid top-left
|
|
261
|
+
Error(
|
|
262
|
+
ErrorTypes.makeSimple(
|
|
263
|
+
ErrorTypes.InvalidElement({
|
|
264
|
+
content: "Not a valid box top-left corner (adjacent box detected)",
|
|
265
|
+
position: topLeft,
|
|
266
|
+
}),
|
|
267
|
+
),
|
|
268
|
+
)
|
|
269
|
+
} else {
|
|
201
270
|
// Step 3: Extract box name from top edge
|
|
202
271
|
let topEdgeChars = Array.map(topEdgeScan, ((_, cell)) => cell)
|
|
203
272
|
|
|
@@ -427,6 +496,7 @@ let traceBox = (grid: Grid.t, topLeft: Position.t): traceResult => {
|
|
|
427
496
|
}
|
|
428
497
|
}
|
|
429
498
|
} // Close else block for isDividerOnlyEdge
|
|
499
|
+
} // Close else block for isValidTopEdge
|
|
430
500
|
}
|
|
431
501
|
}
|
|
432
502
|
| _ =>
|
|
@@ -642,6 +642,17 @@ function parseContentLine(line, lineIndex, contentStartRow, box, registry) {
|
|
|
642
642
|
if (trimmed === "") {
|
|
643
643
|
let row = contentStartRow + lineIndex | 0;
|
|
644
644
|
let baseCol = box.bounds.left + 1 | 0;
|
|
645
|
+
let rowWithinChildBox = box.children.some(child => {
|
|
646
|
+
let b = child.bounds;
|
|
647
|
+
if (row >= b.top) {
|
|
648
|
+
return row <= b.bottom;
|
|
649
|
+
} else {
|
|
650
|
+
return false;
|
|
651
|
+
}
|
|
652
|
+
});
|
|
653
|
+
if (rowWithinChildBox) {
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
645
656
|
let position = Types.Position.make(row, baseCol);
|
|
646
657
|
return {
|
|
647
658
|
TAG: "Spacer",
|
|
@@ -1083,11 +1083,25 @@ let parseContentLine = (
|
|
|
1083
1083
|
let trimmed = line->String.trim
|
|
1084
1084
|
|
|
1085
1085
|
// Issue #16: Preserve empty lines as Spacer elements for vertical spacing
|
|
1086
|
+
// Issue #19: But don't create Spacers for rows that are within child box bounds
|
|
1086
1087
|
if trimmed === "" {
|
|
1087
1088
|
let row = contentStartRow + lineIndex
|
|
1088
1089
|
let baseCol = box.bounds.left + 1
|
|
1089
|
-
|
|
1090
|
-
|
|
1090
|
+
|
|
1091
|
+
// Check if this row is within any child box's vertical bounds
|
|
1092
|
+
// If so, skip creating a Spacer (Issue #19: incorrect spacer count)
|
|
1093
|
+
let rowWithinChildBox = box.children->Array.some(child => {
|
|
1094
|
+
let b = child.bounds
|
|
1095
|
+
row >= b.top && row <= b.bottom
|
|
1096
|
+
})
|
|
1097
|
+
|
|
1098
|
+
if rowWithinChildBox {
|
|
1099
|
+
// Skip spacer for rows occupied by child boxes
|
|
1100
|
+
None
|
|
1101
|
+
} else {
|
|
1102
|
+
let position = Position.make(row, baseCol)
|
|
1103
|
+
Some(Spacer({position: position}))
|
|
1104
|
+
}
|
|
1091
1105
|
} else if isNoiseText(trimmed) {
|
|
1092
1106
|
// Filter out border/noise text - don't create any element
|
|
1093
1107
|
None
|