@markdy/core 0.8.12 → 0.8.13

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 (2) hide show
  1. package/dist/index.js +65 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1571,8 +1571,45 @@ function readIndentedBody(blocks, startIdx, parentIndent) {
1571
1571
  }
1572
1572
  return { body, nextIdx: i };
1573
1573
  }
1574
- function readBody(blocks, startIdx, parentIndent, braceDelimited) {
1575
- if (!braceDelimited) return readIndentedBody(blocks, startIdx, parentIndent);
1574
+ var TOP_LEVEL_KEYWORDS_RE = /^(scene|layout|pattern|group|annotation|edge|beat|var|style)\b/;
1575
+ function isTopLevelStatement(line) {
1576
+ if (line === "}") return true;
1577
+ if (TOP_LEVEL_KEYWORDS_RE.test(line)) return true;
1578
+ const nodeMatch = line.match(/^(\w[\w.-]*)\s+(\w[\w.-]*)/);
1579
+ if (!nodeMatch) return false;
1580
+ const kind = canonicalNodeKind(nodeMatch[1].toLowerCase());
1581
+ return NODE_KINDS.has(kind);
1582
+ }
1583
+ function readColonBody(blocks, startIdx, parentIndent, diagnostics, context, headerLine) {
1584
+ const indented = readIndentedBody(blocks, startIdx, parentIndent);
1585
+ if (indented.body.length > 0 || startIdx >= blocks.length) {
1586
+ return indented;
1587
+ }
1588
+ if (isTopLevelStatement(blocks[startIdx].text)) {
1589
+ return indented;
1590
+ }
1591
+ const body = [];
1592
+ let i = startIdx;
1593
+ while (i < blocks.length) {
1594
+ const block = blocks[i];
1595
+ if (block.indent < parentIndent) break;
1596
+ if (block.indent === parentIndent && isTopLevelStatement(block.text)) break;
1597
+ body.push(block);
1598
+ i++;
1599
+ }
1600
+ if (body.length > 0) {
1601
+ diagnostics.push({
1602
+ severity: "warning",
1603
+ message: `${context} body had no indentation; parsed until the next top-level statement (hosts like MDX/JSX often strip indent from template literals)`,
1604
+ line: headerLine
1605
+ });
1606
+ }
1607
+ return { body, nextIdx: i };
1608
+ }
1609
+ function readBody(blocks, startIdx, parentIndent, braceDelimited, diagnostics = [], context = "block", headerLine = 1) {
1610
+ if (!braceDelimited) {
1611
+ return readColonBody(blocks, startIdx, parentIndent, diagnostics, context, headerLine);
1612
+ }
1576
1613
  const body = [];
1577
1614
  let i = startIdx;
1578
1615
  while (i < blocks.length) {
@@ -1847,7 +1884,15 @@ function parse(source, opts = {}) {
1847
1884
  const m = line.match(/^pattern\s+(\w+)\s*\(([^)]*)\)\s*(?::|\{)\s*$/);
1848
1885
  if (!m) throw new ParseError(`expected pattern name(params):`, lineNo);
1849
1886
  const params = m[2].trim() ? m[2].split(",").map((p) => p.trim()) : [];
1850
- const { body, nextIdx } = readBody(blocks, i + 1, block.indent, line.endsWith("{"));
1887
+ const { body, nextIdx } = readBody(
1888
+ blocks,
1889
+ i + 1,
1890
+ block.indent,
1891
+ line.endsWith("{"),
1892
+ diagnostics,
1893
+ `pattern '${m[1]}'`,
1894
+ lineNo
1895
+ );
1851
1896
  const cues = normalizeCueBlocks(body).map((b) => parseCueLine(b.text, b.line));
1852
1897
  patterns[m[1]] = { name: m[1], params, body: cues, line: lineNo };
1853
1898
  i = nextIdx;
@@ -1868,7 +1913,14 @@ function parse(source, opts = {}) {
1868
1913
  }
1869
1914
  const header = line.match(/^group\s+(\w+)(?:\s+"([^"]*)")?\s*:\s*$/);
1870
1915
  if (!header) throw new ParseError(`expected group name: A B C`, lineNo);
1871
- const { body, nextIdx } = readIndentedBody(blocks, i + 1, block.indent);
1916
+ const { body, nextIdx } = readColonBody(
1917
+ blocks,
1918
+ i + 1,
1919
+ block.indent,
1920
+ diagnostics,
1921
+ `group '${header[1]}'`,
1922
+ lineNo
1923
+ );
1872
1924
  const members = body.flatMap((b) => splitTargets(b.text));
1873
1925
  if (members.length === 0) throw new ParseError(`group '${header[1]}' has no members`, lineNo);
1874
1926
  groups[header[1]] = {
@@ -1919,7 +1971,15 @@ function parse(source, opts = {}) {
1919
1971
  if (line.startsWith("beat ")) {
1920
1972
  const m = line.match(/^beat\s+([\w.-]+)(?:\s+"([^"]*)")?\s*(?::|\{)\s*$/);
1921
1973
  if (!m) throw new ParseError(`expected beat name:`, lineNo);
1922
- const { body, nextIdx } = readBody(blocks, i + 1, block.indent, line.endsWith("{"));
1974
+ const { body, nextIdx } = readBody(
1975
+ blocks,
1976
+ i + 1,
1977
+ block.indent,
1978
+ line.endsWith("{"),
1979
+ diagnostics,
1980
+ `beat '${m[1]}'`,
1981
+ lineNo
1982
+ );
1923
1983
  let cues = normalizeCueBlocks(body).map((b) => parseCueLine(b.text, b.line));
1924
1984
  cues = expandPatternCues(cues, patterns, lineNo);
1925
1985
  beats.push({ name: m[1], label: m[2], cues, line: lineNo });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markdy/core",
3
- "version": "0.8.12",
3
+ "version": "0.8.13",
4
4
  "description": "Diagram-native MarkdyScript parser and compiler (auto-layout, edge routing, cue scheduling) — zero runtime dependencies.",
5
5
  "license": "MIT",
6
6
  "type": "module",