satteri 0.1.0 → 0.1.3

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 (55) hide show
  1. package/README.md +298 -4
  2. package/dist/command-buffer.js +1 -14
  3. package/dist/compile.d.ts +14 -9
  4. package/dist/compile.js +44 -36
  5. package/dist/hast/hast-materializer.js +0 -1
  6. package/dist/hast/hast-reader.d.ts +1 -1
  7. package/dist/hast/hast-reader.js +1 -2
  8. package/dist/hast/hast-visitor.d.ts +15 -15
  9. package/dist/hast/hast-visitor.js +7 -12
  10. package/dist/hast-types.d.ts +1 -3
  11. package/dist/hast-types.js +0 -1
  12. package/dist/index.d.ts +2 -2
  13. package/dist/index.js +2 -3
  14. package/dist/lazy-props.js +0 -1
  15. package/dist/mdast/mdast-materializer.js +0 -1
  16. package/dist/mdast/mdast-reader.js +0 -4
  17. package/dist/mdast/mdast-visitor.d.ts +19 -14
  18. package/dist/mdast/mdast-visitor.js +24 -36
  19. package/dist/mdast-types.d.ts +1 -3
  20. package/dist/mdast-types.js +0 -1
  21. package/dist/mdx-types.d.ts +140 -0
  22. package/dist/mdx-types.js +7 -0
  23. package/dist/plugin.d.ts +4 -6
  24. package/dist/plugin.js +0 -7
  25. package/dist/types.d.ts +4 -6
  26. package/dist/types.js +0 -5
  27. package/index.d.ts +21 -4
  28. package/index.js +54 -53
  29. package/package.json +16 -14
  30. package/satteri_napi.wasi-browser.js +2 -0
  31. package/satteri_napi.wasi.cjs +1 -0
  32. package/dist/command-buffer.js.map +0 -1
  33. package/dist/compile.js.map +0 -1
  34. package/dist/data-map.d.ts +0 -10
  35. package/dist/data-map.js +0 -26
  36. package/dist/data-map.js.map +0 -1
  37. package/dist/hast/hast-materializer.js.map +0 -1
  38. package/dist/hast/hast-reader.js.map +0 -1
  39. package/dist/hast/hast-visitor.js.map +0 -1
  40. package/dist/hast-types.js.map +0 -1
  41. package/dist/index.js.map +0 -1
  42. package/dist/lazy-props.js.map +0 -1
  43. package/dist/mdast/mdast-materializer.js.map +0 -1
  44. package/dist/mdast/mdast-reader.js.map +0 -1
  45. package/dist/mdast/mdast-visitor.js.map +0 -1
  46. package/dist/mdast-types.js.map +0 -1
  47. package/dist/pipeline.d.ts +0 -29
  48. package/dist/pipeline.js +0 -87
  49. package/dist/pipeline.js.map +0 -1
  50. package/dist/plugin.js.map +0 -1
  51. package/dist/processor.d.ts +0 -33
  52. package/dist/processor.js +0 -49
  53. package/dist/processor.js.map +0 -1
  54. package/dist/types.js.map +0 -1
  55. package/satteri_napi.linux-x64-gnu.node +0 -0
@@ -82,12 +82,12 @@ class HastVisitorContextImpl {
82
82
  setProperty(node, key, value) {
83
83
  const id = nid(node);
84
84
  if (node.type === "element") {
85
- // Fast binary path no materialization, no JSON serialization
85
+ // Fast binary path, no materialization, no JSON serialization
86
86
  this.#commandBuffer.setProperty(id, key, value);
87
87
  return;
88
88
  }
89
89
  if (node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement") {
90
- // MDX JSX nodes use `attributes`, not `properties` keep replaceNode path
90
+ // MDX JSX nodes use `attributes`, not `properties`, keep replaceNode path
91
91
  const current = this.#pendingNodes.get(id) ?? node;
92
92
  const updated = { ...current };
93
93
  const attrs = [...(updated.attributes ?? [])];
@@ -104,7 +104,7 @@ class HastVisitorContextImpl {
104
104
  this.replaceNode(node, updated);
105
105
  return;
106
106
  }
107
- // Text-like nodes (text, comment, raw, expressions, esm) fast binary path.
107
+ // Text-like nodes (text, comment, raw, expressions, esm), fast binary path.
108
108
  // Rust handles "value" setProperty directly on these types.
109
109
  this.#commandBuffer.setProperty(id, key, value);
110
110
  }
@@ -144,7 +144,7 @@ export function resolveSubscriptions(plugin) {
144
144
  }
145
145
  }
146
146
  else {
147
- // Bare function empty filter matches all nodes of this type
147
+ // Bare function, empty filter matches all nodes of this type
148
148
  subs.push({ nodeType, tagFilter: [], visitFn: value });
149
149
  }
150
150
  }
@@ -201,7 +201,7 @@ function decodeProperties(view, buf, pos) {
201
201
  }
