typewright 0.2.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.
Files changed (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +168 -0
  3. package/SPEC.md +327 -0
  4. package/dist/chunk-CZQO7TTL.js +1533 -0
  5. package/dist/chunk-CZQO7TTL.js.map +1 -0
  6. package/dist/chunk-KNEKNZXK.js +286 -0
  7. package/dist/chunk-KNEKNZXK.js.map +1 -0
  8. package/dist/chunk-M6IVEMXO.js +1398 -0
  9. package/dist/chunk-M6IVEMXO.js.map +1 -0
  10. package/dist/chunk-NJ7PJKHN.js +652 -0
  11. package/dist/chunk-NJ7PJKHN.js.map +1 -0
  12. package/dist/commands-Z3ndUSza.d.cts +221 -0
  13. package/dist/commands-Z3ndUSza.d.ts +221 -0
  14. package/dist/core/index.cjs +2952 -0
  15. package/dist/core/index.cjs.map +1 -0
  16. package/dist/core/index.d.cts +410 -0
  17. package/dist/core/index.d.ts +410 -0
  18. package/dist/core/index.js +4 -0
  19. package/dist/core/index.js.map +1 -0
  20. package/dist/mdx/index.cjs +662 -0
  21. package/dist/mdx/index.cjs.map +1 -0
  22. package/dist/mdx/index.d.cts +252 -0
  23. package/dist/mdx/index.d.ts +252 -0
  24. package/dist/mdx/index.js +3 -0
  25. package/dist/mdx/index.js.map +1 -0
  26. package/dist/react/index.cjs +7439 -0
  27. package/dist/react/index.cjs.map +1 -0
  28. package/dist/react/index.d.cts +140 -0
  29. package/dist/react/index.d.ts +140 -0
  30. package/dist/react/index.js +3644 -0
  31. package/dist/react/index.js.map +1 -0
  32. package/dist/streaming/index.cjs +1494 -0
  33. package/dist/streaming/index.cjs.map +1 -0
  34. package/dist/streaming/index.d.cts +64 -0
  35. package/dist/streaming/index.d.ts +64 -0
  36. package/dist/streaming/index.js +4 -0
  37. package/dist/streaming/index.js.map +1 -0
  38. package/dist/types-CX1GOx0Y.d.cts +319 -0
  39. package/dist/types-CX1GOx0Y.d.ts +319 -0
  40. package/package.json +128 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/streaming/anticipate.ts","../src/streaming/index.ts"],"names":["committed","committedHtml"],"mappings":"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","file":"chunk-KNEKNZXK.js","sourcesContent":["/**\n * Anticipatory streaming renderer (SPEC.md §8).\n *\n * Given a PARTIAL Markdown string (as it arrives token-by-token from an LLM),\n * render the confirmed prefix richly via the real parser/renderer, and\n * optimistically resolve the trailing incomplete construct — an unterminated\n * `**bo` renders as in-progress bold, an open ``` opens a code block, a forming\n * `<Comp` shows a component skeleton — so the preview reads as finished prose\n * while it is still streaming. Confirmed content is never reflowed.\n *\n * Open-delimiter detection is PARITY based (an odd number of a delimiter on the\n * active line means the last one is unclosed) so a completed span is never\n * mistaken for an open one.\n */\n\nimport { parse } from '../core/parser';\nimport { renderToHtml, renderInline } from '../core/render';\nimport type { AnticipationOptions } from '../types';\n\nexport interface AnticipateResult {\n /** Sanitized HTML for the current partial (safe to inject — render.ts escapes). */\n html: string;\n /** Which constructs are currently being anticipated (e.g. ['strong']). */\n pending: string[];\n}\n\ntype Opt = Required<AnticipationOptions>;\n\nfunction normalizeOpt(o: AnticipationOptions | boolean): Opt {\n const all = (v: boolean): Opt => ({\n emphasis: v, strong: v, code: v, strikethrough: v, links: v,\n headings: v, fences: v, listItems: v, tables: v, jsx: v,\n });\n if (o === true || o === undefined) return all(true);\n if (o === false) return all(false);\n return { ...all(true), ...o };\n}\n\nfunction esc(s: string): string {\n // escapes text AND attribute values (the fence language class, component name),\n // so `\"`/`'` must be escaped too — this is a security boundary.\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n\n/** Inline HTML for a single line via the real renderer (no <p> wrapper). */\nfunction inlineHtml(text: string): string {\n const doc = parse(text);\n const first = doc.children[0];\n if (first && (first.type === 'paragraph' || first.type === 'heading')) {\n return renderInline(first.children);\n }\n return esc(text);\n}\n\nconst CARET = '<span class=\"tw-caret\" aria-hidden=\"true\"></span>';\n\ninterface OpenRun {\n kind: string;\n tag: string;\n cls: string;\n /** Offset of the opening delimiter within the line. */\n opener: number;\n /** Delimiter length. */\n dl: number;\n}\n\nfunction indexesOf(line: string, sub: string): number[] {\n const out: number[] = [];\n let i = line.indexOf(sub);\n while (i >= 0) {\n out.push(i);\n i = line.indexOf(sub, i + sub.length);\n }\n return out;\n}\n\n/**\n * Offset of the `[` opening a still-forming link on the line, or null.\n *\n * Forming = an unclosed `[text…` (no `]` yet) OR a `[text](url…` whose\n * destination is still open (no closing `)`). A completed `[text](url)` — or a\n * bare closed `[text]` not followed by `(` — is NOT forming, so a finished link\n * is never mistaken for an open one (the STABILITY RULE).\n */\nfunction findOpenLink(line: string): number | null {\n const bi = line.lastIndexOf('[');\n if (bi < 0) return null;\n const rest = line.slice(bi);\n if (!rest.includes(']')) return bi; // \"[text…\"\n if (/^\\[[^\\]]*\\]\\([^)]*$/.test(rest)) return bi; // \"[text](url…\"\n return null;\n}\n\n/**\n * Push the trailing lone-`ch` emphasis run when its parity is odd. The doubled\n * `strong` form (`**`/`__`) is masked with an EQUAL-LENGTH sentinel first, so\n * strong pairs never count as emphasis while the surviving delimiter offsets\n * still line up with the original line (a plain strip would shift them).\n */\nfunction pushEmphasis(line: string, ch: string, dbl: string, cands: OpenRun[]): void {\n const masked = line.split(dbl).join('\u0001\u0001');\n const idx: number[] = [];\n for (let i = 0; i < masked.length; i++) if (masked[i] === ch) idx.push(i);\n if (idx.length % 2 === 1) {\n cands.push({ kind: 'emphasis', tag: 'em', cls: 'tw-pending tw-pending-em', opener: idx[idx.length - 1]!, dl: 1 });\n }\n}\n\n/** Find the OUTERMOST unclosed inline delimiter on a line, or null. */\nfunction findOpenRun(line: string, opt: Opt): OpenRun | null {\n const cands: OpenRun[] = [];\n\n if (opt.strong) {\n const x = indexesOf(line, '**');\n if (x.length % 2 === 1) cands.push({ kind: 'strong', tag: 'strong', cls: 'tw-pending tw-pending-strong', opener: x[x.length - 1]!, dl: 2 });\n }\n if (opt.strikethrough) {\n const x = indexesOf(line, '~~');\n if (x.length % 2 === 1) cands.push({ kind: 'strikethrough', tag: 'del', cls: 'tw-pending tw-pending-del', opener: x[x.length - 1]!, dl: 2 });\n }\n if (opt.code) {\n // ignore ``` fence runs — those are code-block markers, not inline code\n const ticks: number[] = [];\n for (const m of line.matchAll(/`+/g)) {\n if (m[0].length >= 3) continue;\n for (let k = 0; k < m[0].length; k++) ticks.push(m.index + k);\n }\n if (ticks.length % 2 === 1) cands.push({ kind: 'code', tag: 'code', cls: 'tw-pending tw-pending-code', opener: ticks[ticks.length - 1]!, dl: 1 });\n }\n if (opt.links) {\n const li = findOpenLink(line);\n if (li !== null) cands.push({ kind: 'link', tag: 'a', cls: 'tw-pending tw-pending-link', opener: li, dl: 1 });\n }\n if (opt.emphasis) {\n // `*` and `_` emphasis in parallel (mask their `**`/`__` strong forms first)\n pushEmphasis(line, '*', '**', cands);\n pushEmphasis(line, '_', '__', cands);\n }\n\n if (!cands.length) return null;\n cands.sort((a, b) => a.opener - b.opener); // outermost first\n return cands[0]!;\n}\n\nfunction isFormingJsx(line: string, opt: Opt): boolean {\n return opt.jsx && /<[A-Z][A-Za-z0-9]*\\b[^>]*$/.test(line) && !/\\/?>\\s*$/.test(line);\n}\n\n/**\n * A line whose active tail is a forming list item — `- `, `* `, `+ ` or `1. `\n * followed by a space. The text may be empty while it is still being typed, so\n * only the marker+space is required. Rendered as an in-progress <li>.\n */\nconst LIST_ITEM_RE = /^( {0,3})([-+*]|\\d{1,9}[.)])[ \\t]+(.*)$/;\nfunction isFormingListItem(line: string, opt: Opt): boolean {\n return opt.listItems && LIST_ITEM_RE.test(line);\n}\n\n/** A `| a | b` line — a table row (header, delimiter and data all start `|`). */\nconst TABLE_ROW_RE = /^ {0,3}\\|/;\nfunction splitTableCells(row: string): string[] {\n let s = row.trim();\n if (s.startsWith('|')) s = s.slice(1);\n if (s.endsWith('|')) s = s.slice(0, -1);\n return s.split('|').map((c) => c.trim());\n}\n\nfunction hasTrailing(line: string, opt: Opt): boolean {\n if (!line.trim()) return false;\n return (\n isFormingJsx(line, opt) ||\n isFormingListItem(line, opt) ||\n findOpenRun(line, opt) !== null\n );\n}\n\n/** Render a line whose trailing construct is being anticipated. */\nfunction renderActiveLine(line: string, opt: Opt, pending: string[], fallback?: string): string {\n if (isFormingJsx(line, opt)) {\n const name = /<([A-Z][A-Za-z0-9]*)/.exec(line)?.[1] ?? 'Component';\n pending.push('jsx');\n const label = fallback ? esc(fallback) : `‹${esc(name)}› rendering…`;\n return `<div class=\"tw-skeleton\" data-component=\"${esc(name)}\"><span class=\"tw-skeleton-label\">${label}</span><div class=\"tw-skeleton-bar\"></div><div class=\"tw-skeleton-bar\" style=\"width:70%\"></div></div>`;\n }\n\n if (isFormingListItem(line, opt)) return renderActiveListItem(line, opt, pending);\n\n const heading = /^(#{1,6})\\s+(.*)$/.exec(line);\n const body = heading ? (heading[2] ?? '') : line;\n const inner = renderInlineWithOpen(body, opt, pending);\n if (heading) return `<h${heading[1]!.length}>${inner}${CARET}</h${heading[1]!.length}>`;\n return `<p>${inner}${CARET}</p>`;\n}\n\n/**\n * An in-progress list item as its OWN single-item list. Committed items above\n * render through the real parser (their own <ul>/<ol>) and are never touched,\n * so anticipation only ADDS the forming item ahead of confirmation.\n */\nfunction renderActiveListItem(line: string, opt: Opt, pending: string[]): string {\n const m = LIST_ITEM_RE.exec(line)!;\n const marker = m[2]!;\n const content = m[3] ?? '';\n pending.push('listItem');\n const inner = content ? renderInlineWithOpen(content, opt, pending) : '';\n const li = `<li class=\"tw-pending tw-pending-li\">${inner}${CARET}</li>`;\n if (/\\d/.test(marker)) {\n const n = parseInt(marker, 10);\n const startAttr = Number.isFinite(n) && n !== 1 ? ` start=\"${esc(String(n))}\"` : '';\n return `<ol${startAttr} class=\"tw-pending tw-pending-list\">${li}</ol>`;\n }\n return `<ul class=\"tw-pending tw-pending-list\">${li}</ul>`;\n}\n\nfunction renderInlineWithOpen(text: string, opt: Opt, pending: string[]): string {\n const open = findOpenRun(text, opt);\n if (!open) return inlineHtml(text);\n const prefix = text.slice(0, open.opener);\n pending.push(open.kind);\n if (open.kind === 'link') {\n // Show the resolved link TEXT (up to `]`); the href is withheld until the\n // URL finishes, so a partial/unsafe destination is never emitted.\n const after = text.slice(open.opener + 1);\n const close = after.indexOf(']');\n const label = close >= 0 ? after.slice(0, close) : after;\n return `${inlineHtml(prefix)}<a class=\"${open.cls}\">${inlineHtml(label)}</a>`;\n }\n const content = text.slice(open.opener + open.dl);\n const inner = open.kind === 'code' ? esc(content) : inlineHtml(content);\n return `${inlineHtml(prefix)}<${open.tag} class=\"${open.cls}\">${inner}</${open.tag}>`;\n}\n\nfunction renderOpenFence(block: string, pending: string[]): string {\n const nl = block.indexOf('\\n');\n const info = block.slice(3, nl < 0 ? block.length : nl).trim();\n const lang = info.split(/\\s+/)[0] ?? '';\n const code = nl < 0 ? '' : block.slice(nl + 1);\n pending.push('code');\n const langAttr = lang ? ` class=\"language-${esc(lang)}\"` : '';\n return `<pre class=\"tw-codeblock\"><code${langAttr}>${esc(code)}${CARET}</code></pre>`;\n}\n\n/** An in-progress table row appended under a committed header+delimiter table. */\nfunction renderActiveTableRow(row: string, pending: string[]): string {\n const cells = splitTableCells(row);\n pending.push('tableRow');\n let tds = '';\n for (let i = 0; i < cells.length; i++) {\n const caret = i === cells.length - 1 ? CARET : '';\n tds += `<td>${cells[i] ? inlineHtml(cells[i]!) : ''}${caret}</td>`;\n }\n return `<table class=\"tw-pending tw-pending-table\"><tbody><tr>${tds}</tr></tbody></table>`;\n}\n\nexport function anticipate(\n partial: string,\n options: AnticipationOptions | boolean = true,\n componentFallback?: string,\n): AnticipateResult {\n const opt = normalizeOpt(options);\n const pending: string[] = [];\n if (!partial) return { html: '', pending };\n\n // 1) open fenced code block — an odd number of ``` fences means the last is open\n const fenceCount = (partial.match(/^```/gm) ?? []).length;\n if (opt.fences && fenceCount % 2 === 1) {\n const idx = partial.lastIndexOf('```');\n const committed = partial.slice(0, idx).replace(/\\n+$/, '');\n const open = partial.slice(idx);\n const committedHtml = committed.trim() ? renderToHtml(parse(committed)) : '';\n return { html: committedHtml + renderOpenFence(open, pending), pending };\n }\n\n // 2) in-progress table row — a `| …` last line under a committed table\n // (header+delimiter, or a fuller table above). Uses the multi-line\n // committed/active split like the fence path, so the confirmed rows —\n // which do not change until the active row commits — are never reflowed.\n if (opt.tables) {\n const nl = partial.lastIndexOf('\\n');\n if (nl >= 0) {\n const row = partial.slice(nl + 1);\n if (TABLE_ROW_RE.test(row)) {\n const committed = partial.slice(0, nl);\n const doc = parse(committed);\n const last = doc.children[doc.children.length - 1];\n if (last && last.type === 'table') {\n return { html: renderToHtml(doc) + renderActiveTableRow(row, pending), pending };\n }\n }\n }\n }\n\n // 3) anticipate a trailing construct on the LAST line, if any\n const lastNl = partial.lastIndexOf('\\n');\n const active = lastNl >= 0 ? partial.slice(lastNl + 1) : partial;\n if (!hasTrailing(active, opt)) {\n // nothing to anticipate — render the whole thing as-is\n return { html: renderToHtml(parse(partial)), pending };\n }\n const committed = lastNl >= 0 ? partial.slice(0, lastNl) : '';\n const committedHtml = committed.trim() ? renderToHtml(parse(committed)) : '';\n return { html: committedHtml + renderActiveLine(active, opt, pending, componentFallback), pending };\n}\n","/**\n * `typewright/streaming` — feed an AI/LLM token stream into a preview.\n *\n * Text accumulation, stream piping, and smoothing are implemented:\n * `createStreamController` buffers the incoming stream and, when `smooth` is\n * set, drives a timer that reveals a steadily-growing prefix so bursty chunk\n * arrivals read as smooth typing. The anticipatory formatting renderer —\n * turning an incomplete `*bo` into in-progress bold, an unterminated fence into\n * an open code block, and partial JSX into a component skeleton (SPEC.md §8) —\n * lives in {@link anticipate} and is wired into the React `StreamingPreview`\n * component in `typewright`.\n */\n\nimport type { StreamController, StreamOptions } from '../types';\n\nexport type {\n StreamController,\n StreamOptions,\n AnticipationOptions,\n} from '../types';\n\nexport { anticipate } from './anticipate';\nexport type { AnticipateResult } from './anticipate';\n\n/** Default reveal rate when `smooth` is `true` (chars/second). */\nconst DEFAULT_CPS = 220;\n/** Reveal-timer cadence — ~30fps, so the cursor advances in small steady steps. */\nconst TICK_MS = 1000 / 30;\n\n/**\n * Create a controller that accumulates an incoming token stream and emits the\n * running text on every update.\n *\n * When {@link StreamOptions.smooth} is set the FULL buffer is retained (readable\n * via `.text`) but `onUpdate` receives only a steadily-revealed prefix: a timer\n * advances a reveal cursor at the target rate (`charsPerSecond`, or a default),\n * so bursty chunk arrivals read as smooth typing. `end()` reveals everything and\n * clears the timer; `reset()` clears it too — no timer or handle is ever leaked.\n *\n * @param onUpdate Called with the emitted text (revealed prefix when smoothing)\n * and whether the stream has ended.\n * @param options Anticipation / smoothing options (see SPEC.md §8).\n */\nexport function createStreamController(\n onUpdate: (text: string, complete: boolean) => void,\n options: StreamOptions = {},\n): StreamController {\n const smoothCfg =\n !options.smooth\n ? null\n : typeof options.smooth === 'object'\n ? options.smooth\n : { charsPerSecond: DEFAULT_CPS };\n const cps = smoothCfg && smoothCfg.charsPerSecond > 0 ? smoothCfg.charsPerSecond : DEFAULT_CPS;\n // Chars revealed per tick — deterministic (no wall-clock), so it is stable\n // under fake timers and averages to the requested rate.\n const perTick = Math.max(1, Math.round((cps * TICK_MS) / 1000));\n\n let text = '';\n let revealed = 0;\n let complete = false;\n let timer: ReturnType<typeof setInterval> | null = null;\n\n const emit = (): void => onUpdate(smoothCfg ? text.slice(0, revealed) : text, complete);\n\n const stopTimer = (): void => {\n if (timer !== null) {\n clearInterval(timer);\n timer = null;\n }\n };\n const tick = (): void => {\n revealed = Math.min(text.length, revealed + perTick);\n emit();\n if (revealed >= text.length) stopTimer();\n };\n const ensureTimer = (): void => {\n if (timer !== null || complete || revealed >= text.length) return;\n timer = setInterval(tick, TICK_MS);\n };\n\n return {\n push(chunk: string): void {\n if (complete) return;\n text += chunk;\n if (smoothCfg) ensureTimer();\n emit();\n },\n replace(full: string): void {\n text = full;\n complete = false;\n if (smoothCfg) {\n if (revealed > text.length) revealed = text.length;\n ensureTimer();\n }\n emit();\n },\n end(): void {\n complete = true;\n revealed = text.length; // flush everything on completion\n stopTimer();\n emit();\n },\n reset(): void {\n text = '';\n revealed = 0;\n complete = false;\n stopTimer();\n emit();\n },\n get text(): string {\n return text;\n },\n get complete(): boolean {\n return complete;\n },\n };\n}\n\n/**\n * Drive a controller from an async iterable or a `ReadableStream` of string\n * chunks, calling `end()` when the source is exhausted.\n *\n * @example\n * const controller = createStreamController(setText);\n * await pipeStream(llmResponse.textStream, controller);\n */\nexport async function pipeStream(\n source: AsyncIterable<string> | ReadableStream<string>,\n controller: StreamController,\n): Promise<void> {\n if (Symbol.asyncIterator in source) {\n for await (const chunk of source as AsyncIterable<string>) {\n controller.push(chunk);\n }\n } else {\n const reader = source.getReader();\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value != null) controller.push(value);\n }\n }\n controller.end();\n}\n"]}