bonsai-js 1.1.0 → 1.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.
- package/CHANGELOG.md +9 -0
- package/README.md +4 -4
- package/dist/builtins/index.d.mts +91 -0
- package/dist/builtins/index.mjs +93 -0
- package/dist/builtins/index.mjs.map +1 -0
- package/dist/check/checker.mjs +20 -4
- package/dist/check/checker.mjs.map +1 -1
- package/dist/environment.d.mts +13 -0
- package/dist/environment.mjs +14 -7
- package/dist/environment.mjs.map +1 -1
- package/dist/functions/builtins.mjs +550 -473
- package/dist/functions/builtins.mjs.map +1 -1
- package/dist/functions/define.mjs +41 -6
- package/dist/functions/define.mjs.map +1 -1
- package/dist/functions/descriptions.mjs +110 -0
- package/dist/functions/descriptions.mjs.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/lite/index.d.mts +2 -2
- package/dist/lite/index.mjs.map +1 -1
- package/dist/load.mjs +1 -2
- package/dist/load.mjs.map +1 -1
- package/dist/program.mjs +6 -8
- package/dist/program.mjs.map +1 -1
- package/dist/runtime/core.d.mts +18 -0
- package/dist/runtime/core.mjs +31 -0
- package/dist/runtime/core.mjs.map +1 -0
- package/dist/runtime/create.d.mts +61 -0
- package/dist/runtime/create.mjs +76 -0
- package/dist/runtime/create.mjs.map +1 -0
- package/dist/runtime/index.d.mts +4 -41
- package/dist/runtime/index.mjs +7 -68
- package/dist/runtime/index.mjs.map +1 -1
- package/dist/service/index.mjs +4 -3
- package/dist/service/index.mjs.map +1 -1
- package/dist/version.mjs +1 -1
- package/dist/version.mjs.map +1 -1
- package/package.json +17 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/service/index.ts"],"sourcesContent":["import { acceptsArgument, analyze, type Analysis } from '../check/checker.js'\nimport { internalsOf, type Environment, type LiteEnvironment } from '../environment.js'\nimport { BonsaiError, BonsaiSyntaxError, locate, type Diagnostic } from '../errors.js'\nimport { assertType, signatureText, type FunctionDef } from '../functions/define.js'\nimport { forEachChild, type Node } from '../syntax/ast.js'\nimport { parse } from '../syntax/parser.js'\nimport {\n fieldOf,\n formatType,\n isExact,\n nonNull,\n t,\n typeData,\n unionMembers,\n unionOf,\n widen,\n type MapType,\n type Type,\n} from '../types.js'\n\nexport type CompletionKind =\n | 'value'\n | 'variable'\n | 'local'\n | 'property'\n | 'function'\n | 'method'\n | 'keyword'\n\nexport interface Completion {\n readonly label: string\n readonly kind: CompletionKind\n /** Type or signature text. */\n readonly detail: string\n readonly documentation?: string\n /** Text to insert (e.g. `trim()` for a method). */\n readonly insertText: string\n /**\n * The range this item replaces, when it differs from the result's range: a\n * field that is not a plain name is inserted as `[\"first-name\"]` in place of\n * the `.` before it.\n */\n readonly range?: { readonly start: number; readonly end: number }\n}\n\nexport interface CompletionResult {\n /** The range the completion replaces (the partially typed name). */\n readonly start: number\n readonly end: number\n readonly items: readonly Completion[]\n}\n\nexport interface HoverResult {\n readonly start: number\n readonly end: number\n /** Type of the expression under the cursor, or the function signature. */\n readonly detail: string\n readonly documentation?: string\n}\n\nexport interface LanguageService {\n /** Completions at a UTF-16 offset in `source`. */\n complete: (source: string, offset: number) => CompletionResult\n /** Type information for the expression at `offset`. */\n hover: (source: string, offset: number) => HoverResult | undefined\n /** Every syntax and check diagnostic, never throwing. */\n diagnostics: (source: string) => readonly Diagnostic[]\n}\n\nconst PROBE = '__bonsai_probe__'\n\nconst CLOSER: Readonly<Record<string, string>> = { '(': ')', '[': ']', '{': '}', '${': '}' }\nconst KEYWORDS = ['true', 'false', 'null', 'let', 'has', 'try', 'not in', 'in']\nconst IDENT_CHAR = /[A-Za-z0-9_$]/u\nconst IDENTIFIER = /^[A-Za-z_$][\\w$]*$/u\n\n/**\n * A UTF-16 offset inside `source`: past the end, or NaN, means the end. A\n * negative or fractional offset is a caller bug (RangeError), and so is a\n * source or an offset of the wrong type (TypeError).\n */\nfunction clampOffset(source: string, offset: number): number {\n if (typeof source !== 'string') throw new TypeError('An expression must be a string')\n if (typeof offset !== 'number') {\n throw new TypeError(`An offset must be a number, not ${typeof offset}`)\n }\n if (offset < 0 || (Number.isFinite(offset) && !Number.isInteger(offset))) {\n throw new RangeError(`An offset must be a whole number of at least 0, not ${offset}`)\n }\n return Number.isNaN(offset) ? source.length : Math.min(offset, source.length)\n}\n\nexport interface LanguageServiceOptions {\n /**\n * The type every expression must have, as `check(source, { expect })` takes\n * it: diagnostics then include EXPECTED_TYPE (a filter editor passes\n * `t.boolean()`).\n */\n readonly expect?: Type | undefined\n}\n\n/** Reads the service options once: only `expect`, which must be a type built with t. */\nfunction serviceExpect(options: unknown): Type | undefined {\n if (options === undefined) return undefined\n if (typeof options !== 'object' || options === null || Array.isArray(options))\n throw new TypeError('Language service options must be an object')\n for (const key of Object.keys(options)) {\n if (key !== 'expect')\n throw new TypeError(`Unknown language service option key \"${key}\" (expected one of: expect)`)\n }\n const expect = (options as { expect?: unknown }).expect\n if (expect === undefined) return undefined\n // Kept as a private copy, like compile()'s, so later changes do not reach it.\n assertType(expect, 'Language service option \"expect\"')\n const own = typeData(expect)\n if (own !== expect) assertType(own, 'Language service option \"expect\"')\n return own\n}\n\n/**\n * Editor features over an environment. Nothing here evaluates an expression or\n * calls a host function: completions and hovers come from the static checker.\n */\nexport function createLanguageService(\n env: Environment | LiteEnvironment,\n options?: LanguageServiceOptions,\n): LanguageService {\n const { checkEnv, parseLimits } = internalsOf(env)\n const expect = serviceExpect(options)\n const checkOptions = expect === undefined ? undefined : { expect }\n\n function tryAnalyze(source: string, probe?: string): Analysis | undefined {\n try {\n return analyze(parse(source, parseLimits), checkEnv, { probe, expected: expect })\n } catch (error) {\n if (error instanceof BonsaiError) return undefined\n throw error\n }\n }\n\n /**\n * How far `source` parses: Infinity when it parses whole, the offset of the\n * first token it cannot take (its length when it only ends too soon), or -1\n * past a limit. A ` ]` after it, which nothing can continue with, turns\n * \"the expression ended\" into an error past the end.\n */\n function parsesTo(source: string, budget: { left: number }): number {\n for (const text of [source, `${source} ]`]) {\n // Out of parses: no answer, which ends the search.\n if (budget.left-- <= 0) return -1\n try {\n parse(text, parseLimits)\n if (text === source) return Number.POSITIVE_INFINITY\n } catch (error) {\n if (!(error instanceof BonsaiError)) throw error\n if (!(error instanceof BonsaiSyntaxError) || error.span === undefined) return -1\n if (text !== source) return Math.min(error.span.start, source.length)\n }\n }\n return -1\n }\n\n /**\n * An ending for nested open constructs no single ending covers, such as\n * `let v = try(o1.`: at each closer, innermost first, and after the last,\n * the fillers the parser gets through (a few at most), within the parses\n * `budget` has left.\n */\n function builtEnding(\n text: string,\n closers: string,\n budget: { left: number },\n ): string | undefined {\n let built = text\n for (let gap = 0; gap <= closers.length; gap++) {\n const rest = closers.slice(gap)\n for (let round = 0; round < MAX_FILLERS; round++) {\n const reached = parsesTo(built + rest, budget)\n // A mistake before the probe is one no ending can mend.\n if (reached < text.length) return undefined\n if (reached === Number.POSITIVE_INFINITY) return built + rest\n // The parser got past this closer: what is missing is further out.\n if (reached > built.length) break\n let filler: string | undefined\n for (const f of FILLERS) {\n if (budget.left <= 0) return undefined\n if (parsesTo(built + f + rest, budget) >= built.length + f.length) {\n filler = f\n break\n }\n }\n if (filler === undefined) return undefined\n built += filler\n }\n if (gap < closers.length) built += closers[gap]\n }\n return undefined\n }\n\n function complete(source: string, offset: number): CompletionResult {\n const cursor = clampOffset(source, offset)\n let from = cursor\n while (from > 0 && IDENT_CHAR.test(source[from - 1])) from--\n let to = cursor\n while (to < source.length && IDENT_CHAR.test(source[to])) to++\n const typed = source.slice(from, cursor)\n const empty: CompletionResult = { start: from, end: to, items: [] }\n\n const prefix = source.slice(0, from)\n const scan = scanOpen(prefix)\n // Inside a string after == or != (user.plan == \"p|), in a list after `in`\n // (user.plan in [\"pro\", \"f|), or as a call argument (roles.includes(\"a|),\n // xs.sortBy(.k, \"d|)): offer the values the other side allows.\n const quoted =\n /(?:==|!=|[(,]|\\bin\\s*\\[(?:\\s*(?:\"[^\"\\\\]*\"|'[^'\\\\]*')\\s*,)*)\\s*(?<quote>[\"'])(?<typed>[^\"'\\\\]*)$/u.exec(\n source.slice(0, cursor),\n )\n if (quoted !== null && scan.inString) {\n const enumPrefix = quoted.groups?.typed ?? ''\n const quoteAt = cursor - enumPrefix.length\n const outer = source.slice(0, quoteAt - 1)\n const outerScan = scanOpen(outer)\n const analysis = tryAnalyze(`${outer}${PROBE}${outerScan.closers}`, PROBE)\n const values =\n analysis === undefined ? [] : literalValues(analysis).filter((v) => typeof v === 'string')\n const items = values.map((v) => ({\n label: v,\n kind: 'value' as const,\n detail: 'value',\n insertText: v,\n }))\n let end = cursor\n while (end < source.length && source[end] !== quoted.groups?.quote) end++\n return { start: quoteAt, end, items: rank(items, enumPrefix) }\n }\n if (scan.inString || scan.inComment) return empty\n if (from > 0 && /[0-9]/u.test(source[from - 1])) return empty\n\n // Whitespace and comments may sit between a `.` and the cursor.\n const before = withoutTrailingTrivia(prefix)\n const afterDot = before.endsWith('?.') || (before.endsWith('.') && !before.endsWith('...'))\n const probeText = afterDot ? `${before}${PROBE}` : `${prefix}${PROBE}`\n\n // Every parse below counts against one budget, so a completion costs at\n // most a fixed number of parses however the source nests, and at most a\n // few parses' worth of text when the source is long.\n const budget = {\n left: Math.min(\n MAX_COMPLETION_PARSES,\n Math.max(MIN_COMPLETION_PARSES, Math.floor(MAX_COMPLETION_CHARS / probeText.length)),\n ),\n }\n let analysis: Analysis | undefined\n for (const suffix of probeSuffixes(scan.closers)) {\n if (budget.left-- <= 0) break\n analysis = tryAnalyze(probeText + suffix, PROBE)\n if (analysis !== undefined) break\n }\n // The last parse is kept for analyzing the ending found.\n budget.left--\n if (analysis === undefined && budget.left > 0) {\n const ended = builtEnding(probeText, scan.closers, budget)\n if (ended !== undefined) analysis = tryAnalyze(ended, PROBE)\n }\n if (analysis === undefined) return empty\n\n const dotAt = afterDot && !before.endsWith('?.') ? before.length - 1 : undefined\n const items = afterDot\n ? memberCompletions(analysis, dotAt === undefined ? undefined : { start: dotAt, end: to })\n : nameCompletions(analysis)\n if (!afterDot && /(?:==|!=)\\s*$/u.test(prefix)) {\n for (const value of literalValues(analysis)) {\n items.unshift({\n label: JSON.stringify(value),\n kind: 'value',\n detail: 'value',\n insertText: JSON.stringify(value),\n })\n }\n }\n return { start: from, end: to, items: rank(items, typed) }\n }\n\n /** Literal members of the type on the other side of `== probe` or `in [..., probe]`. */\n function literalValues(analysis: Analysis): (string | number | boolean)[] {\n let other: Type | undefined\n const isProbe = (node: Node): boolean => node.type === 'Variable' && node.name === PROBE\n const find = (node: Node): void => {\n if (other !== undefined) return\n if (node.type === 'Binary' && (node.operator === '==' || node.operator === '!=')) {\n if (isProbe(node.right)) other = analysis.types.get(node.left)\n else if (isProbe(node.left)) other = analysis.types.get(node.right)\n if (other !== undefined) return\n }\n if (\n node.type === 'Binary' &&\n (node.operator === 'in' || node.operator === 'not in') &&\n node.right.type === 'List' &&\n node.right.items.some((item) => item.type !== 'Spread' && isProbe(item))\n ) {\n other = analysis.types.get(node.left)\n if (other !== undefined) return\n }\n if (node.type === 'Call') {\n const index = node.args.findIndex((arg) => arg.type !== 'Spread' && isProbe(arg))\n if (index > 0) {\n const receiver = node.args[0]\n if (node.name === 'includes' && index === 1 && receiver.type !== 'Spread') {\n // roles.includes(\"a\"): the list's element type.\n const list = analysis.types.get(receiver)\n const listType = list === undefined ? undefined : nonNull(list)\n if (listType?.kind === 'list') other = listType.element\n } else {\n // A parameter declared as literals (sortBy's \"asc\" | \"desc\").\n const plan = analysis.calls.get(node)\n const overload = plan?.def.overloads[plan.candidates[0] ?? 0]\n const param = overload?.params[index] ?? overload?.rest\n if (param !== undefined && unionMembers(param).every((m) => m.kind === 'literal'))\n other = param\n }\n if (other !== undefined) return\n }\n }\n forEachChild(node, find)\n }\n find(analysis.root)\n if (other === undefined) return []\n return unionMembers(other).flatMap((member) =>\n member.kind === 'literal' ? [member.value] : [],\n )\n }\n\n /** Completions after `receiver.`; `dot` is the range of the `.` and the typed name. */\n function memberCompletions(\n analysis: Analysis,\n dot: { start: number; end: number } | undefined,\n ): Completion[] {\n let receiver: Type | undefined\n // `.name` directly after an implicit-lambda `.` (xs.map(.name)).\n let onItem = false\n const find = (node: Node): void => {\n if (receiver !== undefined) return\n if (node.type === 'Member' && node.name === PROBE) {\n receiver = analysis.types.get(node.object)\n onItem = node.object.type === 'It'\n return\n }\n forEachChild(node, find)\n }\n find(analysis.root)\n if (receiver === undefined) return []\n const target = nonNull(receiver)\n const items: Completion[] = []\n const members = unionMembers(target)\n // Fields of every map member (a union of records offers each one's keys).\n const maps = members.filter((member): member is MapType => member.kind === 'map')\n const names = new Set(maps.flatMap((member) => Object.keys(member.fields)))\n // The type a read has, as check() and hover report it: a member without\n // the field reads its `rest` (or null), and a declared object may hold any key.\n const readOf = (member: MapType, name: string): Type => {\n const field = fieldOf(member, name)\n if (field !== undefined) return field\n if (member.rest !== undefined) return t.optional(member.rest)\n return isExact(member) ? t.null() : t.any()\n }\n for (const name of names) {\n const detail = formatType(\n analysis.probeMembers?.get(name) ?? unionOf(maps.map((member) => readOf(member, name))),\n )\n if (IDENTIFIER.test(name)) {\n items.push({ label: name, kind: 'property', detail, insertText: name })\n } else {\n // `user.first-name` would subtract: index it instead. The item's own\n // `.` stays: xs.map(.[\"first-name\"]).\n items.push({\n label: name,\n kind: 'property',\n detail,\n insertText: `${onItem ? '.' : ''}[${JSON.stringify(name)}]`,\n ...(dot === undefined ? {} : { range: dot }),\n })\n }\n }\n if (\n members.some(\n (member) =>\n member.kind === 'list' ||\n member.kind === 'string' ||\n (member.kind === 'literal' && typeof member.value === 'string'),\n )\n ) {\n items.push({ label: 'length', kind: 'property', detail: 'number', insertText: 'length' })\n }\n // Functions whose first parameter accepts the receiver can be called as\n // methods; for a union, every member must be accepted by some signature.\n const receivers = unionMembers(widen(target))\n for (const name of checkEnv.functionNames()) {\n const def = checkEnv.lookup(name) as FunctionDef\n const firstOf = (o: (typeof def.overloads)[number]): Type | undefined => {\n const first = o.params[0] ?? o.rest\n return first === undefined || first.kind === 'function' ? undefined : first\n }\n const accepts = (o: (typeof def.overloads)[number], member: Type): boolean => {\n const first = firstOf(o)\n return first !== undefined && (member.kind === 'any' || acceptsArgument(first, member))\n }\n const applicable = def.overloads.filter((o) => receivers.some((member) => accepts(o, member)))\n if (\n applicable.length === 0 ||\n !receivers.every((member) => applicable.some((o) => accepts(o, member)))\n )\n continue\n items.push({\n label: name,\n kind: 'method',\n detail: applicable.map((o) => signatureText(name, o)).join('\\n'),\n documentation: def.description,\n insertText: `${name}(${takesMore(def) ? '' : ')'}`,\n })\n }\n return items\n }\n\n function nameCompletions(analysis: Analysis): Completion[] {\n const items: Completion[] = []\n const scope = analysis.probeScope\n if (scope?.it !== undefined) {\n items.push({\n label: '.',\n kind: 'local',\n detail: formatType(scope.it),\n documentation: 'The current item',\n insertText: '.',\n })\n }\n for (const [name, type] of scope?.locals ?? []) {\n items.push({ label: name, kind: 'local', detail: formatType(type), insertText: name })\n }\n for (const [name, type] of Object.entries(checkEnv.variables ?? {})) {\n items.push({ label: name, kind: 'variable', detail: formatType(type), insertText: name })\n }\n for (const name of checkEnv.functionNames()) {\n const def = checkEnv.lookup(name) as FunctionDef\n items.push({\n label: name,\n kind: 'function',\n detail: def.overloads.map((o) => signatureText(name, o)).join('\\n'),\n documentation: def.description,\n insertText: `${name}(`,\n })\n }\n for (const keyword of KEYWORDS) {\n items.push({\n label: keyword,\n kind: 'keyword',\n detail: 'keyword',\n insertText: keyword === 'has' || keyword === 'try' ? `${keyword}(` : keyword,\n })\n }\n return items\n }\n\n function hover(source: string, rawOffset: number): HoverResult | undefined {\n const offset = clampOffset(source, rawOffset)\n const analysis = tryAnalyze(source)\n if (analysis === undefined) return undefined\n let best: Node | undefined\n const visit = (node: Node): void => {\n if (offset < node.start || offset > node.end) return\n // The implicit item's `.` ends where the name after it starts (`.cat`):\n // an offset on that name belongs to the member, not the item.\n if (node.type === 'It' && offset === node.end && best?.type === 'Member') return\n best = node\n forEachChild(node, visit)\n }\n visit(analysis.root)\n if (best === undefined) return undefined\n const node: Node = best\n if (\n node.type === 'Call' &&\n node.nameStart !== undefined &&\n node.nameEnd !== undefined &&\n offset >= node.nameStart &&\n offset <= node.nameEnd\n ) {\n const def = checkEnv.lookup(node.name)\n if (def !== undefined) {\n return {\n start: node.nameStart,\n end: node.nameEnd,\n detail: def.overloads.map((o) => signatureText(def.name, o)).join('\\n'),\n documentation: def.description,\n }\n }\n }\n const type = analysis.types.get(node)\n if (type === undefined) return undefined\n return {\n start: node.start,\n end: node.end,\n detail: formatType(type.kind === 'literal' ? widen(type) : type),\n }\n }\n\n function diagnostics(source: string): readonly Diagnostic[] {\n // Spans stay inside the source (an error at the end is zero-width there).\n const found = env.check(source, checkOptions).diagnostics\n if (found.every((d) => d.start >= 0 && d.end >= d.start && d.end <= source.length)) return found\n return locate(\n source,\n found.map((d) => {\n const start = Math.min(Math.max(d.start, 0), source.length)\n return { ...d, start, end: Math.min(Math.max(d.end, start), source.length) }\n }),\n )\n }\n\n return Object.freeze({ complete, hover, diagnostics })\n}\n\nfunction takesMore(def: FunctionDef): boolean {\n return def.overloads.some((o) => o.params.length > 1 || o.rest !== undefined)\n}\n\nfunction rank(items: readonly Completion[], typed: string): Completion[] {\n const needle = typed.toLowerCase()\n const scored = items\n .map((item) => {\n const label = item.label.toLowerCase()\n let score = 0\n if (needle === '') score = 1\n else if (label.startsWith(needle)) score = 2\n else if (label.includes(needle)) score = 1\n return { item, score }\n })\n .filter((entry) => entry.score > 0)\n const order: Record<CompletionKind, number> = {\n value: -1,\n local: 0,\n property: 1,\n variable: 2,\n method: 3,\n function: 4,\n keyword: 5,\n }\n scored.sort(\n (a, b) =>\n b.score - a.score ||\n order[a.item.kind] - order[b.item.kind] ||\n a.item.label.localeCompare(b.item.label),\n )\n const seen = new Set<string>()\n return scored\n .map((entry) => entry.item)\n .filter((item) => !seen.has(item.label) && (seen.add(item.label), true))\n}\n\n/** `text` without the whitespace and comments at its end. */\nfunction withoutTrailingTrivia(text: string): string {\n const startOf = new Map(commentSpans(text).map((span) => [span.end, span.start]))\n let end = text.length\n for (;;) {\n while (end > 0 && /\\s/u.test(text[end - 1])) end--\n const start = startOf.get(end)\n if (start === undefined) break\n end = start\n }\n return text.slice(0, end)\n}\n\n/** The comments in `text` (outside strings and templates), as [start, end) spans. */\nfunction commentSpans(text: string): { start: number; end: number }[] {\n const spans: { start: number; end: number }[] = []\n let i = 0\n let template = 0\n while (i < text.length) {\n const ch = text[i]\n if (template > 0 && ch === '`') {\n template--\n i++\n } else if (template > 0) {\n i += ch === '\\\\' ? 2 : 1\n } else if (ch === '`') {\n template++\n i++\n } else if (ch === '/' && text[i + 1] === '/') {\n let end = text.indexOf('\\n', i)\n if (end === -1) end = text.length\n spans.push({ start: i, end })\n i = end\n } else if (ch === '/' && text[i + 1] === '*') {\n const close = text.indexOf('*/', i + 2)\n const end = close === -1 ? text.length : close + 2\n spans.push({ start: i, end })\n i = end\n } else if (ch === '\"' || ch === \"'\") {\n let j = i + 1\n while (j < text.length && text[j] !== ch) j += text[j] === '\\\\' ? 2 : 1\n i = j + 1\n } else i++\n }\n return spans\n}\n\n/** Open constructs a filler is tried inside of, innermost first. */\nconst PROBE_SPLITS = 4\n\n/** What a nested ending may add at one closer: a missing branch, argument, value, or body. */\nconst FILLERS = [' : null', ', null', ': null', '; null', ' 0']\n/** Fillers one closer may take, as in try(b ? x : null, null). */\nconst MAX_FILLERS = 3\n/**\n * Parses one completion may cost in all (fixed endings, nested ending search,\n * and its analysis): enough for every ending a short source needs.\n */\nconst MAX_COMPLETION_PARSES = 100\n/**\n * Characters one completion may parse in all, so a long source gets fewer\n * tries (each costs a parse of the whole source), but never fewer than\n * {@link MIN_COMPLETION_PARSES}.\n */\nconst MAX_COMPLETION_CHARS = 1_200_000\n/** Enough for the fixed endings a single open construct needs, plus the analysis. */\nconst MIN_COMPLETION_PARSES = 12\n\n/**\n * Endings that make a prefix ending in the probe parse, cheapest first: the\n * closers alone, a missing branch or value inside them, the missing half of\n * an enclosing try(x, fallback) or computed key [k]: v, and a `let` body or\n * `?:` branch after them.\n */\nfunction probeSuffixes(closers: string): string[] {\n const out = [\n closers,\n ` : null${closers}`,\n `; null${closers}`,\n ` 0${closers}`,\n `, null${closers}`,\n `${closers}; null`,\n `${closers} : null`,\n `${closers} : null; null`,\n ]\n for (let at = 1; at <= Math.min(closers.length, PROBE_SPLITS); at++) {\n const inner = closers.slice(0, at)\n const outer = closers.slice(at)\n out.push(`${inner}: null${outer}`, `${inner}, null${outer}`)\n }\n return [...new Set(out)]\n}\n\n/** Tracks open brackets, strings, and templates in a prefix to synthesize closers. */\nfunction scanOpen(text: string): { closers: string; inString: boolean; inComment: boolean } {\n const stack: string[] = []\n let i = 0\n while (i < text.length) {\n const ch = text[i]\n const top = stack[stack.length - 1]\n if (top === '`') {\n if (ch === '\\\\') i += 2\n else if (ch === '`') {\n stack.pop()\n i++\n } else if (ch === '$' && text[i + 1] === '{') {\n stack.push('${')\n i += 2\n } else i++\n continue\n }\n if (ch === '/' && text[i + 1] === '/') {\n const end = text.indexOf('\\n', i)\n if (end === -1) return { closers: '', inString: false, inComment: true }\n i = end\n continue\n }\n if (ch === '/' && text[i + 1] === '*') {\n const end = text.indexOf('*/', i + 2)\n if (end === -1) return { closers: '', inString: false, inComment: true }\n i = end + 2\n continue\n }\n if (ch === '\"' || ch === \"'\") {\n let j = i + 1\n while (j < text.length && text[j] !== ch) j += text[j] === '\\\\' ? 2 : 1\n if (j >= text.length) return { closers: '', inString: true, inComment: false }\n i = j + 1\n continue\n }\n if (ch === '`') stack.push('`')\n else if (ch === '(' || ch === '[' || ch === '{') stack.push(ch)\n else if (ch === ')' || ch === ']' || ch === '}') {\n if (top === '${' && ch === '}') stack.pop()\n else if (top === '(' || top === '[' || top === '{') stack.pop()\n }\n i++\n }\n if (stack[stack.length - 1] === '`') return { closers: '', inString: true, inComment: false }\n const closers = stack\n .reverse()\n .map((open) => CLOSER[open] ?? '`')\n .join('')\n return { closers, inString: false, inComment: false }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/service/index.ts"],"sourcesContent":["import { acceptsArgument, analyze, type Analysis } from '../check/checker.js'\nimport { internalsOf, type Environment, type LiteEnvironment } from '../environment.js'\nimport { BonsaiError, BonsaiSyntaxError, locate, type Diagnostic } from '../errors.js'\nimport { assertType, signatureText, type FunctionDef } from '../functions/define.js'\nimport { descriptionOf } from '../functions/descriptions.js'\nimport { forEachChild, type Node } from '../syntax/ast.js'\nimport { parse } from '../syntax/parser.js'\nimport {\n fieldOf,\n formatType,\n isExact,\n nonNull,\n t,\n typeData,\n unionMembers,\n unionOf,\n widen,\n type MapType,\n type Type,\n} from '../types.js'\n\nexport type CompletionKind =\n | 'value'\n | 'variable'\n | 'local'\n | 'property'\n | 'function'\n | 'method'\n | 'keyword'\n\nexport interface Completion {\n readonly label: string\n readonly kind: CompletionKind\n /** Type or signature text. */\n readonly detail: string\n readonly documentation?: string\n /** Text to insert (e.g. `trim()` for a method). */\n readonly insertText: string\n /**\n * The range this item replaces, when it differs from the result's range: a\n * field that is not a plain name is inserted as `[\"first-name\"]` in place of\n * the `.` before it.\n */\n readonly range?: { readonly start: number; readonly end: number }\n}\n\nexport interface CompletionResult {\n /** The range the completion replaces (the partially typed name). */\n readonly start: number\n readonly end: number\n readonly items: readonly Completion[]\n}\n\nexport interface HoverResult {\n readonly start: number\n readonly end: number\n /** Type of the expression under the cursor, or the function signature. */\n readonly detail: string\n readonly documentation?: string\n}\n\nexport interface LanguageService {\n /** Completions at a UTF-16 offset in `source`. */\n complete: (source: string, offset: number) => CompletionResult\n /** Type information for the expression at `offset`. */\n hover: (source: string, offset: number) => HoverResult | undefined\n /** Every syntax and check diagnostic, never throwing. */\n diagnostics: (source: string) => readonly Diagnostic[]\n}\n\nconst PROBE = '__bonsai_probe__'\n\nconst CLOSER: Readonly<Record<string, string>> = { '(': ')', '[': ']', '{': '}', '${': '}' }\nconst KEYWORDS = ['true', 'false', 'null', 'let', 'has', 'try', 'not in', 'in']\nconst IDENT_CHAR = /[A-Za-z0-9_$]/u\nconst IDENTIFIER = /^[A-Za-z_$][\\w$]*$/u\n\n/**\n * A UTF-16 offset inside `source`: past the end, or NaN, means the end. A\n * negative or fractional offset is a caller bug (RangeError), and so is a\n * source or an offset of the wrong type (TypeError).\n */\nfunction clampOffset(source: string, offset: number): number {\n if (typeof source !== 'string') throw new TypeError('An expression must be a string')\n if (typeof offset !== 'number') {\n throw new TypeError(`An offset must be a number, not ${typeof offset}`)\n }\n if (offset < 0 || (Number.isFinite(offset) && !Number.isInteger(offset))) {\n throw new RangeError(`An offset must be a whole number of at least 0, not ${offset}`)\n }\n return Number.isNaN(offset) ? source.length : Math.min(offset, source.length)\n}\n\nexport interface LanguageServiceOptions {\n /**\n * The type every expression must have, as `check(source, { expect })` takes\n * it: diagnostics then include EXPECTED_TYPE (a filter editor passes\n * `t.boolean()`).\n */\n readonly expect?: Type | undefined\n}\n\n/** Reads the service options once: only `expect`, which must be a type built with t. */\nfunction serviceExpect(options: unknown): Type | undefined {\n if (options === undefined) return undefined\n if (typeof options !== 'object' || options === null || Array.isArray(options))\n throw new TypeError('Language service options must be an object')\n for (const key of Object.keys(options)) {\n if (key !== 'expect')\n throw new TypeError(`Unknown language service option key \"${key}\" (expected one of: expect)`)\n }\n const expect = (options as { expect?: unknown }).expect\n if (expect === undefined) return undefined\n // Kept as a private copy, like compile()'s, so later changes do not reach it.\n assertType(expect, 'Language service option \"expect\"')\n const own = typeData(expect)\n if (own !== expect) assertType(own, 'Language service option \"expect\"')\n return own\n}\n\n/**\n * Editor features over an environment. Nothing here evaluates an expression or\n * calls a host function: completions and hovers come from the static checker.\n */\nexport function createLanguageService(\n env: Environment | LiteEnvironment,\n options?: LanguageServiceOptions,\n): LanguageService {\n const { checkEnv, parseLimits } = internalsOf(env)\n const expect = serviceExpect(options)\n const checkOptions = expect === undefined ? undefined : { expect }\n\n function tryAnalyze(source: string, probe?: string): Analysis | undefined {\n try {\n return analyze(parse(source, parseLimits), checkEnv, { probe, expected: expect })\n } catch (error) {\n if (error instanceof BonsaiError) return undefined\n throw error\n }\n }\n\n /**\n * How far `source` parses: Infinity when it parses whole, the offset of the\n * first token it cannot take (its length when it only ends too soon), or -1\n * past a limit. A ` ]` after it, which nothing can continue with, turns\n * \"the expression ended\" into an error past the end.\n */\n function parsesTo(source: string, budget: { left: number }): number {\n for (const text of [source, `${source} ]`]) {\n // Out of parses: no answer, which ends the search.\n if (budget.left-- <= 0) return -1\n try {\n parse(text, parseLimits)\n if (text === source) return Number.POSITIVE_INFINITY\n } catch (error) {\n if (!(error instanceof BonsaiError)) throw error\n if (!(error instanceof BonsaiSyntaxError) || error.span === undefined) return -1\n if (text !== source) return Math.min(error.span.start, source.length)\n }\n }\n return -1\n }\n\n /**\n * An ending for nested open constructs no single ending covers, such as\n * `let v = try(o1.`: at each closer, innermost first, and after the last,\n * the fillers the parser gets through (a few at most), within the parses\n * `budget` has left.\n */\n function builtEnding(\n text: string,\n closers: string,\n budget: { left: number },\n ): string | undefined {\n let built = text\n for (let gap = 0; gap <= closers.length; gap++) {\n const rest = closers.slice(gap)\n for (let round = 0; round < MAX_FILLERS; round++) {\n const reached = parsesTo(built + rest, budget)\n // A mistake before the probe is one no ending can mend.\n if (reached < text.length) return undefined\n if (reached === Number.POSITIVE_INFINITY) return built + rest\n // The parser got past this closer: what is missing is further out.\n if (reached > built.length) break\n let filler: string | undefined\n for (const f of FILLERS) {\n if (budget.left <= 0) return undefined\n if (parsesTo(built + f + rest, budget) >= built.length + f.length) {\n filler = f\n break\n }\n }\n if (filler === undefined) return undefined\n built += filler\n }\n if (gap < closers.length) built += closers[gap]\n }\n return undefined\n }\n\n function complete(source: string, offset: number): CompletionResult {\n const cursor = clampOffset(source, offset)\n let from = cursor\n while (from > 0 && IDENT_CHAR.test(source[from - 1])) from--\n let to = cursor\n while (to < source.length && IDENT_CHAR.test(source[to])) to++\n const typed = source.slice(from, cursor)\n const empty: CompletionResult = { start: from, end: to, items: [] }\n\n const prefix = source.slice(0, from)\n const scan = scanOpen(prefix)\n // Inside a string after == or != (user.plan == \"p|), in a list after `in`\n // (user.plan in [\"pro\", \"f|), or as a call argument (roles.includes(\"a|),\n // xs.sortBy(.k, \"d|)): offer the values the other side allows.\n const quoted =\n /(?:==|!=|[(,]|\\bin\\s*\\[(?:\\s*(?:\"[^\"\\\\]*\"|'[^'\\\\]*')\\s*,)*)\\s*(?<quote>[\"'])(?<typed>[^\"'\\\\]*)$/u.exec(\n source.slice(0, cursor),\n )\n if (quoted !== null && scan.inString) {\n const enumPrefix = quoted.groups?.typed ?? ''\n const quoteAt = cursor - enumPrefix.length\n const outer = source.slice(0, quoteAt - 1)\n const outerScan = scanOpen(outer)\n const analysis = tryAnalyze(`${outer}${PROBE}${outerScan.closers}`, PROBE)\n const values =\n analysis === undefined ? [] : literalValues(analysis).filter((v) => typeof v === 'string')\n const items = values.map((v) => ({\n label: v,\n kind: 'value' as const,\n detail: 'value',\n insertText: v,\n }))\n let end = cursor\n while (end < source.length && source[end] !== quoted.groups?.quote) end++\n return { start: quoteAt, end, items: rank(items, enumPrefix) }\n }\n if (scan.inString || scan.inComment) return empty\n if (from > 0 && /[0-9]/u.test(source[from - 1])) return empty\n\n // Whitespace and comments may sit between a `.` and the cursor.\n const before = withoutTrailingTrivia(prefix)\n const afterDot = before.endsWith('?.') || (before.endsWith('.') && !before.endsWith('...'))\n const probeText = afterDot ? `${before}${PROBE}` : `${prefix}${PROBE}`\n\n // Every parse below counts against one budget, so a completion costs at\n // most a fixed number of parses however the source nests, and at most a\n // few parses' worth of text when the source is long.\n const budget = {\n left: Math.min(\n MAX_COMPLETION_PARSES,\n Math.max(MIN_COMPLETION_PARSES, Math.floor(MAX_COMPLETION_CHARS / probeText.length)),\n ),\n }\n let analysis: Analysis | undefined\n for (const suffix of probeSuffixes(scan.closers)) {\n if (budget.left-- <= 0) break\n analysis = tryAnalyze(probeText + suffix, PROBE)\n if (analysis !== undefined) break\n }\n // The last parse is kept for analyzing the ending found.\n budget.left--\n if (analysis === undefined && budget.left > 0) {\n const ended = builtEnding(probeText, scan.closers, budget)\n if (ended !== undefined) analysis = tryAnalyze(ended, PROBE)\n }\n if (analysis === undefined) return empty\n\n const dotAt = afterDot && !before.endsWith('?.') ? before.length - 1 : undefined\n const items = afterDot\n ? memberCompletions(analysis, dotAt === undefined ? undefined : { start: dotAt, end: to })\n : nameCompletions(analysis)\n if (!afterDot && /(?:==|!=)\\s*$/u.test(prefix)) {\n for (const value of literalValues(analysis)) {\n items.unshift({\n label: JSON.stringify(value),\n kind: 'value',\n detail: 'value',\n insertText: JSON.stringify(value),\n })\n }\n }\n return { start: from, end: to, items: rank(items, typed) }\n }\n\n /** Literal members of the type on the other side of `== probe` or `in [..., probe]`. */\n function literalValues(analysis: Analysis): (string | number | boolean)[] {\n let other: Type | undefined\n const isProbe = (node: Node): boolean => node.type === 'Variable' && node.name === PROBE\n const find = (node: Node): void => {\n if (other !== undefined) return\n if (node.type === 'Binary' && (node.operator === '==' || node.operator === '!=')) {\n if (isProbe(node.right)) other = analysis.types.get(node.left)\n else if (isProbe(node.left)) other = analysis.types.get(node.right)\n if (other !== undefined) return\n }\n if (\n node.type === 'Binary' &&\n (node.operator === 'in' || node.operator === 'not in') &&\n node.right.type === 'List' &&\n node.right.items.some((item) => item.type !== 'Spread' && isProbe(item))\n ) {\n other = analysis.types.get(node.left)\n if (other !== undefined) return\n }\n if (node.type === 'Call') {\n const index = node.args.findIndex((arg) => arg.type !== 'Spread' && isProbe(arg))\n if (index > 0) {\n const receiver = node.args[0]\n if (node.name === 'includes' && index === 1 && receiver.type !== 'Spread') {\n // roles.includes(\"a\"): the list's element type.\n const list = analysis.types.get(receiver)\n const listType = list === undefined ? undefined : nonNull(list)\n if (listType?.kind === 'list') other = listType.element\n } else {\n // A parameter declared as literals (sortBy's \"asc\" | \"desc\").\n const plan = analysis.calls.get(node)\n const overload = plan?.def.overloads[plan.candidates[0] ?? 0]\n const param = overload?.params[index] ?? overload?.rest\n if (param !== undefined && unionMembers(param).every((m) => m.kind === 'literal'))\n other = param\n }\n if (other !== undefined) return\n }\n }\n forEachChild(node, find)\n }\n find(analysis.root)\n if (other === undefined) return []\n return unionMembers(other).flatMap((member) =>\n member.kind === 'literal' ? [member.value] : [],\n )\n }\n\n /** Completions after `receiver.`; `dot` is the range of the `.` and the typed name. */\n function memberCompletions(\n analysis: Analysis,\n dot: { start: number; end: number } | undefined,\n ): Completion[] {\n let receiver: Type | undefined\n // `.name` directly after an implicit-lambda `.` (xs.map(.name)).\n let onItem = false\n const find = (node: Node): void => {\n if (receiver !== undefined) return\n if (node.type === 'Member' && node.name === PROBE) {\n receiver = analysis.types.get(node.object)\n onItem = node.object.type === 'It'\n return\n }\n forEachChild(node, find)\n }\n find(analysis.root)\n if (receiver === undefined) return []\n const target = nonNull(receiver)\n const items: Completion[] = []\n const members = unionMembers(target)\n // Fields of every map member (a union of records offers each one's keys).\n const maps = members.filter((member): member is MapType => member.kind === 'map')\n const names = new Set(maps.flatMap((member) => Object.keys(member.fields)))\n // The type a read has, as check() and hover report it: a member without\n // the field reads its `rest` (or null), and a declared object may hold any key.\n const readOf = (member: MapType, name: string): Type => {\n const field = fieldOf(member, name)\n if (field !== undefined) return field\n if (member.rest !== undefined) return t.optional(member.rest)\n return isExact(member) ? t.null() : t.any()\n }\n for (const name of names) {\n const detail = formatType(\n analysis.probeMembers?.get(name) ?? unionOf(maps.map((member) => readOf(member, name))),\n )\n if (IDENTIFIER.test(name)) {\n items.push({ label: name, kind: 'property', detail, insertText: name })\n } else {\n // `user.first-name` would subtract: index it instead. The item's own\n // `.` stays: xs.map(.[\"first-name\"]).\n items.push({\n label: name,\n kind: 'property',\n detail,\n insertText: `${onItem ? '.' : ''}[${JSON.stringify(name)}]`,\n ...(dot === undefined ? {} : { range: dot }),\n })\n }\n }\n if (\n members.some(\n (member) =>\n member.kind === 'list' ||\n member.kind === 'string' ||\n (member.kind === 'literal' && typeof member.value === 'string'),\n )\n ) {\n items.push({ label: 'length', kind: 'property', detail: 'number', insertText: 'length' })\n }\n // Functions whose first parameter accepts the receiver can be called as\n // methods; for a union, every member must be accepted by some signature.\n const receivers = unionMembers(widen(target))\n for (const name of checkEnv.functionNames()) {\n const def = checkEnv.lookup(name) as FunctionDef\n const firstOf = (o: (typeof def.overloads)[number]): Type | undefined => {\n const first = o.params[0] ?? o.rest\n return first === undefined || first.kind === 'function' ? undefined : first\n }\n const accepts = (o: (typeof def.overloads)[number], member: Type): boolean => {\n const first = firstOf(o)\n return first !== undefined && (member.kind === 'any' || acceptsArgument(first, member))\n }\n const applicable = def.overloads.filter((o) => receivers.some((member) => accepts(o, member)))\n if (\n applicable.length === 0 ||\n !receivers.every((member) => applicable.some((o) => accepts(o, member)))\n )\n continue\n items.push({\n label: name,\n kind: 'method',\n detail: applicable.map((o) => signatureText(name, o)).join('\\n'),\n documentation: descriptionOf(def),\n insertText: `${name}(${takesMore(def) ? '' : ')'}`,\n })\n }\n return items\n }\n\n function nameCompletions(analysis: Analysis): Completion[] {\n const items: Completion[] = []\n const scope = analysis.probeScope\n if (scope?.it !== undefined) {\n items.push({\n label: '.',\n kind: 'local',\n detail: formatType(scope.it),\n documentation: 'The current item',\n insertText: '.',\n })\n }\n for (const [name, type] of scope?.locals ?? []) {\n items.push({ label: name, kind: 'local', detail: formatType(type), insertText: name })\n }\n for (const [name, type] of Object.entries(checkEnv.variables ?? {})) {\n items.push({ label: name, kind: 'variable', detail: formatType(type), insertText: name })\n }\n for (const name of checkEnv.functionNames()) {\n const def = checkEnv.lookup(name) as FunctionDef\n items.push({\n label: name,\n kind: 'function',\n detail: def.overloads.map((o) => signatureText(name, o)).join('\\n'),\n documentation: descriptionOf(def),\n insertText: `${name}(`,\n })\n }\n for (const keyword of KEYWORDS) {\n items.push({\n label: keyword,\n kind: 'keyword',\n detail: 'keyword',\n insertText: keyword === 'has' || keyword === 'try' ? `${keyword}(` : keyword,\n })\n }\n return items\n }\n\n function hover(source: string, rawOffset: number): HoverResult | undefined {\n const offset = clampOffset(source, rawOffset)\n const analysis = tryAnalyze(source)\n if (analysis === undefined) return undefined\n let best: Node | undefined\n const visit = (node: Node): void => {\n if (offset < node.start || offset > node.end) return\n // The implicit item's `.` ends where the name after it starts (`.cat`):\n // an offset on that name belongs to the member, not the item.\n if (node.type === 'It' && offset === node.end && best?.type === 'Member') return\n best = node\n forEachChild(node, visit)\n }\n visit(analysis.root)\n if (best === undefined) return undefined\n const node: Node = best\n if (\n node.type === 'Call' &&\n node.nameStart !== undefined &&\n node.nameEnd !== undefined &&\n offset >= node.nameStart &&\n offset <= node.nameEnd\n ) {\n const def = checkEnv.lookup(node.name)\n if (def !== undefined) {\n return {\n start: node.nameStart,\n end: node.nameEnd,\n detail: def.overloads.map((o) => signatureText(def.name, o)).join('\\n'),\n documentation: descriptionOf(def),\n }\n }\n }\n const type = analysis.types.get(node)\n if (type === undefined) return undefined\n return {\n start: node.start,\n end: node.end,\n detail: formatType(type.kind === 'literal' ? widen(type) : type),\n }\n }\n\n function diagnostics(source: string): readonly Diagnostic[] {\n // Spans stay inside the source (an error at the end is zero-width there).\n const found = env.check(source, checkOptions).diagnostics\n if (found.every((d) => d.start >= 0 && d.end >= d.start && d.end <= source.length)) return found\n return locate(\n source,\n found.map((d) => {\n const start = Math.min(Math.max(d.start, 0), source.length)\n return { ...d, start, end: Math.min(Math.max(d.end, start), source.length) }\n }),\n )\n }\n\n return Object.freeze({ complete, hover, diagnostics })\n}\n\nfunction takesMore(def: FunctionDef): boolean {\n return def.overloads.some((o) => o.params.length > 1 || o.rest !== undefined)\n}\n\nfunction rank(items: readonly Completion[], typed: string): Completion[] {\n const needle = typed.toLowerCase()\n const scored = items\n .map((item) => {\n const label = item.label.toLowerCase()\n let score = 0\n if (needle === '') score = 1\n else if (label.startsWith(needle)) score = 2\n else if (label.includes(needle)) score = 1\n return { item, score }\n })\n .filter((entry) => entry.score > 0)\n const order: Record<CompletionKind, number> = {\n value: -1,\n local: 0,\n property: 1,\n variable: 2,\n method: 3,\n function: 4,\n keyword: 5,\n }\n scored.sort(\n (a, b) =>\n b.score - a.score ||\n order[a.item.kind] - order[b.item.kind] ||\n a.item.label.localeCompare(b.item.label),\n )\n const seen = new Set<string>()\n return scored\n .map((entry) => entry.item)\n .filter((item) => !seen.has(item.label) && (seen.add(item.label), true))\n}\n\n/** `text` without the whitespace and comments at its end. */\nfunction withoutTrailingTrivia(text: string): string {\n const startOf = new Map(commentSpans(text).map((span) => [span.end, span.start]))\n let end = text.length\n for (;;) {\n while (end > 0 && /\\s/u.test(text[end - 1])) end--\n const start = startOf.get(end)\n if (start === undefined) break\n end = start\n }\n return text.slice(0, end)\n}\n\n/** The comments in `text` (outside strings and templates), as [start, end) spans. */\nfunction commentSpans(text: string): { start: number; end: number }[] {\n const spans: { start: number; end: number }[] = []\n let i = 0\n let template = 0\n while (i < text.length) {\n const ch = text[i]\n if (template > 0 && ch === '`') {\n template--\n i++\n } else if (template > 0) {\n i += ch === '\\\\' ? 2 : 1\n } else if (ch === '`') {\n template++\n i++\n } else if (ch === '/' && text[i + 1] === '/') {\n let end = text.indexOf('\\n', i)\n if (end === -1) end = text.length\n spans.push({ start: i, end })\n i = end\n } else if (ch === '/' && text[i + 1] === '*') {\n const close = text.indexOf('*/', i + 2)\n const end = close === -1 ? text.length : close + 2\n spans.push({ start: i, end })\n i = end\n } else if (ch === '\"' || ch === \"'\") {\n let j = i + 1\n while (j < text.length && text[j] !== ch) j += text[j] === '\\\\' ? 2 : 1\n i = j + 1\n } else i++\n }\n return spans\n}\n\n/** Open constructs a filler is tried inside of, innermost first. */\nconst PROBE_SPLITS = 4\n\n/** What a nested ending may add at one closer: a missing branch, argument, value, or body. */\nconst FILLERS = [' : null', ', null', ': null', '; null', ' 0']\n/** Fillers one closer may take, as in try(b ? x : null, null). */\nconst MAX_FILLERS = 3\n/**\n * Parses one completion may cost in all (fixed endings, nested ending search,\n * and its analysis): enough for every ending a short source needs.\n */\nconst MAX_COMPLETION_PARSES = 100\n/**\n * Characters one completion may parse in all, so a long source gets fewer\n * tries (each costs a parse of the whole source), but never fewer than\n * {@link MIN_COMPLETION_PARSES}.\n */\nconst MAX_COMPLETION_CHARS = 1_200_000\n/** Enough for the fixed endings a single open construct needs, plus the analysis. */\nconst MIN_COMPLETION_PARSES = 12\n\n/**\n * Endings that make a prefix ending in the probe parse, cheapest first: the\n * closers alone, a missing branch or value inside them, the missing half of\n * an enclosing try(x, fallback) or computed key [k]: v, and a `let` body or\n * `?:` branch after them.\n */\nfunction probeSuffixes(closers: string): string[] {\n const out = [\n closers,\n ` : null${closers}`,\n `; null${closers}`,\n ` 0${closers}`,\n `, null${closers}`,\n `${closers}; null`,\n `${closers} : null`,\n `${closers} : null; null`,\n ]\n for (let at = 1; at <= Math.min(closers.length, PROBE_SPLITS); at++) {\n const inner = closers.slice(0, at)\n const outer = closers.slice(at)\n out.push(`${inner}: null${outer}`, `${inner}, null${outer}`)\n }\n return [...new Set(out)]\n}\n\n/** Tracks open brackets, strings, and templates in a prefix to synthesize closers. */\nfunction scanOpen(text: string): { closers: string; inString: boolean; inComment: boolean } {\n const stack: string[] = []\n let i = 0\n while (i < text.length) {\n const ch = text[i]\n const top = stack[stack.length - 1]\n if (top === '`') {\n if (ch === '\\\\') i += 2\n else if (ch === '`') {\n stack.pop()\n i++\n } else if (ch === '$' && text[i + 1] === '{') {\n stack.push('${')\n i += 2\n } else i++\n continue\n }\n if (ch === '/' && text[i + 1] === '/') {\n const end = text.indexOf('\\n', i)\n if (end === -1) return { closers: '', inString: false, inComment: true }\n i = end\n continue\n }\n if (ch === '/' && text[i + 1] === '*') {\n const end = text.indexOf('*/', i + 2)\n if (end === -1) return { closers: '', inString: false, inComment: true }\n i = end + 2\n continue\n }\n if (ch === '\"' || ch === \"'\") {\n let j = i + 1\n while (j < text.length && text[j] !== ch) j += text[j] === '\\\\' ? 2 : 1\n if (j >= text.length) return { closers: '', inString: true, inComment: false }\n i = j + 1\n continue\n }\n if (ch === '`') stack.push('`')\n else if (ch === '(' || ch === '[' || ch === '{') stack.push(ch)\n else if (ch === ')' || ch === ']' || ch === '}') {\n if (top === '${' && ch === '}') stack.pop()\n else if (top === '(' || top === '[' || top === '{') stack.pop()\n }\n i++\n }\n if (stack[stack.length - 1] === '`') return { closers: '', inString: true, inComment: false }\n const closers = stack\n .reverse()\n .map((open) => CLOSER[open] ?? '`')\n .join('')\n return { closers, inString: false, inComment: false }\n}\n"],"mappings":"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"}
|
package/dist/version.mjs
CHANGED
package/dist/version.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.mjs","names":[],"sources":["../src/version.ts"],"sourcesContent":["/** This package's version, recorded in artifacts. A test keeps it equal to package.json. */\nexport const VERSION = '1.
|
|
1
|
+
{"version":3,"file":"version.mjs","names":[],"sources":["../src/version.ts"],"sourcesContent":["/** This package's version, recorded in artifacts. A test keeps it equal to package.json. */\nexport const VERSION = '1.2.0'\n"],"mappings":";;AACA,MAAa,UAAU"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bonsai-js",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A safe, zero-dependency expression language for rules, filters, and templates",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -19,6 +19,12 @@
|
|
|
19
19
|
],
|
|
20
20
|
"runtime": [
|
|
21
21
|
"./dist/runtime/index.d.mts"
|
|
22
|
+
],
|
|
23
|
+
"runtime/core": [
|
|
24
|
+
"./dist/runtime/core.d.mts"
|
|
25
|
+
],
|
|
26
|
+
"builtins": [
|
|
27
|
+
"./dist/builtins/index.d.mts"
|
|
22
28
|
]
|
|
23
29
|
}
|
|
24
30
|
},
|
|
@@ -47,6 +53,16 @@
|
|
|
47
53
|
"types": "./dist/runtime/index.d.mts",
|
|
48
54
|
"import": "./dist/runtime/index.mjs",
|
|
49
55
|
"default": "./dist/runtime/index.mjs"
|
|
56
|
+
},
|
|
57
|
+
"./runtime/core": {
|
|
58
|
+
"types": "./dist/runtime/core.d.mts",
|
|
59
|
+
"import": "./dist/runtime/core.mjs",
|
|
60
|
+
"default": "./dist/runtime/core.mjs"
|
|
61
|
+
},
|
|
62
|
+
"./builtins": {
|
|
63
|
+
"types": "./dist/builtins/index.d.mts",
|
|
64
|
+
"import": "./dist/builtins/index.mjs",
|
|
65
|
+
"default": "./dist/builtins/index.mjs"
|
|
50
66
|
}
|
|
51
67
|
},
|
|
52
68
|
"files": [
|