202
202
  /**
203
203
  * Walk-path element node: uses prototype getters instead of per-instance
204
- * Object.defineProperty. V8 optimises shared hidden classes far better
204
+ * Object.defineProperty. V8 optimises shared hidden classes far better,
205
205
  * this is ~16x faster for construction than the defineProperty approach.
206
206
  *
207
207
  * The buffer reference data is stored on private instance fields so the
@@ -279,7 +279,7 @@ function readElementFromBinary(view, buf, offset, nodeId, resolver) {
279
279
  const ids = [];
280
280
  for (let i = 0; i < childCount; i++)
281
281
  ids.push(view.getUint32(childIdsPos + i * 4, true));
282
- // Build node using class (prototype getters no per-instance defineProperty)
282
+ // Build node using class (prototype getters, no per-instance defineProperty)
283
283
  const node = new WalkElement();
284
284
  node.tagName = tagName;
285
285
  node._view = view;
@@ -385,11 +385,9 @@ function readMatchedNode(view, buf, offset, nodeId, nodeType, resolver) {
385
385
  nodeIdMap.set(node, nodeId);
386
386
  return node;
387
387
  }
388
- // ---------------------------------------------------------------------------
389
388
  // Shared helpers
390
- // ---------------------------------------------------------------------------
391
389
  /**
392
- * Lazy child materializer serializes the handle's buffer once when first
390
+ * Lazy child materializer, serializes the handle's buffer once when first
393
391
  * child is accessed, then materializes children from it via HastReader.
394
392
  */
