@flatkit/compiler 0.11.0 → 0.12.1

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/dist/analysis.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  scopeProgram,
15
15
  scopeRegions,
16
16
  splitScopeProgram
17
- } from "./chunk-UADRVB63.js";
17
+ } from "./chunk-VXETK5WQ.js";
18
18
  export {
19
19
  allScopeVariables,
20
20
  docHasErrors,
@@ -33,6 +33,7 @@ function localVariables(units) {
33
33
  return vars;
34
34
  }
35
35
  var TEXT_CALL = /\btext\s*\(/;
36
+ var SECOND_ASSIGN = /[\w\]]\s*=(?![=])/;
36
37
  function lint(src, ctx = {}) {
37
38
  const { units, diagnostics, sites } = parseUnits(src);
38
39
  const out = [...diagnostics];
@@ -56,7 +57,8 @@ function lint(src, ctx = {}) {
56
57
  }
57
58
  const a = analyzeExpr(s.text);
58
59
  if (!a.ok) {
59
- out.push({ line: s.line, col: s.col, message: `invalid expression: ${a.error}` });
60
+ const message = SECOND_ASSIGN.test(s.text) ? "two statements on one line \u2014 put each on its own line (FlatInk ends a statement at the newline)" : `invalid expression: ${a.error}`;
61
+ out.push({ line: s.line, col: s.col, message });
60
62
  continue;
61
63
  }
62
64
  for (const fn of a.refs.calls) if (!knownFns.has(fn)) out.push({ line: s.line, col: s.col, message: `unknown function "${fn}"` });
@@ -323,4 +325,4 @@ export {
323
325
  lintDocReport,
324
326
  docHasErrors
325
327
  };
326
- //# sourceMappingURL=chunk-UADRVB63.js.map
328
+ //# sourceMappingURL=chunk-VXETK5WQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lint.ts","../src/scopeProgram.ts","../src/programDoc.ts"],"sourcesContent":["// ─────────────────────────────────────────────────────────────────────────────\n// lint.ts — linter for the FlatInk Script language (batch L3).\n//\n// Builds on the parser (dsl.ts) for syntax errors + positions, then adds\n// SEMANTIC validation, ~free and PURE:\n// • each expression is compiled (compileExpr) → expression syntax error;\n// • referenced functions / member objects / identifiers are checked against\n// the standard environment (expr.ts) + the known variables → \"unknown\";\n// • `go to \"label\"` is checked against the set of known labels.\n//\n// Tolerant and kid-friendly: a variable is \"known\" if it is declared\n// (`let`) OR simply assigned (`x = …`) somewhere in the source, or provided\n// by the caller (document global variables). Labels are only checked\n// if the caller provides their list (otherwise we don't know the universe).\n// ─────────────────────────────────────────────────────────────────────────────\nimport { analyzeExpr, STD_CONSTANTS, STD_FUNCTIONS, STD_IDS, STD_OBJECTS } from '@flatkit/engine/expr'\nimport { packageFunctionNames } from '@flatkit/engine/stdlib'\nimport { parseUnits, type Diagnostic, type ScriptUnit } from '@flatkit/engine/dsl'\nimport type { Action } from '@flatkit/engine/actions'\n\nexport type LintContext = {\n /** Known variables in addition to those declared/assigned in the source. */\n variables?: Iterable<string>\n /** Known labels (timeline). Absent = we don't check `go to \"…\"`. */\n labels?: Iterable<string>\n /** Known functions in addition to those defined in the source. */\n functions?: Iterable<string>\n /** Scene objects referenceable by name (`Hero.x`) — in addition to mouse/keys. */\n objects?: Iterable<string>\n}\n\n/** Collects the names of ASSIGNED variables (setVar) + loop vars, inside action bodies. */\nfunction collectAssigned(actions: Action[], into: Set<string>): void {\n for (const a of actions) {\n if (a.do === 'setVar') into.add(a.name)\n else if (a.do === 'if') {\n collectAssigned(a.then, into)\n if (a.else) collectAssigned(a.else, into)\n } else if (a.do === 'repeat') collectAssigned(a.body, into)\n else if (a.do === 'repeatRange') { into.add(a.var); collectAssigned(a.body, into) } // i is known in the body\n }\n}\n\n/** Locally known variables: `let` declarations + every assigned variable. */\nexport function localVariables(units: ScriptUnit[]): Set<string> {\n const vars = new Set<string>()\n for (const u of units) {\n if (u.kind === 'declare') vars.add(u.name)\n else if (u.kind === 'event' || u.kind === 'frameActions') collectAssigned(u.body, vars)\n else if (u.kind === 'each') vars.add(u.as) // the index is known in the each bindings\n else if (u.kind === 'interactor') { if (u.varX) vars.add(u.varX); if (u.varY) vars.add(u.varY) } // drag writes these variables\n else if (u.kind === 'drop') collectAssigned(u.body, vars)\n else if (u.kind === 'func') { for (const p of u.func.params) vars.add(p); if (u.func.kind === 'proc') collectAssigned(u.func.body, vars) } // params + assignments\n }\n return vars\n}\n\n/** Detects a `text(` call (whole word) in an expression → only allowed in a `send` payload. */\nconst TEXT_CALL = /\\btext\\s*\\(/\n\n/** A bare assignment (`x =`, `a[i] =`; NOT ==/<=/>=/!=) left inside an expression: the tell-tale of a\n * SECOND statement crammed onto one line (FlatInk ends a statement at the newline, so it got swallowed). */\nconst SECOND_ASSIGN = /[\\w\\]]\\s*=(?![=])/\n\n/** Analyze a DSL source and return all diagnostics (syntax + semantic). */\nexport function lint(src: string, ctx: LintContext = {}): Diagnostic[] {\n const { units, diagnostics, sites } = parseUnits(src)\n const out: Diagnostic[] = [...diagnostics]\n\n const variables = localVariables(units)\n for (const v of ctx.variables ?? []) variables.add(v)\n const knownIds = new Set<string>([...STD_IDS, ...STD_CONSTANTS, ...variables])\n const knownFns = new Set(STD_FUNCTIONS)\n for (const u of units) {\n if (u.kind === 'func') knownFns.add(u.func.name) // user-defined functions\n else if (u.kind === 'use') for (const name of packageFunctionNames(u.name)) knownFns.add(name) // package functions (bare + qualified)\n }\n for (const f of ctx.functions ?? []) knownFns.add(f)\n const knownObjs = new Set(STD_OBJECTS)\n for (const o of ctx.objects ?? []) knownObjs.add(o) // scene objects (Hero.x…)\n const labels = ctx.labels ? new Set(ctx.labels) : null\n\n for (const s of sites) {\n if (s.kind === 'expr') {\n // `text(…)` is valid ONLY as a `send` payload (consumed by the parser, never\n // exposed as an expression site). Seeing it here = out-of-context use → dedicated error.\n if (TEXT_CALL.test(s.text)) {\n out.push({ line: s.line, col: s.col, message: 'text(\"…\") is only allowed as an argument to \"send\"' })\n continue\n }\n const a = analyzeExpr(s.text)\n if (!a.ok) {\n // #1 footgun: two statements on one line. The 2nd `channel = …` got swallowed into this\n // expression → a cryptic \"unexpected character =\". Detect the leftover assignment and say so.\n const message = SECOND_ASSIGN.test(s.text)\n ? 'two statements on one line — put each on its own line (FlatInk ends a statement at the newline)'\n : `invalid expression: ${a.error}`\n out.push({ line: s.line, col: s.col, message })\n continue\n }\n for (const fn of a.refs.calls) if (!knownFns.has(fn)) out.push({ line: s.line, col: s.col, message: `unknown function \"${fn}\"` })\n for (const o of a.refs.members)\n if (!knownObjs.has(o)) out.push({ line: s.line, col: s.col, message: `unknown object \"${o}\" (expected: ${[...knownObjs].join(', ')})` })\n for (const id of a.refs.ids)\n if (!knownIds.has(id))\n out.push({ line: s.line, col: s.col, message: `unknown variable \"${id}\"${variables.size ? '' : ' — declare it with \"let\"'}` })\n } else if (labels && !labels.has(s.name)) {\n out.push({ line: s.line, col: s.col, message: `unknown label \"${s.name}\"` })\n }\n }\n\n return out.sort((a, b) => a.line - b.line || a.col - b.col)\n}\n\n/**\n * Lint report ready to feed back to a generator (LLM/CLI): `''` = no issue (the code passes),\n * otherwise one `line:col: message` line per diagnostic. Primitive of the \"generate → lint →\n * fix\" loop: the language fits in few tokens, robustness comes from this feedback, not from context.\n */\nexport function lintReport(src: string, ctx: LintContext = {}): string {\n return lint(src, ctx).map((d) => `${d.line}:${d.col}: ${d.message}`).join('\\n')\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// scopeProgram.ts — the \"unified file\" of a scope (the Scene, or a Symbol).\n//\n// Vision: one file = one scope. All the code of a scope fits in ONE text:\n// var … (global variables, root only)\n// when loaded {} (lifecycle of the scope's timeline)\n// every frame {}\n// object \"name\" {} (one block per scripted object of the scope)\n//\n// This is the `.flatink` structure WITHOUT the geometry (which stays visual). This module\n// ONLY deals with the text: splitting the `object` blocks from the rest, and formatting a block.\n// The wiring to the Doc (a single commit) lives in the store, which reuses these functions\n// + scriptDoc/dsl. Pure, no DOM, testable.\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** End of the block opened at `open` (index of the matching `}`), ignoring strings and comments. -1 if unclosed. */\nfunction matchBrace(s: string, open: number): number {\n let depth = 0\n for (let i = open; i < s.length; i++) {\n const c = s[i]\n if (c === '\"') { i++; while (i < s.length && s[i] !== '\"') { if (s[i] === '\\\\') i++; i++ }; continue }\n if (c === '/' && s[i + 1] === '/') { while (i < s.length && s[i] !== '\\n') i++; continue }\n if (c === '{') depth++\n else if (c === '}') { depth--; if (depth === 0) return i }\n }\n return -1\n}\n\n/** Splits a scope file: the `object \"name\" { … }` blocks on one side, the REST (var + lifecycle) on the other. */\nexport function splitScopeProgram(text: string): { rest: string; objects: { name: string; body: string }[] } {\n let rest = ''\n let i = 0\n const objects: { name: string; body: string }[] = []\n while (i < text.length) {\n const m = /object\\s+\"((?:[^\"\\\\]|\\\\.)*)\"\\s*\\{/.exec(text.slice(i))\n if (!m) { rest += text.slice(i); break }\n const start = i + m.index\n rest += text.slice(i, start)\n const ob = start + m[0].length - 1 // the opening brace\n const oc = matchBrace(text, ob)\n if (oc < 0) { rest += text.slice(start); break } // unclosed block → left to the rest (diagnostic downstream)\n objects.push({ name: m[1].replace(/\\\\(.)/g, (_, c) => (c === 'n' ? '\\n' : c)), body: text.slice(ob + 1, oc) })\n i = oc + 1\n }\n return { rest, objects }\n}\n\n/** LINTABLE regions of a scope file (the \"rest\" gaps + the `object` bodies), with their\n * 1-based start line in the original text — to lint each piece as pure DSL and\n * reproject the positions. The `object` keyword and its braces are NOT DSL: we skip them. */\nexport function scopeRegions(text: string): { body: string; line: number }[] {\n const lineAt = (off: number) => text.slice(0, off).split('\\n').length\n const regions: { body: string; line: number }[] = []\n let i = 0\n let restStart = 0\n while (i < text.length) {\n const m = /object\\s+\"((?:[^\"\\\\]|\\\\.)*)\"\\s*\\{/.exec(text.slice(i))\n if (!m) break\n const start = i + m.index\n const gap = text.slice(restStart, start)\n if (gap.trim()) regions.push({ body: gap, line: lineAt(restStart) })\n const ob = start + m[0].length - 1\n const oc = matchBrace(text, ob)\n if (oc < 0) break\n regions.push({ body: text.slice(ob + 1, oc), line: lineAt(ob + 1) })\n i = oc + 1\n restStart = i\n }\n const tail = text.slice(restStart)\n if (tail.trim()) regions.push({ body: tail, line: lineAt(restStart) })\n return regions\n}\n\nconst esc = (s: string) => s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"').replace(/\\n/g, '\\\\n')\nconst indent = (body: string) => body.split('\\n').map((l) => (l.trim() ? ' ' + l : l)).join('\\n')\n\n/** Formats an `object \"name\" { … }` block (body already in DSL). */\nexport function formatObjectBlock(name: string, body: string): string {\n const inner = body.trim()\n return `object \"${esc(name)}\" {\\n${inner ? indent(inner) + '\\n' : ''}}`\n}\n\n/** Assembles a scope file: rest (var + lifecycle) then the object blocks, separated by a blank line. */\nexport function joinScopeProgram(rest: string, objects: { name: string; body: string }[]): string {\n const parts: string[] = []\n if (rest.trim()) parts.push(rest.trim())\n for (const o of objects) if (o.body.trim()) parts.push(formatObjectBlock(o.name, o.body))\n return parts.length ? parts.join('\\n\\n') + '\\n' : ''\n}\n","// -----------------------------------------------------------------------------\n// programDoc.ts — PURE bridge Doc <-> \"scope program\" (text) + lint of a whole Doc.\n//\n// Both the editor AND the CLI need to rebuild the DSL text of a scope (to display it,\n// or to lint it) and to assemble the lint context (variables/labels/functions/objects)\n// FROM a Doc — without depending on the React store. Everything lives here, pure and testable:\n// • `scopeProgram` : Doc fragments -> program text of a scope (round-trip via printUnits);\n// • `docLintContext` : Doc + scope -> LintContext (known names);\n// • `lintDoc` / report : semantic lint of ALL the scopes of a Doc (scene + symbols).\n// -> the CLI gains a `flatc --check`, the editor stops duplicating the logic.\n// -----------------------------------------------------------------------------\nimport type { Doc, EditFrame, Group, Instance } from '@flatkit/types'\nimport { printUnits, type Diagnostic } from '@flatkit/engine/dsl'\nimport { joinScopeProgram, scopeRegions } from './scopeProgram'\nimport { functionsToUnits, importsToUnits, objectToUnits, timelineToUnits, variablesToUnits } from '@flatkit/engine/scriptDoc'\nimport { contextLayers, getScopeTimeline, isContainer, isGroup, isText, isImage } from '@flatkit/engine/layers'\nimport { importedFunctions } from '@flatkit/engine/stdlib'\nimport { objectNames } from '@flatkit/engine/sceneRefs'\nimport { itemBBox, dropZoneBounds } from '@flatkit/engine/groups'\nimport { bboxIntersects } from '@flatkit/engine/bbox'\nimport { lint, localVariables, type LintContext } from './lint'\nimport { parseUnits } from '@flatkit/engine/dsl'\nimport type { Item, Layer, Text } from '@flatkit/types'\n\n/** Rebuilds the \"program\" text of a scope (imports + variables + functions + scene cycle\n * + one `object \"Name\" { … }` block per scripted container with a unique name). Pure, round-trip via printUnits. */\nexport function scopeProgram(doc: Doc, editPath: EditFrame[] = []): string {\n const atRoot = editPath.length === 0\n const items = contextLayers(doc, editPath).flatMap((l) => l.items)\n const nameCount = new Map<string, number>()\n for (const it of items) if (isContainer(it) && it.name) nameCount.set(it.name, (nameCount.get(it.name) ?? 0) + 1)\n const scripted = (it: Group | Instance) => !!doc.interactions?.some((i) => i.targetId === it.id) || !!doc.interactors?.some((i) => i.targetId === it.id) || !!(it.expressions && Object.keys(it.expressions).length)\n const objects = items\n .filter((it): it is Group | Instance => isContainer(it) && !!it.name && nameCount.get(it.name) === 1 && scripted(it))\n .map((it) => ({ name: it.name, body: printUnits(objectToUnits(it.id, doc.interactions, it.expressions, doc.interactors)) }))\n const imports = atRoot ? printUnits(importsToUnits(doc.imports)) : ''\n const funcs = atRoot ? printUnits(functionsToUnits(doc.functions)) : ''\n const globals = atRoot ? printUnits(variablesToUnits(doc.variables)) : ''\n const scene = printUnits(timelineToUnits(getScopeTimeline(doc, editPath)))\n const head = [imports, globals, funcs, scene].filter((t) => t.trim()).join('\\n\\n')\n return joinScopeProgram(head, objects)\n}\n\n/** Lint context of a scope: known names (variables, labels, functions, objects) drawn from the Doc.\n * `extraVars` = variables assigned in the OTHER scopes (FlatInk variables are GLOBAL -> known\n * everywhere; avoids a false \"unknown variable\" on a var written elsewhere, e.g. generated by `match`). */\nexport function docLintContext(doc: Doc, editPath: EditFrame[] = [], extraVars?: Iterable<string>): LintContext {\n return {\n variables: [...Object.keys(doc.variables ?? {}), ...(extraVars ?? [])],\n labels: (getScopeTimeline(doc, editPath)?.labels ?? []).map((l) => l.name),\n functions: [...(doc.functions ?? []).map((f) => f.name), ...importedFunctions(doc.imports).map((f) => f.name)],\n objects: objectNames(contextLayers(doc, editPath)),\n }\n}\n\n/** All the scopes of a Doc: the scene (root) + each symbol of the library. */\nfunction scopes(doc: Doc): { label: string; editPath: EditFrame[] }[] {\n return [{ label: 'scene', editPath: [] }, ...doc.symbols.map((s) => ({ label: s.name, editPath: [{ kind: 'symbol' as const, symbolId: s.id, name: s.name }] }))]\n}\n\n/** Union of the variables ASSIGNED in ALL the scopes (scene + symbols). FlatInk variables are\n * global -> a var written in one scope is legitimate in the others (cross-scope reads). */\nexport function allScopeVariables(doc: Doc): string[] {\n const set = new Set<string>()\n for (const { editPath } of scopes(doc))\n for (const r of scopeRegions(scopeProgram(doc, editPath)))\n for (const v of localVariables(parseUnits(r.body).units)) set.add(v)\n return [...set]\n}\n\n/** Readable name of an item by id (for the messages). */\nfunction itemNameById(doc: Doc, id: string): string | null {\n let found: string | null = null\n const walk = (layers: { items: import('@flatkit/types').Item[] }[]) => {\n for (const l of layers) for (const it of l.items) {\n if (found) return\n if ('name' in it && it.id === id) { found = it.name; return }\n if (isGroup(it)) walk(it.layers)\n }\n }\n walk(doc.layers)\n return found\n}\n\nconst escapeRe = (s: string) => s.replace(/[.*+?^${}()|[\\]\\\\-]/g, '\\\\$&')\n\n/** STRUCTURAL warnings (non-blocking) of a Doc: phantom drop zones, dead variables. */\nexport function docStructureWarnings(doc: Doc): { scope: string; diag: Diagnostic }[] {\n const out: { scope: string; diag: Diagnostic }[] = []\n // (a) `when dropped on X` whose zone X does not exist (no item named so) -> the handler can never fire.\n const names = new Set(objectNames(doc.layers))\n for (const it of doc.interactions ?? []) {\n if (it.event === 'drop' && it.over && !names.has(it.over)) {\n const who = itemNameById(doc, it.targetId) ?? it.targetId\n out.push({ scope: 'scene', diag: { line: 1, col: 1, severity: 'warning', message: `unknown drop zone \"${it.over}\" (object \"${who}\") — no item of the scene carries this name` } })\n }\n }\n // (b) global variable never referenced (declared but not found in any scope) -> probably dead.\n const names0 = Object.keys(doc.variables ?? {})\n if (names0.length) {\n const allText = scopes(doc).map(({ editPath }) => scopeProgram(doc, editPath)).join('\\n')\n for (const name of names0) {\n const m = allText.match(new RegExp(`(?<![\\\\w-])${escapeRe(name)}(?![\\\\w-])`, 'g'))\n if ((m?.length ?? 0) <= 1) out.push({ scope: 'scene', diag: { line: 1, col: 1, severity: 'warning', message: `global variable \"${name}\" never used (declared, but neither read nor written)` } })\n }\n }\n out.push(...docLayoutWarnings(doc))\n return out\n}\n\nconst warn = (message: string): { scope: string; diag: Diagnostic } => ({ scope: 'scene', diag: { line: 1, col: 1, severity: 'warning', message } })\nconst itemLabel = (it: Item): string => ('name' in it && it.name ? it.name : 'kind' in it ? it.kind : 'path')\n/** Estimated width of the longest line (approximate metric, without canvas). */\nfunction estTextWidth(t: Text): number {\n const advance = (t.weight && t.weight >= 700 ? 0.56 : 0.52) * t.size // mean advance of a proportional glyph\n let longest = 0\n for (const line of t.content.split('\\n')) longest = Math.max(longest, line.length)\n return longest * advance\n}\n\n/** LAYOUT warnings (non-blocking): canvas overflow, text too wide, overlapping hitboxes.\n * Approximate but without canvas — catches \"blind\" positioning bugs before the render. */\nexport function docLayoutWarnings(doc: Doc): { scope: string; diag: Diagnostic }[] {\n const out: { scope: string; diag: Diagnostic }[] = []\n const W = doc.width, H = doc.height\n const TOL = 8 // overflow tolerance (px) before alerting\n const r0 = (n: number) => Math.round(n)\n\n // (c) TEXT/IMAGE clipped at the canvas edge. Precise to avoid noise: we ignore `path`/groups\n // (decor that \"bleeds\" on purpose), objects driven by an expression (dynamic position ->\n // misleading static bbox), and items PARKED entirely off-screen (\"hidden\" pattern).\n const dynamicPos = (it: Item) => 'expressions' in it && it.expressions && (it.expressions.x != null || it.expressions.y != null)\n for (const layer of doc.layers) {\n for (const it of layer.items) {\n if (!(isText(it) || isImage(it)) || dynamicPos(it)) continue\n const b = itemBBox(doc, it)\n if (!b) continue\n const visible = b.maxX > 0 && b.minX < W && b.maxY > 0 && b.minY < H // overlaps the canvas (not parked off-screen)\n const clipped = b.minX < -TOL || b.minY < -TOL || b.maxX > W + TOL || b.maxY > H + TOL\n if (visible && clipped) {\n out.push(warn(`\"${itemLabel(it)}\" clipped at the canvas edge: bbox [${r0(b.minX)},${r0(b.minY)} -> ${r0(b.maxX)},${r0(b.maxY)}] outside 0,0 -> ${W},${H}`))\n }\n }\n }\n\n // (d) Text (without `wrap`) whose estimated width makes it OVERFLOW THE CANVAS -> instruction clipped.\n // (We do NOT compare against `box.w`: without wrap, a text overflows its box harmlessly as long as it\n // fits in the canvas — it is the canvas edge that clips.) Top-level only (x = world).\n for (const it of doc.layers.flatMap((l) => l.items)) {\n if (!isText(it) || it.wrap || dynamicPos(it)) continue\n const estW = estTextWidth(it)\n const left = it.align === 'left' ? 0 : it.align === 'right' ? it.box.w - estW : it.box.w / 2 - estW / 2\n const wl = it.transform.e + left, wr = wl + estW // left/right edge of the content in world coords\n if (wr > W + TOL || wl < -TOL) {\n out.push(warn(`text \"${it.content.slice(0, 24)}${it.content.length > 24 ? '…' : ''}\" overflows the canvas (estimated ~${r0(estW)} px, edge ${r0(wl)}->${r0(wr)} outside 0->${W}) — add \"wrap\"`))\n }\n }\n\n // (e) Drop zones (`hitbox`) that overlap -> ambiguous drop.\n const zones: { name: string; b: NonNullable<ReturnType<typeof dropZoneBounds>> }[] = []\n const collectZones = (layers: Layer[]) => {\n for (const l of layers) for (const it of l.items) {\n if (isGroup(it) && it.hitbox && it.name) { const b = dropZoneBounds(doc, it.name); if (b) zones.push({ name: it.name, b }) }\n if (isGroup(it)) collectZones(it.layers)\n }\n }\n collectZones(doc.layers)\n for (let i = 0; i < zones.length; i++) for (let j = i + 1; j < zones.length; j++) {\n if (bboxIntersects(zones[i].b, zones[j].b)) out.push(warn(`overlapping hitboxes: \"${zones[i].name}\" and \"${zones[j].name}\" -> ambiguous drop`))\n }\n return out\n}\n\n/** Semantic lint of a whole Doc (all the scopes) -> diagnostics labeled by scope.\n * The scope program contains `object` blocks (outside DSL) -> we lint each region\n * separately and re-project the lines (like the editor, cf. CodeEditor.lintFile).\n * Adds the structural warnings (phantom drop zones, dead variables). */\nexport function lintDoc(doc: Doc): { scope: string; diag: Diagnostic }[] {\n const out: { scope: string; diag: Diagnostic }[] = []\n const allVars = allScopeVariables(doc) // computed ONCE (global vars -> known in all the scopes)\n for (const { label, editPath } of scopes(doc)) {\n const ctx = docLintContext(doc, editPath, allVars)\n for (const r of scopeRegions(scopeProgram(doc, editPath))) for (const d of lint(r.body, ctx)) out.push({ scope: label, diag: { ...d, line: d.line + r.line - 1 } })\n }\n out.push(...docStructureWarnings(doc))\n return out\n}\n\nconst sev = (d: Diagnostic) => (d.severity === 'warning' ? 'warning' : 'error')\n\n/** Lint report of a Doc ready to display: `''` = no issue, otherwise `[scope] line:col: level: message`. */\nexport function lintDocReport(doc: Doc): string {\n return lintDoc(doc).map(({ scope, diag }) => `[${scope}] ${diag.line}:${diag.col}: ${sev(diag)}: ${diag.message}`).join('\\n')\n}\n\n/** `true` if the Doc has at least one ERROR (warnings alone do not block). */\nexport function docHasErrors(doc: Doc): boolean {\n return lintDoc(doc).some(({ diag }) => sev(diag) === 'error')\n}\n"],"mappings":"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","names":["parseUnits"]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  docHasErrors,
3
3
  lintDocReport
4
- } from "./chunk-UADRVB63.js";
4
+ } from "./chunk-VXETK5WQ.js";
5
5
  import {
6
6
  compileFlatpack,
7
7
  packToJSON
@@ -411,4 +411,4 @@ function run(argv) {
411
411
  export {
412
412
  run
413
413
  };
414
- //# sourceMappingURL=chunk-OUMQ6NWP.js.map
414
+ //# sourceMappingURL=chunk-WX4UZMNZ.js.map
package/dist/cli/flatc.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  run
3
- } from "../chunk-OUMQ6NWP.js";
4
- import "../chunk-UADRVB63.js";
3
+ } from "../chunk-WX4UZMNZ.js";
4
+ import "../chunk-VXETK5WQ.js";
5
5
  import "../chunk-TPDP5FDF.js";
