wyreframe 0.1.5 → 0.2.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.
@@ -70,6 +70,90 @@ let isDividerOnlyEdge = (edgeChars: array<cellChar>): bool => {
70
70
  !hasHLineOrChar
71
71
  }
72
72
 
73
+ /**
74
+ * Find the last Corner character below a given position in the same column.
75
+ * Simple version used for fallback width mismatch detection.
76
+ *
77
+ * @param grid - The 2D character grid
78
+ * @param startPos - Starting position (searches below this row)
79
+ * @returns Option of position where the last corner was found
80
+ */
81
+ let findLastCornerInColumn = (grid: Grid.t, startPos: Position.t): option<Position.t> => {
82
+ let lastCorner = ref(None)
83
+ for row in startPos.row + 1 to grid.height - 1 {
84
+ let pos = Position.make(row, startPos.col)
85
+ switch Grid.get(grid, pos) {
86
+ | Some(Corner) => lastCorner := Some(pos)
87
+ | _ => ()
88
+ }
89
+ }
90
+ lastCorner.contents
91
+ }
92
+
93
+ /**
94
+ * Check if a row has any VLine character between left and right columns (inclusive).
95
+ * Used to determine if a row is part of a box (even with misaligned borders).
96
+ */
97
+ let rowHasVLineInRange = (grid: Grid.t, row: int, leftCol: int, rightCol: int): bool => {
98
+ let found = ref(false)
99
+ let col = ref(leftCol)
100
+ while col.contents <= rightCol && !found.contents {
101
+ switch Grid.get(grid, Position.make(row, col.contents)) {
102
+ | Some(VLine) => found := true
103
+ | _ => ()
104
+ }
105
+ col := col.contents + 1
106
+ }
107
+ found.contents
108
+ }
109
+
110
+ /**
111
+ * Find the bottom-right corner of a box by scanning down from top-right.
112
+ *
113
+ * This is more tolerant than the strict scanDown approach:
114
+ * - Continues through rows with misaligned VLines (records for warnings)
115
+ * - Stops at rows with no VLine at all in the box's column range (box boundary)
116
+ * - Handles internal dividers (+=====+) correctly by finding the last corner
117
+ *
118
+ * @param grid - The 2D character grid
119
+ * @param topLeft - Position of top-left corner (for determining left boundary)
120
+ * @param topRight - Position of top-right corner (starting point for scan)
121
+ * @returns Option of position where the bottom-right corner was found
122
+ */
123
+ let findBottomRightCorner = (grid: Grid.t, topLeft: Position.t, topRight: Position.t): option<Position.t> => {
124
+ let lastCorner = ref(None)
125
+ let row = ref(topRight.row + 1)
126
+ let continue = ref(true)
127
+
128
+ while row.contents < grid.height && continue.contents {
129
+ let pos = Position.make(row.contents, topRight.col)
130
+
131
+ switch Grid.get(grid, pos) {
132
+ | Some(Corner) => {
133
+ // Found a corner at the expected column - remember it
134
+ lastCorner := Some(pos)
135
+ row := row.contents + 1
136
+ }
137
+ | Some(VLine) => {
138
+ // Found a VLine at the expected column - continue scanning
139
+ row := row.contents + 1
140
+ }
141
+ | _ => {
142
+ // No VLine/Corner at expected column - check if row is part of this box
143
+ if rowHasVLineInRange(grid, row.contents, topLeft.col, topRight.col) {
144
+ // Row has a VLine somewhere (misaligned) - continue scanning
145
+ row := row.contents + 1
146
+ } else {
147
+ // No VLine in this row's box range - we've reached the end of the box
148
+ continue := false
149
+ }
150
+ }
151
+ }
152
+ }
153
+
154
+ lastCorner.contents
155
+ }
156
+
73
157
  /**
74
158
  * Trace a box starting from the top-left corner position.
75
159
  *
@@ -134,38 +218,22 @@ let traceBox = (grid: Grid.t, topLeft: Position.t): traceResult => {
134
218
  // Calculate top width
135
219
  let topWidth = topRight.col - topLeft.col
136
220
 
137
- // Step 4: Scan down from top-right to find bottom-right corner
138
- let rightEdgeScan = Grid.scanDown(grid, topRight, isValidVerticalChar)
221
+ // Step 4: Find bottom-right corner by searching the column
222
+ // Use tolerant search that ignores interior rows with misaligned VLines
223
+ let bottomRightOpt = findBottomRightCorner(grid, topLeft, topRight)
139
224
 
140
- let bottomRightOpt = {
141
- let lastCorner = ref(None)
142
- Array.forEach(rightEdgeScan, ((pos, cell)) => {
143
- switch cell {
144
- | Corner if !Position.equals(pos, topRight) => lastCorner := Some(pos)
145
- | _ => ()
146
- }
147
- })
148
- lastCorner.contents
149
- }
225
+ // Store rightEdgeScan for later validation (after we know the box is valid)
226
+ let rightEdgeScan = Grid.scanDown(grid, topRight, isValidVerticalChar)
150
227
 
151
228
  switch bottomRightOpt {
152
229
  | None => {
153
- // Right edge scan failed - could be width mismatch
154
- // Try tracing from left side to detect width mismatch
155
- let leftEdgeScan = Grid.scanDown(grid, topLeft, isValidVerticalChar)
156
- let bottomLeftOpt = {
157
- let lastCorner = ref(None)
158
- Array.forEach(leftEdgeScan, ((pos, cell)) => {
159
- switch cell {
160
- | Corner if !Position.equals(pos, topLeft) => lastCorner := Some(pos)
161
- | _ => ()
162
- }
163
- })
164
- lastCorner.contents
165
- }
230
+ // No corner found in the right column at topRight.col
231
+ // Try to detect width mismatch by finding bottom-left via left edge
232
+ let bottomLeftViaLeft = findLastCornerInColumn(grid, topLeft)
166
233
 
167
- switch bottomLeftOpt {
234
+ switch bottomLeftViaLeft {
168
235
  | None =>
236
+ // No bottom-left corner found either - unclosed box
169
237
  Error(
170
238
  ErrorTypes.makeSimple(
171
239
  ErrorTypes.UncloseBox({
@@ -212,7 +280,7 @@ let traceBox = (grid: Grid.t, topLeft: Position.t): traceResult => {
212
280
  ),
213
281
  )
214
282
  } else {
215
- // Widths match but right edge still failed - unclosed box
283
+ // Widths match but right edge corners don't align - unclosed box
216
284
  Error(
217
285
  ErrorTypes.makeSimple(
218
286
  ErrorTypes.UncloseBox({
@@ -372,3 +440,80 @@ let traceBox = (grid: Grid.t, topLeft: Position.t): traceResult => {
372
440
  )
373
441
  }
374
442
  }
443
+
444
+ /**
445
+ * Validate interior row alignment for a successfully traced box.
446
+ *
447
+ * Checks each row between the top and bottom borders to ensure:
448
+ * - The closing '|' character is at the expected column (bounds.right)
449
+ * - Generates MisalignedClosingBorder warnings for any misaligned rows
450
+ *
451
+ * This validation runs AFTER successful box tracing to detect visual
452
+ * alignment issues that don't prevent parsing but should be warned about.
453
+ *
454
+ * @param grid - The 2D character grid
455
+ * @param bounds - The bounds of the traced box
456
+ * @returns Array of warnings for any misaligned closing borders
457
+ */
458
+ let validateInteriorAlignment = (grid: Grid.t, bounds: Bounds.t): array<ErrorTypes.t> => {
459
+ let warnings = []
460
+
461
+ // Check each interior row (excluding top and bottom border rows)
462
+ for row in bounds.top + 1 to bounds.bottom - 1 {
463
+ // Check if there's a VLine at the expected right border column
464
+ let expectedRightCol = bounds.right
465
+ let rightCell = Grid.get(grid, Position.make(row, expectedRightCol))
466
+
467
+ switch rightCell {
468
+ | Some(VLine) => () // Properly aligned, no warning needed
469
+ | Some(_) | None => {
470
+ // The expected column doesn't have a VLine
471
+ // Try to find where the actual closing '|' is on this row
472
+ // Search in both directions from the expected position
473
+ let actualCol = ref(None)
474
+
475
+ // First, search to the RIGHT of expectedRightCol (for pipes beyond the expected boundary)
476
+ // Search up to 50 chars beyond to catch misaligned pipes
477
+ let maxSearchRight = expectedRightCol + 50
478
+ let colRight = ref(expectedRightCol + 1)
479
+ while colRight.contents <= maxSearchRight && Option.isNone(actualCol.contents) {
480
+ switch Grid.get(grid, Position.make(row, colRight.contents)) {
481
+ | Some(VLine) => actualCol := Some(colRight.contents)
482
+ | _ => ()
483
+ }
484
+ colRight := colRight.contents + 1
485
+ }
486
+
487
+ // If not found to the right, search to the LEFT (for pipes before the expected boundary)
488
+ // But only if it's not the opening pipe (bounds.left)
489
+ if Option.isNone(actualCol.contents) {
490
+ let col = ref(expectedRightCol - 1)
491
+ while col.contents > bounds.left && Option.isNone(actualCol.contents) {
492
+ switch Grid.get(grid, Position.make(row, col.contents)) {
493
+ | Some(VLine) => actualCol := Some(col.contents)
494
+ | _ => ()
495
+ }
496
+ col := col.contents - 1
497
+ }
498
+ }
499
+
500
+ // If we found a VLine at a different position, generate a warning
501
+ switch actualCol.contents {
502
+ | Some(foundCol) if foundCol !== expectedRightCol => {
503
+ let warning = ErrorTypes.makeSimple(
504
+ ErrorTypes.MisalignedClosingBorder({
505
+ position: Position.make(row, foundCol),
506
+ expectedCol: expectedRightCol,
507
+ actualCol: foundCol,
508
+ }),
509
+ )
510
+ warnings->Array.push(warning)->ignore
511
+ }
512
+ | _ => () // No VLine found or it's at the correct position (already handled above)
513
+ }
514
+ }
515
+ }
516
+ }
517
+
518
+ warnings
519
+ }
@@ -47,10 +47,16 @@ function detect(grid) {
47
47
  let corners = grid.cornerIndex;
48
48
  let boxes = [];
49
49
  let traceFailures = [];
50
+ let warnings = [];
50
51
  corners.forEach(corner => {
51
52
  let box = BoxTracer.traceBox(grid, corner);
52
53
  if (box.TAG === "Ok") {
53
- boxes.push(box._0);
54
+ let box$1 = box._0;
55
+ boxes.push(box$1);
56
+ let alignmentWarnings = BoxTracer.validateInteriorAlignment(grid, box$1.bounds);
57
+ alignmentWarnings.forEach(w => {
58
+ warnings.push(w);
59
+ });
54
60
  return;
55
61
  }
56
62
  traceFailures.push(box._0);
@@ -59,7 +65,10 @@ function detect(grid) {
59
65
  if (corners.length === 0) {
60
66
  return {
61
67
  TAG: "Ok",
62
- _0: []
68
+ _0: [
69
+ [],
70
+ []
71
+ ]
63
72
  };
64
73
  } else if (traceFailures.length > 0) {
65
74
  return {
@@ -69,7 +78,10 @@ function detect(grid) {
69
78
  } else {
70
79
  return {
71
80
  TAG: "Ok",
72
- _0: []
81
+ _0: [
82
+ [],
83
+ []
84
+ ]
73
85
  };
74
86
  }
75
87
  }
@@ -78,7 +90,10 @@ function detect(grid) {
78
90
  if (rootBoxes.TAG === "Ok") {
79
91
  return {
80
92
  TAG: "Ok",
81
- _0: rootBoxes._0
93
+ _0: [
94
+ rootBoxes._0,
95
+ warnings
96
+ ]
82
97
  };
83
98
  }
84
99
  let parseError = hierarchyErrorToParseError(rootBoxes._0);
@@ -101,26 +116,29 @@ function flattenBoxes(boxes) {
101
116
 
102
117
  function getStats(result) {
103
118
  if (result.TAG === "Ok") {
104
- let boxes = result._0;
119
+ let match = result._0;
120
+ let boxes = match[0];
105
121
  let rootCount = boxes.length;
106
122
  let totalCount = countBoxes(boxes);
123
+ let warningCount = match[1].length;
107
124
  return `Shape Detection Success:
108
125
  Root boxes: ` + rootCount.toString() + `
109
- Total boxes (including nested): ` + totalCount.toString();
126
+ Total boxes (including nested): ` + totalCount.toString() + `
127
+ Warnings: ` + warningCount.toString();
110
128
  }
111
129
  let errors = result._0;
112
130
  let errorCount = errors.length;
113
- let warningCount = Core__Array.reduce(errors, 0, (acc, err) => {
131
+ let warningCount$1 = Core__Array.reduce(errors, 0, (acc, err) => {
114
132
  if (ErrorTypes.isWarning(err)) {
115
133
  return acc + 1 | 0;
116
134
  } else {
117
135
  return acc;
118
136
  }
119
137
  });
120
- let realErrorCount = errorCount - warningCount | 0;
138
+ let realErrorCount = errorCount - warningCount$1 | 0;
121
139
  return `Shape Detection Failed:
122
140
  Errors: ` + realErrorCount.toString() + `
123
- Warnings: ` + warningCount.toString();
141
+ Warnings: ` + warningCount$1.toString();
124
142
  }
125
143
 
126
144
  export {
@@ -19,10 +19,10 @@ open Types
19
19
  /**
20
20
  * Result type for shape detection.
21
21
  * Returns either:
22
- * - Ok(boxes): Array of root-level boxes with nested hierarchy
22
+ * - Ok((boxes, warnings)): Array of root-level boxes with nested hierarchy, plus any warnings
23
23
  * - Error(errors): Array of all errors encountered during detection
24
24
  */
25
- type detectResult = result<array<BoxTracer.box>, array<ErrorTypes.t>>
25
+ type detectResult = result<(array<BoxTracer.box>, array<ErrorTypes.t>), array<ErrorTypes.t>>
26
26
 
27
27
  // ============================================================================
28
28
  // Helper Functions
@@ -121,12 +121,17 @@ let detect = (grid: Grid.t): detectResult => {
121
121
  // Only corners that are actually top-left of a box will trace successfully.
122
122
  let boxes = []
123
123
  let traceFailures = [] // Keep track of failures
124
+ let warnings = [] // Collect alignment warnings
124
125
 
125
126
  corners->Array.forEach(corner => {
126
127
  switch BoxTracer.traceBox(grid, corner) {
127
128
  | Ok(box) => {
128
129
  // Successfully traced a box - add to collection
129
130
  boxes->Array.push(box)
131
+
132
+ // Validate interior alignment and collect warnings
133
+ let alignmentWarnings = BoxTracer.validateInteriorAlignment(grid, box.bounds)
134
+ alignmentWarnings->Array.forEach(w => warnings->Array.push(w)->ignore)
130
135
  }
131
136
  | Error(traceError) => {
132
137
  // This corner failed to trace as a top-left corner.
@@ -141,14 +146,14 @@ let detect = (grid: Grid.t): detectResult => {
141
146
  // No boxes traced successfully
142
147
  if Array.length(corners) === 0 {
143
148
  // No corners at all - truly empty wireframe
144
- Ok([])
149
+ Ok(([], []))
145
150
  } else if Array.length(traceFailures) > 0 {
146
151
  // Had corners but all traces failed - this indicates malformed boxes
147
152
  // Return all trace failures as errors
148
153
  Error(traceFailures)
149
154
  } else {
150
155
  // No corners and no failures - empty result
151
- Ok([])
156
+ Ok(([], []))
152
157
  }
153
158
  } else {
154
159
  // Step 4: Detect dividers for each successfully traced box
@@ -160,8 +165,8 @@ let detect = (grid: Grid.t): detectResult => {
160
165
  // Step 6: Build hierarchy using HierarchyBuilder
161
166
  switch HierarchyBuilder.buildHierarchy(uniqueBoxes) {
162
167
  | Ok(rootBoxes) => {
163
- // Hierarchy built successfully - return the boxes
164
- Ok(rootBoxes)
168
+ // Hierarchy built successfully - return the boxes with any warnings
169
+ Ok((rootBoxes, warnings))
165
170
  }
166
171
  | Error(hierarchyError) => {
167
172
  // Hierarchy building failed (e.g., overlapping boxes)
@@ -210,12 +215,14 @@ let rec flattenBoxes = (boxes: array<BoxTracer.box>): array<BoxTracer.box> => {
210
215
  */
211
216
  let getStats = (result: detectResult): string => {
212
217
  switch result {
213
- | Ok(boxes) => {
218
+ | Ok((boxes, warnings)) => {
214
219
  let rootCount = Array.length(boxes)
215
220
  let totalCount = countBoxes(boxes)
221
+ let warningCount = Array.length(warnings)
216
222
  `Shape Detection Success:
217
223
  Root boxes: ${Int.toString(rootCount)}
218
- Total boxes (including nested): ${Int.toString(totalCount)}`
224
+ Total boxes (including nested): ${Int.toString(totalCount)}
225
+ Warnings: ${Int.toString(warningCount)}`
219
226
  }
220
227
  | Error(errors) => {
221
228
  let errorCount = Array.length(errors)
@@ -218,6 +218,31 @@ Consider simplifying the structure:
218
218
 
219
219
  This is a warning - parsing will continue.`
220
220
  };
221
+ case "MisalignedClosingBorder" :
222
+ let actualCol$1 = code.actualCol;
223
+ let expectedCol$1 = code.expectedCol;
224
+ return {
225
+ title: "⚠️ Misaligned closing border",
226
+ message: `The closing '|' at ` + formatPosition(code.position) + ` is not aligned with the box border:
227
+ • Expected column: ` + (expectedCol$1 + 1 | 0).toString() + `
228
+ • Actual column: ` + (actualCol$1 + 1 | 0).toString() + `
229
+ • Off by: ` + Math.abs(expectedCol$1 - actualCol$1 | 0).toString() + ` ` + (
230
+ Math.abs(expectedCol$1 - actualCol$1 | 0) === 1 ? "space" : "spaces"
231
+ ) + `
232
+
233
+ The closing border character on this row is not aligned with the right edge of the box.`,
234
+ solution: `💡 Solution:
235
+ Align the closing '|' to column ` + (expectedCol$1 + 1 | 0).toString() + `:
236
+ • ` + (
237
+ expectedCol$1 > actualCol$1 ? "Add" : "Remove"
238
+ ) + ` ` + Math.abs(expectedCol$1 - actualCol$1 | 0).toString() + ` space` + (
239
+ Math.abs(expectedCol$1 - actualCol$1 | 0) === 1 ? "" : "s"
240
+ ) + ` before the closing '|'
241
+ • Use a monospace font editor to ensure proper alignment
242
+ • Check that all rows in this box have the closing '|' at the same column
243
+
244
+ This is a warning - parsing will continue with the detected box structure.`
245
+ };
221
246
  }
222
247
  }
223
248
 
@@ -198,6 +198,23 @@ Consider simplifying the structure:
198
198
  This is a warning - parsing will continue.`,
199
199
  }
200
200
 
201
+ | MisalignedClosingBorder({position, expectedCol, actualCol}) => {
202
+ title: "⚠️ Misaligned closing border",
203
+ message: `The closing '|' at ${formatPosition(position)} is not aligned with the box border:
204
+ • Expected column: ${Int.toString(expectedCol + 1)}
205
+ • Actual column: ${Int.toString(actualCol + 1)}
206
+ • Off by: ${Int.toString(Js.Math.abs_int(expectedCol - actualCol))} ${Js.Math.abs_int(expectedCol - actualCol) === 1 ? "space" : "spaces"}
207
+
208
+ The closing border character on this row is not aligned with the right edge of the box.`,
209
+ solution: `💡 Solution:
210
+ Align the closing '|' to column ${Int.toString(expectedCol + 1)}:
211
+ • ${expectedCol > actualCol ? "Add" : "Remove"} ${Int.toString(Js.Math.abs_int(expectedCol - actualCol))} space${Js.Math.abs_int(expectedCol - actualCol) === 1 ? "" : "s"} before the closing '|'
212
+ • Use a monospace font editor to ensure proper alignment
213
+ • Check that all rows in this box have the closing '|' at the same column
214
+
215
+ This is a warning - parsing will continue with the detected box structure.`,
216
+ }
217
+
201
218
  | InvalidInput({message}) => {
202
219
  title: "❌ Invalid input",
203
220
  message: `${message}
@@ -7,6 +7,7 @@ function getSeverity(code) {
7
7
  switch (code.TAG) {
8
8
  case "UnusualSpacing" :
9
9
  case "DeepNesting" :
10
+ case "MisalignedClosingBorder" :
10
11
  return "Warning";
11
12
  default:
12
13
  return "Error";
@@ -89,6 +90,8 @@ function getCodeName(code) {
89
90
  return "UnusualSpacing";
90
91
  case "DeepNesting" :
91
92
  return "DeepNesting";
93
+ case "MisalignedClosingBorder" :
94
+ return "MisalignedClosingBorder";
92
95
  }
93
96
  }
94
97
 
@@ -59,6 +59,11 @@ type errorCode =
59
59
  depth: int,
60
60
  position: Position.t,
61
61
  }) // Nesting depth exceeds recommended level
62
+ | MisalignedClosingBorder({
63
+ position: Position.t,
64
+ expectedCol: int,
65
+ actualCol: int,
66
+ }) // Closing border '|' is not aligned with the box edge (REQ-7)
62
67
 
63
68
  /**
64
69
  * Complete parse error with error code, severity, and context
@@ -75,7 +80,7 @@ type t = {
75
80
  */
76
81
  let getSeverity = (code: errorCode): severity => {
77
82
  switch code {
78
- | UnusualSpacing(_) | DeepNesting(_) => Warning
83
+ | UnusualSpacing(_) | DeepNesting(_) | MisalignedClosingBorder(_) => Warning
79
84
  | _ => Error
80
85
  }
81
86
  }
@@ -130,6 +135,7 @@ let getPosition = (code: errorCode): option<Position.t> => {
130
135
  | InvalidInteractionDSL({position}) => position
131
136
  | UnusualSpacing({position}) => Some(position)
132
137
  | DeepNesting({position}) => Some(position)
138
+ | MisalignedClosingBorder({position}) => Some(position)
133
139
  }
134
140
  }
135
141
 
@@ -165,5 +171,6 @@ let getCodeName = (code: errorCode): string => {
165
171
  | InvalidInteractionDSL(_) => "InvalidInteractionDSL"
166
172
  | UnusualSpacing(_) => "UnusualSpacing"
167
173
  | DeepNesting(_) => "DeepNesting"
174
+ | MisalignedClosingBorder(_) => "MisalignedClosingBorder"
168
175
  }
169
176
  }
@@ -11,10 +11,11 @@ import type {sceneInteractions as Types_sceneInteractions} from '../../src/parse
11
11
 
12
12
  import type {t as ErrorTypes_t} from '../../src/parser/Errors/ErrorTypes.gen';
13
13
 
14
- /** * Parse result type - either a successful AST or an array of parse errors.
14
+ /** * Parse result type - either a successful (AST, warnings) tuple or an array of parse errors.
15
+ * Warnings are non-fatal issues like misaligned borders that don't prevent parsing.
15
16
  * This Result type is compatible with TypeScript through GenType. */
16
17
  export type parseResult =
17
- { TAG: "Ok"; _0: Types_ast }
18
+ { TAG: "Ok"; _0: Types_ast; _1: ErrorTypes_t[] }
18
19
  | { TAG: "Error"; _0: ErrorTypes_t[] };
19
20
 
20
21
  /** * Interaction parse result type. */
@@ -76,7 +76,11 @@ function parseSingleScene(sceneContent, sceneMetadata, errors) {
76
76
  let shapesResult = ShapeDetector.detect(grid);
77
77
  let shapes;
78
78
  if (shapesResult.TAG === "Ok") {
79
- shapes = shapesResult._0;
79
+ let match = shapesResult._0;
80
+ match[1].forEach(w => {
81
+ errors.push(w);
82
+ });
83
+ shapes = match[0];
80
84
  } else {
81
85
  shapesResult._0.forEach(err => {
82
86
  errors.push(err);
@@ -111,15 +115,18 @@ function parseSingleScene(sceneContent, sceneMetadata, errors) {
111
115
  }
112
116
 
113
117
  function parseInternal(wireframe, interactions) {
114
- let allErrors = [];
118
+ let allIssues = [];
115
119
  let sceneBlocks = SemanticParser.splitSceneBlocks(wireframe);
116
120
  let trimmed = wireframe.trim();
117
121
  if (sceneBlocks.length === 0 && trimmed === "") {
118
122
  return {
119
123
  TAG: "Ok",
120
- _0: {
121
- scenes: []
122
- }
124
+ _0: [
125
+ {
126
+ scenes: []
127
+ },
128
+ []
129
+ ]
123
130
  };
124
131
  }
125
132
  let scenes = [];
@@ -127,7 +134,7 @@ function parseInternal(wireframe, interactions) {
127
134
  let lines = block.split("\n");
128
135
  let match = SemanticParser.parseSceneDirectives(lines);
129
136
  let sceneContent = match[1].join("\n");
130
- let scene = parseSingleScene(sceneContent, match[0], allErrors);
137
+ let scene = parseSingleScene(sceneContent, match[0], allIssues);
131
138
  if (scene !== undefined) {
132
139
  scenes.push(scene);
133
140
  return;
@@ -143,23 +150,28 @@ function parseInternal(wireframe, interactions) {
143
150
  finalAst = mergeInteractionsIntoAST(baseAst, interactionsResult._0);
144
151
  } else {
145
152
  interactionsResult._0.forEach(err => {
146
- allErrors.push(err);
153
+ allIssues.push(err);
147
154
  });
148
155
  finalAst = baseAst;
149
156
  }
150
157
  } else {
151
158
  finalAst = baseAst;
152
159
  }
160
+ let errors = allIssues.filter(ErrorTypes.isError);
161
+ let warnings = allIssues.filter(ErrorTypes.isWarning);
153
162
  let totalElements = Core__Array.reduce(finalAst.scenes, 0, (acc, scene) => acc + scene.elements.length | 0);
154
- if (allErrors.length > 0 && totalElements === 0) {
163
+ if (errors.length > 0 && totalElements === 0) {
155
164
  return {
156
165
  TAG: "Error",
157
- _0: allErrors
166
+ _0: allIssues
158
167
  };
159
168
  } else {
160
169
  return {
161
170
  TAG: "Ok",
162
- _0: finalAst
171
+ _0: [
172
+ finalAst,
173
+ warnings
174
+ ]
163
175
  };
164
176
  }
165
177
  }