395
393
  class LazyChildResolver {
@@ -501,9 +499,7 @@ function mergeAndReset(returnBuffer, ctx) {
501
499
  ctxCmdBuf.reset();
502
500
  return { merged, hasMutations: totalLen > 0 };
503
501
  }
504
- // ---------------------------------------------------------------------------
505
502
  // Handle-based visitor
506
- // ---------------------------------------------------------------------------
507
503
  /**
508
504
  * Walk a handle's arena in Rust, dispatch matched nodes to JS visitor functions,
509
505
  * and apply mutations back to the handle. No arena buffers cross NAPI.
@@ -534,4 +530,3 @@ function applyMutations(handle, returnBuffer, ctx) {
534
530
  applyCommandsToHandle(handle, merged);
535
531
  }
536
532
  }
537
- //# sourceMappingURL=hast-visitor.js.map
@@ -1,5 +1,3 @@
1
1
  export type { Root, Element, Text, Comment, Doctype, Properties, Nodes, RootContent, ElementContent, Data, Literal, Parent, } from "hast";
2
- export type { MdxJsxFlowElementHast, MdxJsxTextElementHast, MdxJsxAttribute, MdxJsxExpressionAttribute, MdxJsxAttributeValueExpression, } from "mdast-util-mdx-jsx";
3
- export type { MdxFlowExpressionHast, MdxTextExpressionHast } from "mdast-util-mdx-expression";
4
- export type { MdxjsEsmHast } from "mdast-util-mdxjs-esm";
2
+ export type { MdxJsxFlowElementHast, MdxJsxTextElementHast, MdxJsxAttribute, MdxJsxExpressionAttribute, MdxJsxAttributeValueExpression, MdxFlowExpressionHast, MdxTextExpressionHast, MdxjsEsmHast, } from "./mdx-types.js";
5
3
  export type { HastRaw } from "./types.js";
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=hast-types.js.map
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { compileMarkdownToHtml, compileMdxToJs } from "./compile.js";
2
- export type { CompileOptions, OptimizeStaticConfig } from "./compile.js";
1
+ export { markdownToHtml, mdxToJs, markdownToMdast, mdxToMdast, markdownToHast, mdxToHast, } from "./compile.js";
2
+ export type { CompileOptions, MdxCompileOptions, OptimizeStaticConfig } from "./compile.js";
3
3
  export { defineMdastPlugin, defineHastPlugin } from "./plugin.js";
4
4
  export type { MdastPluginDefinition, HastPluginDefinition } from "./plugin.js";
5
5
  export type { HastVisitorInstance, HastVisitorContext, HastFilteredVisitor, EstreeProgram, } from "./hast/hast-visitor.js";
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
- // Public API compile functions
2
- export { compileMarkdownToHtml, compileMdxToJs } from "./compile.js";
1
+ // Public API: compile functions
2
+ export { markdownToHtml, mdxToJs, markdownToMdast, mdxToMdast, markdownToHast, mdxToHast, } from "./compile.js";
3
3
  // Plugin definitions
4
4
  export { defineMdastPlugin, defineHastPlugin } from "./plugin.js";
5
- //# sourceMappingURL=index.js.map
@@ -48,4 +48,3 @@ export function lazyGroup(node, keys, resolve) {
48
48
  });
49
49
  }
50
50
  }
51
- //# sourceMappingURL=lazy-props.js.map
@@ -159,4 +159,3 @@ export function materializeNode(reader, nodeId) {
159
159
  export function materializeTree(reader) {
160
160
  return materializeNode(reader, 0);
161
161
  }
162
- //# sourceMappingURL=mdast-materializer.js.map
@@ -211,7 +211,6 @@ export class ArenaReader {
211
211
  const { typeDataOffset } = this.#header;
212
212
  return new Uint8Array(this.#view.buffer, this.#view.byteOffset + typeDataOffset + node.dataOffset, node.dataLen);
213
213
  }
214
- // ── Low-level helpers ──────────────────────────────────────────────────────
215
214
  /** Read a StringRef (offset: u32 LE, len: u32 LE) from type data. */
216
215
  readStringRef(typeData, byteOffset = 0) {
217
216
  const view = new DataView(typeData.buffer, typeData.byteOffset + byteOffset);
@@ -220,7 +219,6 @@ export class ArenaReader {
220
219
  len: view.getUint32(4, true),
221
220
  };
222
221
  }
223
- // ── Type-specific data accessors ───────────────────────────────────────────
224
222
  /** HeadingData: depth u8 @ 0. */
225
223
  getHeadingDepth(nodeId) {
226
224
  return this.getTypeData(nodeId)[0];
@@ -455,7 +453,6 @@ export class ArenaReader {
455
453
  const valueRef = this.readStringRef(data, 0);
456
454
  return this.getString(valueRef.offset, valueRef.len);
457
455
  }
458
- // ── Tree walking ──────────────────────────────────────────────────────────
459
456
  /**
460
457
  * Walk the tree depth-first. Return false from visitor to skip children.
461
458
  */
@@ -478,4 +475,3 @@ export class ArenaReader {
478
475
  this.walk((nodeId) => visitor(this.getNode(nodeId)), rootId);
479
476
  }
480
477
  }
481
- //# sourceMappingURL=mdast-reader.js.map
@@ -1,9 +1,9 @@
1
1
  import { CommandBuffer } from "../command-buffer.js";
2
2
  import type { MdastNode, Toml, MathNode, InlineMath } from "../types.js";
3
3
  import type { Blockquote, Break, Code, Definition, Delete, Emphasis, FootnoteDefinition, FootnoteReference, Heading, Html, Image, ImageReference, InlineCode, Link, LinkReference, List, ListItem, Paragraph, Root, Strong, Table, TableRow, TableCell, Text, ThematicBreak, Yaml } from "mdast";
4
- import type { MdxJsxFlowElement, MdxJsxTextElement } from "mdast-util-mdx-jsx";
5
- import type { MdxFlowExpression, MdxTextExpression } from "mdast-util-mdx-expression";
6
- import type { MdxjsEsm } from "mdast-util-mdxjs-esm";
4
+ import type { MdxJsxFlowElement, MdxJsxTextElement } from "../mdx-types.js";
5
+ import type { MdxFlowExpression, MdxTextExpression } from "../mdx-types.js";
6
+ import type { MdxjsEsm } from "../mdx-types.js";
7
7
  export interface MdastDiagnostic {
8
8
  message: string;
9
9
  nodeId?: number | undefined;
@@ -14,18 +14,23 @@ export declare class MdastVisitorContext {
14
14
  #private;
15
15
  readonly source: string;
16
16
  readonly filename: string;
17
- constructor(source: string, filename: string);
18
- removeNode(node: MdastNode): void;
19
- insertBefore(node: MdastNode, newNode: MdastNode): void;
20
- insertAfter(node: MdastNode, newNode: MdastNode): void;
21
- wrapNode(node: MdastNode, parentNode: MdastNode): void;
22
- prependChild(node: MdastNode, childNode: MdastNode): void;
23
- appendChild(node: MdastNode, childNode: MdastNode): void;
24
- replaceNode(node: MdastNode, newNode: MdastNode): void;
25
- setProperty(node: MdastNode, key: string, value: unknown): void;
17
+ constructor(handle: MdastHandle, source: string, filename: string);
18
+ removeNode(node: Readonly<MdastNode>): void;
19
+ insertBefore(node: Readonly<MdastNode>, newNode: MdastNode): void;
20
+ insertAfter(node: Readonly<MdastNode>, newNode: MdastNode): void;
21
+ wrapNode(node: Readonly<MdastNode>, parentNode: MdastNode): void;
22
+ prependChild(node: Readonly<MdastNode>, childNode: MdastNode): void;
23
+ appendChild(node: Readonly<MdastNode>, childNode: MdastNode): void;
24
+ replaceNode(node: Readonly<MdastNode>, newNode: MdastNode): void;
25
+ setProperty<N extends MdastNode, K extends keyof N & string>(node: Readonly<N>, key: K, value: N[K]): void;
26
+ /** Collect the concatenated text of all descendant text nodes (like mdast-util-to-string). */
27
+ textContent(node: Readonly<MdastNode>, options?: {
28
+ includeImageAlt?: boolean;
29
+ includeHtml?: boolean;
30
+ }): string;
26
31
  report({ message, node, severity, }: {
27
32
  message: string;
28
- node?: MdastNode;
33
+ node?: Readonly<MdastNode>;
29
34
  severity?: "error" | "warning" | "info";
30
35
  }): void;
31
36
  /** Get the binary command buffer for all mutations recorded via context methods. */
@@ -37,7 +42,7 @@ type MdastVisitorResult = MdastNode | {
37
42
  } | {
38
43
  rawHtml: string;
39
44
  } | undefined | null | void;
40
- type MdastVisitorFn<N extends MdastNode = MdastNode> = (node: N, context: MdastVisitorContext) => MdastVisitorResult | Promise<MdastVisitorResult>;
45
+ type MdastVisitorFn<N extends MdastNode = MdastNode> = (node: Readonly<N>, context: MdastVisitorContext) => MdastVisitorResult | Promise<MdastVisitorResult>;
41
46
  export interface MdastPluginInstance {
42
47
  root?: MdastVisitorFn<Root>;
43
48
  paragraph?: MdastVisitorFn<Paragraph>;
@@ -1,7 +1,7 @@
1
1
  import { materializeNode, TYPE_NAMES } from "./mdast-materializer.js";
2
2
  import { ArenaReader } from "./mdast-reader.js";
3
3
  import { CommandBuffer, classifyReturn } from "../command-buffer.js";
4
- import { walkMdastHandle, serializeMdastHandle, getNodeData as napiGetNodeData, setNodeData, } from "../../index.js";
4
+ import { walkMdastHandle, serializeMdastHandle, getNodeData as napiGetNodeData, mdastTextContentHandle, } from "../../index.js";
5
5
  const MutationType = {
6
6
  Replace: "replace",
7
7
  Remove: "remove",
@@ -56,9 +56,11 @@ function nid(node) {
56
56
  export class MdastVisitorContext {
57
57
  #commandBuffer = new CommandBuffer();
58
58
  #diagnostics = [];
59
+ #handle;
59
60
  source;
60
61
  filename;
61
- constructor(source, filename) {
62
+ constructor(handle, source, filename) {
63
+ this.#handle = handle;
62
64
  this.source = source;
63
65
  this.filename = filename;
64
66
  }
@@ -84,8 +86,17 @@ export class MdastVisitorContext {
84
86
  this.#commandBuffer.replace(nid(node), newNode);
85
87
  }
86
88
  setProperty(node, key, value) {
89
+ if (key === "data") {
90
+ // data is stored as JSON in the arena, serialize it for the command buffer
91
+ this.#commandBuffer.setProperty(nid(node), key, value != null ? JSON.stringify(value) : null);
92
+ return;
93
+ }
87
94
  this.#commandBuffer.setProperty(nid(node), key, value);
88
95
  }
96
+ /** Collect the concatenated text of all descendant text nodes (like mdast-util-to-string). */
97
+ textContent(node, options) {
98
+ return mdastTextContentHandle(this.#handle, nid(node), options);
99
+ }
89
100
  report({ message, node, severity = "error", }) {
90
101
  this.#diagnostics.push({
91
102
  message,
@@ -203,9 +214,9 @@ class MdastLazyChildResolver {
203
214
  * [node_data: u32+bytes][position: 6×u32 = 24B][child_count: u16][child_ids: N×u32][type-specific data]
204
215
  */
205
216
  const encoder = new TextEncoder();
206
- function readMdastMatchedNode(view, buf, dataOffset, nodeId, nodeType, dirtyData, resolver) {
217
+ function readMdastMatchedNode(view, buf, dataOffset, nodeId, nodeType, resolver) {
207
218
  let pos = dataOffset;
208
- // Node data (JSON bytes) always first
219
+ // Node data (JSON bytes), always first
209
220
  const dataJsonLen = ru32(view, pos);
210
221
  pos += 4;
211
222
  let initialData = null;
@@ -225,7 +236,7 @@ function readMdastMatchedNode(view, buf, dataOffset, nodeId, nodeType, dirtyData
225
236
  end: { offset: ru32(view, pos + 4), line: ru32(view, pos + 16), column: ru32(view, pos + 20) },
226
237
  };
227
238
  pos += 24;
228
- // Children read IDs, materialize lazily via resolver
239
+ // Children, read IDs, materialize lazily via resolver
229
240
  const childCount = ru16(view, pos);
230
241
  pos += 2;
231
242
  const childIds = [];
@@ -446,26 +457,9 @@ function readMdastMatchedNode(view, buf, dataOffset, nodeId, nodeType, dirtyData
446
457
  // strong(12), break(14), tableRow(22), tableCell(23), delete(24): no extra data
447
458
  }
448
459
  mdastNodeIdMap.set(node, nodeId);
449
- // Read inline node_data JSON from the end of the data section.
450
- // The Rust serializer always appends [json_len: u32][json_bytes...] at the end.
451
- // We need to find it by reading from dataEnd backwards.
452
- // Actually, we read it at `dataOffset + dataLen - (4 + jsonDataLen)` but we don't
453
- // know jsonDataLen yet. Instead, the data section ends with [len: u32][bytes...],
454
- // so we scan from the current end of type-specific data.
455
- // For simplicity, we'll handle this in the caller which knows the full data_len.
456
- // Set up data getter/setter that tracks dirty entries
457
- let currentData = initialData;
458
- Object.defineProperty(node, "data", {
459
- get() {
460
- return currentData;
461
- },
462
- set(value) {
463
- currentData = value;
464
- dirtyData.set(nodeId, value);
465
- },
466
- configurable: true,
467
- enumerable: true,
468
- });
460
+ if (initialData) {
461
+ node.data = initialData;
462
+ }
469
463
  return node;
470
464
  }
471
465
  /** Apply a sync visitor result to the return buffer.
@@ -497,9 +491,8 @@ function applyMdastVisitResult(result, nodeId, returnBuffer, originalNode) {
497
491
  * or Promise<MdastVisitResult> if any visitor is async.
498
492
  */
499
493
  export function visitMdastHandle(handle, plugin, subs, source, filename) {
500
- const context = new MdastVisitorContext(source, filename);
494
+ const context = new MdastVisitorContext(handle, source, filename);
501
495
  const returnBuffer = new CommandBuffer();
502
- const dirtyData = new Map();
503
496
  const resolver = new MdastLazyChildResolver(handle);
504
497
  const rustSubs = subs.map((s) => ({ nodeType: s.nodeType, tagFilter: [] }));
505
498
  const matchBuf = walkMdastHandle(handle, rustSubs);
@@ -512,7 +505,7 @@ export function visitMdastHandle(handle, plugin, subs, source, filename) {
512
505
  const subIndex = matchBuf[indexBase + 4];
513
506
  const dataOffset = ru32(matchView, indexBase + 6);
514
507
  const sub = subs[subIndex];
515
- const node = readMdastMatchedNode(matchView, matchBuf, dataOffset, nodeId, sub.nodeType, dirtyData, resolver);
508
+ const node = readMdastMatchedNode(matchView, matchBuf, dataOffset, nodeId, sub.nodeType, resolver);
516
509
  const result = sub.visitFn.call(plugin, node, context);
517
510
  if (result instanceof Promise) {
518
511
  deferred ??= [];
@@ -527,17 +520,12 @@ export function visitMdastHandle(handle, plugin, subs, source, filename) {
527
520
  for (const { nodeId, result, originalNode } of results) {
528
521
  applyMdastVisitResult(result, nodeId, returnBuffer, originalNode);
529
522
  }
530
- return finalizeMdastVisit(handle, context, returnBuffer, dirtyData);
523
+ return finalizeMdastVisit(handle, context, returnBuffer);
531
524
  });
532
525
  }
533
- return finalizeMdastVisit(handle, context, returnBuffer, dirtyData);
526
+ return finalizeMdastVisit(handle, context, returnBuffer);
534
527
  }
535
- function finalizeMdastVisit(handle, context, returnBuffer, dirtyData) {
536
- for (const [id, value] of dirtyData) {
537
- const json = value ? JSON.stringify(value) : "";
538
- setNodeData(handle, id, encoder.encode(json));
539
- }
528
+ function finalizeMdastVisit(handle, context, returnBuffer) {
540
529
  const { merged, hasMutations } = mergeAndReset(returnBuffer, context);
541
530
  return { commandBuffer: merged, diagnostics: context.getDiagnostics(), hasMutations };
542
531
  }
543
- //# sourceMappingURL=mdast-visitor.js.map
@@ -1,5 +1,3 @@
1
1
  export type { Root, Nodes, RootContent, Blockquote, Break, Code, Definition, Delete, Emphasis, FootnoteDefinition, FootnoteReference, Heading, Html, Image, ImageReference, InlineCode, Link, LinkReference, List, ListItem, Paragraph, Strong, Table, TableRow, TableCell, Text, ThematicBreak, Yaml, Data, Literal, Parent, } from "mdast";
2
- export type { MdxJsxFlowElement, MdxJsxTextElement, MdxJsxAttribute, MdxJsxExpressionAttribute, MdxJsxAttributeValueExpression, } from "mdast-util-mdx-jsx";
3
- export type { MdxFlowExpression, MdxTextExpression } from "mdast-util-mdx-expression";
4
- export type { MdxjsEsm } from "mdast-util-mdxjs-esm";
2
+ export type { MdxJsxFlowElement, MdxJsxTextElement, MdxJsxAttribute, MdxJsxExpressionAttribute, MdxJsxAttributeValueExpression, MdxFlowExpression, MdxTextExpression, MdxjsEsm, } from "./mdx-types.js";
5
3
  export type { Toml, MathNode, InlineMath } from "./types.js";
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=mdast-types.js.map
@@ -0,0 +1,140 @@
1
+ import type { Data as HastData, ElementContent, Literal as HastLiteral, Parent as HastParent } from "hast";
2
+ import type { BlockContent, Data as MdastData, DefinitionContent, Literal as MdastLiteral, Parent as MdastParent, PhrasingContent } from "mdast";
3
+ import type { Data, Node } from "unist";
4
+ export interface MdxJsxAttributeValueExpression extends Node {
5
+ type: "mdxJsxAttributeValueExpression";
6
+ value: string;
7
+ data?: MdxJsxAttributeValueExpressionData | undefined;
8
+ }
9
+ export interface MdxJsxAttributeValueExpressionData extends Data {
10
+ estree?: unknown;
11
+ }
12
+ export interface MdxJsxExpressionAttribute extends Node {
13
+ type: "mdxJsxExpressionAttribute";
14
+ value: string;
15
+ data?: MdxJsxExpressionAttributeData | undefined;
16
+ }
17
+ export interface MdxJsxExpressionAttributeData extends Data {
18
+ estree?: unknown;
19
+ }
20
+ export interface MdxJsxAttribute extends Node {
21
+ type: "mdxJsxAttribute";
22
+ name: string;
23
+ value?: MdxJsxAttributeValueExpression | string | null | undefined;
24
+ data?: MdxJsxAttributeData | undefined;
25
+ }
26
+ export interface MdxJsxAttributeData extends Data {
27
+ }
28
+ export interface MdxJsxFlowElement extends MdastParent {
29
+ type: "mdxJsxFlowElement";
30
+ name: string | null;
31
+ attributes: Array<MdxJsxAttribute | MdxJsxExpressionAttribute>;
32
+ children: Array<BlockContent | DefinitionContent>;
33
+ data?: MdxJsxFlowElementData | undefined;
34
+ }
35
+ export interface MdxJsxFlowElementData extends MdastData {
36
+ }
37
+ export interface MdxJsxTextElement extends MdastParent {
38
+ type: "mdxJsxTextElement";
39
+ name: string | null;
40
+ attributes: Array<MdxJsxAttribute | MdxJsxExpressionAttribute>;
41
+ children: PhrasingContent[];
42
+ data?: MdxJsxTextElementData | undefined;
43
+ }
44
+ export interface MdxJsxTextElementData extends MdastData {
45
+ }
46
+ export interface MdxJsxFlowElementHast extends HastParent {
47
+ type: "mdxJsxFlowElement";
48
+ name: string | null;
49
+ attributes: Array<MdxJsxAttribute | MdxJsxExpressionAttribute>;
50
+ children: ElementContent[];
51
+ data?: MdxJsxFlowElementHastData | undefined;
52
+ }
53
+ export interface MdxJsxFlowElementHastData extends HastData {
54
+ }
55
+ export interface MdxJsxTextElementHast extends HastParent {
56
+ type: "mdxJsxTextElement";
57
+ name: string | null;
58
+ attributes: Array<MdxJsxAttribute | MdxJsxExpressionAttribute>;
59
+ children: ElementContent[];
60
+ data?: MdxJsxTextElementHastData | undefined;
61
+ }
62
+ export interface MdxJsxTextElementHastData extends HastData {
63
+ }
64
+ export interface MdxFlowExpression extends MdastLiteral {
65
+ type: "mdxFlowExpression";
66
+ data?: MdxFlowExpressionData | undefined;
67
+ }
68
+ export interface MdxFlowExpressionData extends MdastData {
69
+ estree?: unknown;
70
+ }
71
+ export interface MdxTextExpression extends MdastLiteral {
72
+ type: "mdxTextExpression";
73
+ data?: MdxTextExpressionData | undefined;
74
+ }
75
+ export interface MdxTextExpressionData extends MdastData {
76
+ estree?: unknown;
77
+ }
78
+ export interface MdxFlowExpressionHast extends HastLiteral {
79
+ type: "mdxFlowExpression";
80
+ data?: MdxFlowExpressionHastData | undefined;
81
+ }
82
+ export interface MdxFlowExpressionHastData extends HastData {
83
+ estree?: unknown;
84
+ }
85
+ export interface MdxTextExpressionHast extends HastLiteral {
86
+ type: "mdxTextExpression";
87
+ data?: MdxTextExpressionHastData | undefined;
88
+ }
89
+ export interface MdxTextExpressionHastData extends HastData {
90
+ estree?: unknown;
91
+ }
92
+ export interface MdxjsEsm extends MdastLiteral {
93
+ type: "mdxjsEsm";
94
+ data?: MdxjsEsmData | undefined;
95
+ }
96
+ export interface MdxjsEsmData extends MdastData {
97
+ estree?: unknown;
98
+ }
99
+ export interface MdxjsEsmHast extends HastLiteral {
100
+ type: "mdxjsEsm";
101
+ data?: MdxjsEsmHastData | undefined;
102
+ }
103
+ export interface MdxjsEsmHastData extends HastData {
104
+ estree?: unknown;
105
+ }
106
+ declare module "mdast" {
107
+ interface BlockContentMap {
108
+ mdxJsxFlowElement: MdxJsxFlowElement;
109
+ mdxFlowExpression: MdxFlowExpression;
110
+ }
111
+ interface PhrasingContentMap {
112
+ mdxJsxTextElement: MdxJsxTextElement;
113
+ mdxTextExpression: MdxTextExpression;
114
+ }
115
+ interface RootContentMap {
116
+ mdxJsxFlowElement: MdxJsxFlowElement;
117
+ mdxJsxTextElement: MdxJsxTextElement;
118
+ mdxTextExpression: MdxTextExpression;
119
+ mdxFlowExpression: MdxFlowExpression;
120
+ mdxjsEsm: MdxjsEsm;
121
+ }
122
+ interface FrontmatterContentMap {
123
+ mdxjsEsm: MdxjsEsm;
124
+ }
125
+ }
126
+ declare module "hast" {
127
+ interface ElementContentMap {
128
+ mdxJsxTextElement: MdxJsxTextElementHast;
129
+ mdxJsxFlowElement: MdxJsxFlowElementHast;
130
+ mdxFlowExpression: MdxFlowExpressionHast;
131
+ mdxTextExpression: MdxTextExpressionHast;
132
+ }
133
+ interface RootContentMap {
134
+ mdxJsxTextElement: MdxJsxTextElementHast;
135
+ mdxJsxFlowElement: MdxJsxFlowElementHast;
136
+ mdxFlowExpression: MdxFlowExpressionHast;
137
+ mdxTextExpression: MdxTextExpressionHast;
138
+ mdxjsEsm: MdxjsEsmHast;
139
+ }
140
+ }
@@ -0,0 +1,7 @@
1
+ // Manually-defined MDX AST node types.
2
+ //
3
+ // These replicate the type definitions from mdast-util-mdx-jsx,
4
+ // mdast-util-mdx-expression, and mdast-util-mdxjs-esm so we can avoid
5
+ // pulling in those packages (and their massive transitive dependency trees)
6
+ // just for a handful of interfaces.
7
+ export {};
package/dist/plugin.d.ts CHANGED
@@ -1,12 +1,10 @@
1
1
  import type { MdastPluginInstance } from "./mdast/mdast-visitor.js";
2
2
  import type { HastVisitorInstance } from "./hast/hast-visitor.js";
3
- export interface MdastPluginDefinition {
3
+ export type MdastPluginDefinition = MdastPluginInstance & {
4
4
  name: string;
5
- createOnce(): MdastPluginInstance;
6
- }
7
- export interface HastPluginDefinition {
5
+ };
6
+ export type HastPluginDefinition = HastVisitorInstance & {
8
7
  name: string;
9
- createOnce(): HastVisitorInstance;
10
- }
8
+ };
11
9
  export declare function defineMdastPlugin(definition: MdastPluginDefinition): MdastPluginDefinition;
12
10
  export declare function defineHastPlugin(definition: HastPluginDefinition): HastPluginDefinition;
package/dist/plugin.js CHANGED
@@ -2,18 +2,11 @@ export function defineMdastPlugin(definition) {
2
2
  if (!definition.name) {
3
3
  throw new Error("Plugin definition must have a name");
4
4
  }
5
- if (typeof definition.createOnce !== "function") {
6
- throw new Error("Plugin definition must have a createOnce function");
7
- }
8
5
  return definition;
9
6
  }
10
7
  export function defineHastPlugin(definition) {
11
8
  if (!definition.name) {
12
9
  throw new Error("Plugin definition must have a name");
13
10
  }
14
- if (typeof definition.createOnce !== "function") {
15
- throw new Error("Plugin definition must have a createOnce function");
16
- }
17
11
  return definition;
18
12
  }
19
- //# sourceMappingURL=plugin.js.map
package/dist/types.d.ts CHANGED
@@ -2,10 +2,8 @@ import type { Position } from "unist";
2
2
  import type { Literal as MdastLiteral, Nodes as MdastStdNodes } from "mdast";
3
3
  import type { Nodes as HastStdNodes } from "hast";
4
4
  export type { Position, Point } from "unist";
5
- export type { MdxJsxFlowElement, MdxJsxTextElement, MdxJsxAttribute as MdxJsxAttributeNode, MdxJsxExpressionAttribute as MdxJsxExpressionAttributeNode, MdxJsxAttributeValueExpression as MdxJsxAttributeValueExpressionNode, } from "mdast-util-mdx-jsx";
6
- export type { MdxFlowExpression, MdxTextExpression } from "mdast-util-mdx-expression";
7
- export type { MdxjsEsm } from "mdast-util-mdxjs-esm";
8
- import type { MdxJsxAttribute, MdxJsxExpressionAttribute } from "mdast-util-mdx-jsx";
5
+ export type { MdxJsxFlowElement, MdxJsxTextElement, MdxJsxAttribute as MdxJsxAttributeNode, MdxJsxExpressionAttribute as MdxJsxExpressionAttributeNode, MdxJsxAttributeValueExpression as MdxJsxAttributeValueExpressionNode, MdxFlowExpression, MdxTextExpression, MdxjsEsm, } from "./mdx-types.js";
6
+ import type { MdxJsxAttribute, MdxJsxExpressionAttribute } from "./mdx-types.js";
9
7
  export type MdxJsxAttributeUnion = MdxJsxAttribute | MdxJsxExpressionAttribute;
10
8
  export interface Toml extends MdastLiteral {
11
9
  type: "toml";
@@ -46,13 +44,13 @@ declare module "hast" {
46
44
  }
47
45
  }
48
46
  /**
49
- * Materialized mdast node a standard `mdast.Nodes` discriminated union.
47
+ * Materialized mdast node, a standard `mdast.Nodes` discriminated union.
50
48
  * Narrow by `node.type` to access type-specific properties
51
49
  * (e.g. `depth` on `"heading"`, `url` on `"link"`).
52
50
  */
53
51
  export type MdastNode = MdastStdNodes;
54
52
  /**
55
- * Materialized hast node a standard `hast.Nodes` discriminated union.
53
+ * Materialized hast node, a standard `hast.Nodes` discriminated union.
56
54
  * Narrow by `node.type` to access type-specific properties
57
55
  * (e.g. `tagName` on `"element"`, `value` on `"text"`).
58
56
  */
package/dist/types.js CHANGED
@@ -1,6 +1 @@
1
- // Shared types for the satteri JS layer.
2
- //
3
- // Uses standard @types/mdast, @types/hast, and mdast-util-mdx-* packages
4
- // for AST node types. Extension types (toml, math, raw) are augmented here.
5
1
  export {};
6
- //# sourceMappingURL=types.js.map
package/index.d.ts CHANGED
@@ -23,7 +23,7 @@ export declare function convertMdastToHastHandle(handle: ArenaHandle): ArenaHand
23
23
 
24
24
  /**
25
25
  * Parse markdown source and convert to HAST. Returns an opaque handle.
26
- * The arena stays in Rust memory no buffer is copied to JS.
26
+ * The arena stays in Rust memory, no buffer is copied to JS.
27
27
  */
28
28
  export declare function createHastHandle(source: string): ArenaHandle
29
29
 
@@ -75,13 +75,30 @@ export interface JsSubscription {
75
75
  tagFilter: Array<string>
76
76
  }
77
77
 
78
+ /** Options for `mdast_text_content_handle`, matching `mdast-util-to-string`. */
79
+ export interface JsTextContentOptions {
80
+ /** Include `alt` text from image nodes. Default: true. */
81
+ includeImageAlt?: boolean
82
+ /** Include `value` from HTML nodes. Default: true. */
83
+ includeHtml?: boolean
84
+ }
85
+
86
+ /**
87
+ * Collect the concatenated text content of an MDAST node and all its descendants.
88
+ * Mirrors `mdast-util-to-string`: collects value from text nodes, alt from images.
89
+ */
90
+ export declare function mdastTextContentHandle(handle: ArenaHandle, nodeId: number, options?: JsTextContentOptions | undefined | null): string
91
+
78
92
  /**
79
93
  * Parse a JavaScript expression and return its ESTree-compatible AST as a JSON string.
80
94
  * Returns null if parsing fails. The JS layer calls JSON.parse (faster than serde_json → NAPI).
81
95
  */
82
96
  export declare function parseExpression(source: string): string | null
83
97
 
84
- /** Parse Markdown source and return HTML string directly. */
98
+ /**
99
+ * Parse Markdown source and return HTML string directly.
100
+ * Uses pulldown-cmark's streaming renderer, skipping the arena entirely.
101
+ */
85
102
  export declare function parseToHtml(source: string): string
86
103
 
87
104
  /** Render a handle's HAST arena to HTML. Does not consume the handle. */
@@ -97,8 +114,8 @@ export declare function serializeMdastHandle(handle: ArenaHandle): Uint8Array
97
114
  export declare function setNodeData(handle: ArenaHandle, nodeId: number, json: Uint8Array): void
98
115
 
99
116
  /**
100
- * Collect the concatenated text content of a node and all its descendants.
101
- * Walks entirely in Rust no per-child NAPI round-trips.
117
+ * Collect the concatenated text content of a HAST node and all its descendants.
118
+ * Walks entirely in Rust, no per-child NAPI round-trips.
102
119
  */
103
120
  export declare function textContentHandle(handle: ArenaHandle, nodeId: number): string
104
121