6
6
  export {
7
7
  run
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  run
3
- } from "./chunk-OUMQ6NWP.js";
3
+ } from "./chunk-WX4UZMNZ.js";
4
4
  import {
5
5
  allScopeVariables,
6
6
  docHasErrors,
@@ -17,7 +17,7 @@ import {
17
17
  scopeProgram,
18
18
  scopeRegions,
19
19
  splitScopeProgram
20
- } from "./chunk-UADRVB63.js";
20
+ } from "./chunk-VXETK5WQ.js";
21
21
  import {
22
22
  compileFlatpack,
23
23
  packToJSON
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flatkit/compiler",
3
- "version": "0.11.0",
3
+ "version": "0.12.1",
4
4
  "description": "The FlatInk language (parser + AST) and compiler (.flatink → .flatpack). Ships the flatc CLI.",
5
5
  "license": "MIT",
6
6
  "author": "Zwyk Studio",
@@ -45,9 +45,9 @@
45
45
  "bin"
46
46
  ],
47
47
  "dependencies": {
48
- "@flatkit/engine": "0.11.0",
49
- "@flatkit/player": "0.11.0",
50
- "@flatkit/types": "0.11.0"
48
+ "@flatkit/player": "0.12.1",
49
+ "@flatkit/engine": "0.12.1",
50
+ "@flatkit/types": "0.12.1"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "skia-canvas": "^3.0.8"
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lint.ts","../src/scopeProgram.ts","../src/programDoc.ts"],"sourcesContent":["// ─────────────────────────────────────────────────────────────────────────────\n// lint.ts — linter for the FlatInk Script language (batch L3).\n//\n// Builds on the parser (dsl.ts) for syntax errors + positions, then adds\n// SEMANTIC validation, ~free and PURE:\n// • each expression is compiled (compileExpr) → expression syntax error;\n// • referenced functions / member objects / identifiers are checked against\n// the standard environment (expr.ts) + the known variables → \"unknown\";\n// • `go to \"label\"` is checked against the set of known labels.\n//\n// Tolerant and kid-friendly: a variable is \"known\" if it is declared\n// (`let`) OR simply assigned (`x = …`) somewhere in the source, or provided\n// by the caller (document global variables). Labels are only checked\n// if the caller provides their list (otherwise we don't know the universe).\n// ─────────────────────────────────────────────────────────────────────────────\nimport { analyzeExpr, STD_CONSTANTS, STD_FUNCTIONS, STD_IDS, STD_OBJECTS } from '@flatkit/engine/expr'\nimport { packageFunctionNames } from '@flatkit/engine/stdlib'\nimport { parseUnits, type Diagnostic, type ScriptUnit } from '@flatkit/engine/dsl'\nimport type { Action } from '@flatkit/engine/actions'\n\nexport type LintContext = {\n /** Known variables in addition to those declared/assigned in the source. */\n variables?: Iterable<string>\n /** Known labels (timeline). Absent = we don't check `go to \"…\"`. */\n labels?: Iterable<string>\n /** Known functions in addition to those defined in the source. */\n functions?: Iterable<string>\n /** Scene objects referenceable by name (`Hero.x`) — in addition to mouse/keys. */\n objects?: Iterable<string>\n}\n\n/** Collects the names of ASSIGNED variables (setVar) + loop vars, inside action bodies. */\nfunction collectAssigned(actions: Action[], into: Set<string>): void {\n for (const a of actions) {\n if (a.do === 'setVar') into.add(a.name)\n else if (a.do === 'if') {\n collectAssigned(a.then, into)\n if (a.else) collectAssigned(a.else, into)\n } else if (a.do === 'repeat') collectAssigned(a.body, into)\n else if (a.do === 'repeatRange') { into.add(a.var); collectAssigned(a.body, into) } // i is known in the body\n }\n}\n\n/** Locally known variables: `let` declarations + every assigned variable. */\nexport function localVariables(units: ScriptUnit[]): Set<string> {\n const vars = new Set<string>()\n for (const u of units) {\n if (u.kind === 'declare') vars.add(u.name)\n else if (u.kind === 'event' || u.kind === 'frameActions') collectAssigned(u.body, vars)\n else if (u.kind === 'each') vars.add(u.as) // the index is known in the each bindings\n else if (u.kind === 'interactor') { if (u.varX) vars.add(u.varX); if (u.varY) vars.add(u.varY) } // drag writes these variables\n else if (u.kind === 'drop') collectAssigned(u.body, vars)\n else if (u.kind === 'func') { for (const p of u.func.params) vars.add(p); if (u.func.kind === 'proc') collectAssigned(u.func.body, vars) } // params + assignments\n }\n return vars\n}\n\n/** Detects a `text(` call (whole word) in an expression → only allowed in a `send` payload. */\nconst TEXT_CALL = /\\btext\\s*\\(/\n\n/** Analyze a DSL source and return all diagnostics (syntax + semantic). */\nexport function lint(src: string, ctx: LintContext = {}): Diagnostic[] {\n const { units, diagnostics, sites } = parseUnits(src)\n const out: Diagnostic[] = [...diagnostics]\n\n const variables = localVariables(units)\n for (const v of ctx.variables ?? []) variables.add(v)\n const knownIds = new Set<string>([...STD_IDS, ...STD_CONSTANTS, ...variables])\n const knownFns = new Set(STD_FUNCTIONS)\n for (const u of units) {\n if (u.kind === 'func') knownFns.add(u.func.name) // user-defined functions\n else if (u.kind === 'use') for (const name of packageFunctionNames(u.name)) knownFns.add(name) // package functions (bare + qualified)\n }\n for (const f of ctx.functions ?? []) knownFns.add(f)\n const knownObjs = new Set(STD_OBJECTS)\n for (const o of ctx.objects ?? []) knownObjs.add(o) // scene objects (Hero.x…)\n const labels = ctx.labels ? new Set(ctx.labels) : null\n\n for (const s of sites) {\n if (s.kind === 'expr') {\n // `text(…)` is valid ONLY as a `send` payload (consumed by the parser, never\n // exposed as an expression site). Seeing it here = out-of-context use → dedicated error.\n if (TEXT_CALL.test(s.text)) {\n out.push({ line: s.line, col: s.col, message: 'text(\"…\") is only allowed as an argument to \"send\"' })\n continue\n }\n const a = analyzeExpr(s.text)\n if (!a.ok) {\n out.push({ line: s.line, col: s.col, message: `invalid expression: ${a.error}` })\n continue\n }\n for (const fn of a.refs.calls) if (!knownFns.has(fn)) out.push({ line: s.line, col: s.col, message: `unknown function \"${fn}\"` })\n for (const o of a.refs.members)\n if (!knownObjs.has(o)) out.push({ line: s.line, col: s.col, message: `unknown object \"${o}\" (expected: ${[...knownObjs].join(', ')})` })\n for (const id of a.refs.ids)\n if (!knownIds.has(id))\n out.push({ line: s.line, col: s.col, message: `unknown variable \"${id}\"${variables.size ? '' : ' — declare it with \"let\"'}` })\n } else if (labels && !labels.has(s.name)) {\n out.push({ line: s.line, col: s.col, message: `unknown label \"${s.name}\"` })\n }\n }\n\n return out.sort((a, b) => a.line - b.line || a.col - b.col)\n}\n\n/**\n * Lint report ready to feed back to a generator (LLM/CLI): `''` = no issue (the code passes),\n * otherwise one `line:col: message` line per diagnostic. Primitive of the \"generate → lint →\n * fix\" loop: the language fits in few tokens, robustness comes from this feedback, not from context.\n */\nexport function lintReport(src: string, ctx: LintContext = {}): string {\n return lint(src, ctx).map((d) => `${d.line}:${d.col}: ${d.message}`).join('\\n')\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// scopeProgram.ts — the \"unified file\" of a scope (the Scene, or a Symbol).\n//\n// Vision: one file = one scope. All the code of a scope fits in ONE text:\n// var … (global variables, root only)\n// when loaded {} (lifecycle of the scope's timeline)\n// every frame {}\n// object \"name\" {} (one block per scripted object of the scope)\n//\n// This is the `.flatink` structure WITHOUT the geometry (which stays visual). This module\n// ONLY deals with the text: splitting the `object` blocks from the rest, and formatting a block.\n// The wiring to the Doc (a single commit) lives in the store, which reuses these functions\n// + scriptDoc/dsl. Pure, no DOM, testable.\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** End of the block opened at `open` (index of the matching `}`), ignoring strings and comments. -1 if unclosed. */\nfunction matchBrace(s: string, open: number): number {\n let depth = 0\n for (let i = open; i < s.length; i++) {\n const c = s[i]\n if (c === '\"') { i++; while (i < s.length && s[i] !== '\"') { if (s[i] === '\\\\') i++; i++ }; continue }\n if (c === '/' && s[i + 1] === '/') { while (i < s.length && s[i] !== '\\n') i++; continue }\n if (c === '{') depth++\n else if (c === '}') { depth--; if (depth === 0) return i }\n }\n return -1\n}\n\n/** Splits a scope file: the `object \"name\" { … }` blocks on one side, the REST (var + lifecycle) on the other. */\nexport function splitScopeProgram(text: string): { rest: string; objects: { name: string; body: string }[] } {\n let rest = ''\n let i = 0\n const objects: { name: string; body: string }[] = []\n while (i < text.length) {\n const m = /object\\s+\"((?:[^\"\\\\]|\\\\.)*)\"\\s*\\{/.exec(text.slice(i))\n if (!m) { rest += text.slice(i); break }\n const start = i + m.index\n rest += text.slice(i, start)\n const ob = start + m[0].length - 1 // the opening brace\n const oc = matchBrace(text, ob)\n if (oc < 0) { rest += text.slice(start); break } // unclosed block → left to the rest (diagnostic downstream)\n objects.push({ name: m[1].replace(/\\\\(.)/g, (_, c) => (c === 'n' ? '\\n' : c)), body: text.slice(ob + 1, oc) })\n i = oc + 1\n }\n return { rest, objects }\n}\n\n/** LINTABLE regions of a scope file (the \"rest\" gaps + the `object` bodies), with their\n * 1-based start line in the original text — to lint each piece as pure DSL and\n * reproject the positions. The `object` keyword and its braces are NOT DSL: we skip them. */\nexport function scopeRegions(text: string): { body: string; line: number }[] {\n const lineAt = (off: number) => text.slice(0, off).split('\\n').length\n const regions: { body: string; line: number }[] = []\n let i = 0\n let restStart = 0\n while (i < text.length) {\n const m = /object\\s+\"((?:[^\"\\\\]|\\\\.)*)\"\\s*\\{/.exec(text.slice(i))\n if (!m) break\n const start = i + m.index\n const gap = text.slice(restStart, start)\n if (gap.trim()) regions.push({ body: gap, line: lineAt(restStart) })\n const ob = start + m[0].length - 1\n const oc = matchBrace(text, ob)\n if (oc < 0) break\n regions.push({ body: text.slice(ob + 1, oc), line: lineAt(ob + 1) })\n i = oc + 1\n restStart = i\n }\n const tail = text.slice(restStart)\n if (tail.trim()) regions.push({ body: tail, line: lineAt(restStart) })\n return regions\n}\n\nconst esc = (s: string) => s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"').replace(/\\n/g, '\\\\n')\nconst indent = (body: string) => body.split('\\n').map((l) => (l.trim() ? ' ' + l : l)).join('\\n')\n\n/** Formats an `object \"name\" { … }` block (body already in DSL). */\nexport function formatObjectBlock(name: string, body: string): string {\n const inner = body.trim()\n return `object \"${esc(name)}\" {\\n${inner ? indent(inner) + '\\n' : ''}}`\n}\n\n/** Assembles a scope file: rest (var + lifecycle) then the object blocks, separated by a blank line. */\nexport function joinScopeProgram(rest: string, objects: { name: string; body: string }[]): string {\n const parts: string[] = []\n if (rest.trim()) parts.push(rest.trim())\n for (const o of objects) if (o.body.trim()) parts.push(formatObjectBlock(o.name, o.body))\n return parts.length ? parts.join('\\n\\n') + '\\n' : ''\n}\n","// -----------------------------------------------------------------------------\n// programDoc.ts — PURE bridge Doc <-> \"scope program\" (text) + lint of a whole Doc.\n//\n// Both the editor AND the CLI need to rebuild the DSL text of a scope (to display it,\n// or to lint it) and to assemble the lint context (variables/labels/functions/objects)\n// FROM a Doc — without depending on the React store. Everything lives here, pure and testable:\n// • `scopeProgram` : Doc fragments -> program text of a scope (round-trip via printUnits);\n// • `docLintContext` : Doc + scope -> LintContext (known names);\n// • `lintDoc` / report : semantic lint of ALL the scopes of a Doc (scene + symbols).\n// -> the CLI gains a `flatc --check`, the editor stops duplicating the logic.\n// -----------------------------------------------------------------------------\nimport type { Doc, EditFrame, Group, Instance } from '@flatkit/types'\nimport { printUnits, type Diagnostic } from '@flatkit/engine/dsl'\nimport { joinScopeProgram, scopeRegions } from './scopeProgram'\nimport { functionsToUnits, importsToUnits, objectToUnits, timelineToUnits, variablesToUnits } from '@flatkit/engine/scriptDoc'\nimport { contextLayers, getScopeTimeline, isContainer, isGroup, isText, isImage } from '@flatkit/engine/layers'\nimport { importedFunctions } from '@flatkit/engine/stdlib'\nimport { objectNames } from '@flatkit/engine/sceneRefs'\nimport { itemBBox, dropZoneBounds } from '@flatkit/engine/groups'\nimport { bboxIntersects } from '@flatkit/engine/bbox'\nimport { lint, localVariables, type LintContext } from './lint'\nimport { parseUnits } from '@flatkit/engine/dsl'\nimport type { Item, Layer, Text } from '@flatkit/types'\n\n/** Rebuilds the \"program\" text of a scope (imports + variables + functions + scene cycle\n * + one `object \"Name\" { … }` block per scripted container with a unique name). Pure, round-trip via printUnits. */\nexport function scopeProgram(doc: Doc, editPath: EditFrame[] = []): string {\n const atRoot = editPath.length === 0\n const items = contextLayers(doc, editPath).flatMap((l) => l.items)\n const nameCount = new Map<string, number>()\n for (const it of items) if (isContainer(it) && it.name) nameCount.set(it.name, (nameCount.get(it.name) ?? 0) + 1)\n const scripted = (it: Group | Instance) => !!doc.interactions?.some((i) => i.targetId === it.id) || !!doc.interactors?.some((i) => i.targetId === it.id) || !!(it.expressions && Object.keys(it.expressions).length)\n const objects = items\n .filter((it): it is Group | Instance => isContainer(it) && !!it.name && nameCount.get(it.name) === 1 && scripted(it))\n .map((it) => ({ name: it.name, body: printUnits(objectToUnits(it.id, doc.interactions, it.expressions, doc.interactors)) }))\n const imports = atRoot ? printUnits(importsToUnits(doc.imports)) : ''\n const funcs = atRoot ? printUnits(functionsToUnits(doc.functions)) : ''\n const globals = atRoot ? printUnits(variablesToUnits(doc.variables)) : ''\n const scene = printUnits(timelineToUnits(getScopeTimeline(doc, editPath)))\n const head = [imports, globals, funcs, scene].filter((t) => t.trim()).join('\\n\\n')\n return joinScopeProgram(head, objects)\n}\n\n/** Lint context of a scope: known names (variables, labels, functions, objects) drawn from the Doc.\n * `extraVars` = variables assigned in the OTHER scopes (FlatInk variables are GLOBAL -> known\n * everywhere; avoids a false \"unknown variable\" on a var written elsewhere, e.g. generated by `match`). */\nexport function docLintContext(doc: Doc, editPath: EditFrame[] = [], extraVars?: Iterable<string>): LintContext {\n return {\n variables: [...Object.keys(doc.variables ?? {}), ...(extraVars ?? [])],\n labels: (getScopeTimeline(doc, editPath)?.labels ?? []).map((l) => l.name),\n functions: [...(doc.functions ?? []).map((f) => f.name), ...importedFunctions(doc.imports).map((f) => f.name)],\n objects: objectNames(contextLayers(doc, editPath)),\n }\n}\n\n/** All the scopes of a Doc: the scene (root) + each symbol of the library. */\nfunction scopes(doc: Doc): { label: string; editPath: EditFrame[] }[] {\n return [{ label: 'scene', editPath: [] }, ...doc.symbols.map((s) => ({ label: s.name, editPath: [{ kind: 'symbol' as const, symbolId: s.id, name: s.name }] }))]\n}\n\n/** Union of the variables ASSIGNED in ALL the scopes (scene + symbols). FlatInk variables are\n * global -> a var written in one scope is legitimate in the others (cross-scope reads). */\nexport function allScopeVariables(doc: Doc): string[] {\n const set = new Set<string>()\n for (const { editPath } of scopes(doc))\n for (const r of scopeRegions(scopeProgram(doc, editPath)))\n for (const v of localVariables(parseUnits(r.body).units)) set.add(v)\n return [...set]\n}\n\n/** Readable name of an item by id (for the messages). */\nfunction itemNameById(doc: Doc, id: string): string | null {\n let found: string | null = null\n const walk = (layers: { items: import('@flatkit/types').Item[] }[]) => {\n for (const l of layers) for (const it of l.items) {\n if (found) return\n if ('name' in it && it.id === id) { found = it.name; return }\n if (isGroup(it)) walk(it.layers)\n }\n }\n walk(doc.layers)\n return found\n}\n\nconst escapeRe = (s: string) => s.replace(/[.*+?^${}()|[\\]\\\\-]/g, '\\\\$&')\n\n/** STRUCTURAL warnings (non-blocking) of a Doc: phantom drop zones, dead variables. */\nexport function docStructureWarnings(doc: Doc): { scope: string; diag: Diagnostic }[] {\n const out: { scope: string; diag: Diagnostic }[] = []\n // (a) `when dropped on X` whose zone X does not exist (no item named so) -> the handler can never fire.\n const names = new Set(objectNames(doc.layers))\n for (const it of doc.interactions ?? []) {\n if (it.event === 'drop' && it.over && !names.has(it.over)) {\n const who = itemNameById(doc, it.targetId) ?? it.targetId\n out.push({ scope: 'scene', diag: { line: 1, col: 1, severity: 'warning', message: `unknown drop zone \"${it.over}\" (object \"${who}\") — no item of the scene carries this name` } })\n }\n }\n // (b) global variable never referenced (declared but not found in any scope) -> probably dead.\n const names0 = Object.keys(doc.variables ?? {})\n if (names0.length) {\n const allText = scopes(doc).map(({ editPath }) => scopeProgram(doc, editPath)).join('\\n')\n for (const name of names0) {\n const m = allText.match(new RegExp(`(?<![\\\\w-])${escapeRe(name)}(?![\\\\w-])`, 'g'))\n if ((m?.length ?? 0) <= 1) out.push({ scope: 'scene', diag: { line: 1, col: 1, severity: 'warning', message: `global variable \"${name}\" never used (declared, but neither read nor written)` } })\n }\n }\n out.push(...docLayoutWarnings(doc))\n return out\n}\n\nconst warn = (message: string): { scope: string; diag: Diagnostic } => ({ scope: 'scene', diag: { line: 1, col: 1, severity: 'warning', message } })\nconst itemLabel = (it: Item): string => ('name' in it && it.name ? it.name : 'kind' in it ? it.kind : 'path')\n/** Estimated width of the longest line (approximate metric, without canvas). */\nfunction estTextWidth(t: Text): number {\n const advance = (t.weight && t.weight >= 700 ? 0.56 : 0.52) * t.size // mean advance of a proportional glyph\n let longest = 0\n for (const line of t.content.split('\\n')) longest = Math.max(longest, line.length)\n return longest * advance\n}\n\n/** LAYOUT warnings (non-blocking): canvas overflow, text too wide, overlapping hitboxes.\n * Approximate but without canvas — catches \"blind\" positioning bugs before the render. */\nexport function docLayoutWarnings(doc: Doc): { scope: string; diag: Diagnostic }[] {\n const out: { scope: string; diag: Diagnostic }[] = []\n const W = doc.width, H = doc.height\n const TOL = 8 // overflow tolerance (px) before alerting\n const r0 = (n: number) => Math.round(n)\n\n // (c) TEXT/IMAGE clipped at the canvas edge. Precise to avoid noise: we ignore `path`/groups\n // (decor that \"bleeds\" on purpose), objects driven by an expression (dynamic position ->\n // misleading static bbox), and items PARKED entirely off-screen (\"hidden\" pattern).\n const dynamicPos = (it: Item) => 'expressions' in it && it.expressions && (it.expressions.x != null || it.expressions.y != null)\n for (const layer of doc.layers) {\n for (const it of layer.items) {\n if (!(isText(it) || isImage(it)) || dynamicPos(it)) continue\n const b = itemBBox(doc, it)\n if (!b) continue\n const visible = b.maxX > 0 && b.minX < W && b.maxY > 0 && b.minY < H // overlaps the canvas (not parked off-screen)\n const clipped = b.minX < -TOL || b.minY < -TOL || b.maxX > W + TOL || b.maxY > H + TOL\n if (visible && clipped) {\n out.push(warn(`\"${itemLabel(it)}\" clipped at the canvas edge: bbox [${r0(b.minX)},${r0(b.minY)} -> ${r0(b.maxX)},${r0(b.maxY)}] outside 0,0 -> ${W},${H}`))\n }\n }\n }\n\n // (d) Text (without `wrap`) whose estimated width makes it OVERFLOW THE CANVAS -> instruction clipped.\n // (We do NOT compare against `box.w`: without wrap, a text overflows its box harmlessly as long as it\n // fits in the canvas — it is the canvas edge that clips.) Top-level only (x = world).\n for (const it of doc.layers.flatMap((l) => l.items)) {\n if (!isText(it) || it.wrap || dynamicPos(it)) continue\n const estW = estTextWidth(it)\n const left = it.align === 'left' ? 0 : it.align === 'right' ? it.box.w - estW : it.box.w / 2 - estW / 2\n const wl = it.transform.e + left, wr = wl + estW // left/right edge of the content in world coords\n if (wr > W + TOL || wl < -TOL) {\n out.push(warn(`text \"${it.content.slice(0, 24)}${it.content.length > 24 ? '…' : ''}\" overflows the canvas (estimated ~${r0(estW)} px, edge ${r0(wl)}->${r0(wr)} outside 0->${W}) — add \"wrap\"`))\n }\n }\n\n // (e) Drop zones (`hitbox`) that overlap -> ambiguous drop.\n const zones: { name: string; b: NonNullable<ReturnType<typeof dropZoneBounds>> }[] = []\n const collectZones = (layers: Layer[]) => {\n for (const l of layers) for (const it of l.items) {\n if (isGroup(it) && it.hitbox && it.name) { const b = dropZoneBounds(doc, it.name); if (b) zones.push({ name: it.name, b }) }\n if (isGroup(it)) collectZones(it.layers)\n }\n }\n collectZones(doc.layers)\n for (let i = 0; i < zones.length; i++) for (let j = i + 1; j < zones.length; j++) {\n if (bboxIntersects(zones[i].b, zones[j].b)) out.push(warn(`overlapping hitboxes: \"${zones[i].name}\" and \"${zones[j].name}\" -> ambiguous drop`))\n }\n return out\n}\n\n/** Semantic lint of a whole Doc (all the scopes) -> diagnostics labeled by scope.\n * The scope program contains `object` blocks (outside DSL) -> we lint each region\n * separately and re-project the lines (like the editor, cf. CodeEditor.lintFile).\n * Adds the structural warnings (phantom drop zones, dead variables). */\nexport function lintDoc(doc: Doc): { scope: string; diag: Diagnostic }[] {\n const out: { scope: string; diag: Diagnostic }[] = []\n const allVars = allScopeVariables(doc) // computed ONCE (global vars -> known in all the scopes)\n for (const { label, editPath } of scopes(doc)) {\n const ctx = docLintContext(doc, editPath, allVars)\n for (const r of scopeRegions(scopeProgram(doc, editPath))) for (const d of lint(r.body, ctx)) out.push({ scope: label, diag: { ...d, line: d.line + r.line - 1 } })\n }\n out.push(...docStructureWarnings(doc))\n return out\n}\n\nconst sev = (d: Diagnostic) => (d.severity === 'warning' ? 'warning' : 'error')\n\n/** Lint report of a Doc ready to display: `''` = no issue, otherwise `[scope] line:col: level: message`. */\nexport function lintDocReport(doc: Doc): string {\n return lintDoc(doc).map(({ scope, diag }) => `[${scope}] ${diag.line}:${diag.col}: ${sev(diag)}: ${diag.message}`).join('\\n')\n}\n\n/** `true` if the Doc has at least one ERROR (warnings alone do not block). */\nexport function docHasErrors(doc: Doc): boolean {\n return lintDoc(doc).some(({ diag }) => sev(diag) === 'error')\n}\n"],"mappings":"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","names":["parseUnits"]}