@peisar/peisar-wasm32-wasi 0.2.22 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peisar/peisar-wasm32-wasi",
3
- "version": "0.2.22",
3
+ "version": "0.3.01",
4
4
  "main": "peisar.wasi.cjs",
5
5
  "files": [
6
6
  "peisar.wasm32-wasi.wasm",
@@ -30,8 +30,8 @@
30
30
  "browser": "peisar.wasi-browser.js",
31
31
  "type": "module",
32
32
  "dependencies": {
33
- "@napi-rs/wasm-runtime": "~1.2.4",
34
- "@emnapi/core": "2.0.0-alpha.5",
35
- "@emnapi/runtime": "2.0.0-alpha.5"
33
+ "@napi-rs/wasm-runtime": "~1.2.5",
34
+ "@emnapi/core": "2.0.0-alpha.6",
35
+ "@emnapi/runtime": "2.0.0-alpha.6"
36
36
  }
37
37
  }
@@ -1441,6 +1441,6 @@ try {
1441
1441
  }
1442
1442
  export default __napiModule.exports
1443
1443
  export const Peisar = __napiModule.exports.Peisar
1444
- export const EmphasisLevel = __napiModule.exports.EmphasisLevel
1445
- export const TableCellAlignment = __napiModule.exports.TableCellAlignment
1446
- export const TaskState = __napiModule.exports.TaskState
1444
+ export const PeisarCache = __napiModule.exports.PeisarCache
1445
+ export const frontmatter = __napiModule.exports.frontmatter
1446
+ export const yamlParser = __napiModule.exports.yamlParser
package/peisar.wasi.cjs CHANGED
@@ -1,4 +1,4 @@
1
- // napi-rs-artifact-metadata:{"version":2,"rootEntry":"index.js","exports":["Peisar","EmphasisLevel","TableCellAlignment","TaskState"],"managedRootEntries":["browser.js","index.js","peisar.wasm","peisar.debug.wasm"]}
1
+ // napi-rs-artifact-metadata:{"version":2,"rootEntry":"index.cjs","exports":["Peisar","PeisarCache","frontmatter","yamlParser"],"managedRootEntries":["browser.js","index.cjs","peisar.wasm","peisar.debug.wasm"]}
2
2
  /* eslint-disable */
3
3
  /* auto-generated by NAPI-RS */
4
4
 
@@ -222,6 +222,34 @@ function __hasWasiThreadCrashed() {
222
222
  }
223
223
 
224
224
  let __wasiThreadCrashDisposePromise
225
+ // Raised by the crash disposal right before it terminates the workers. See
226
+ // `__wasiSetImmediate`.
227
+ let __wasiReentryClosed = false
228
+
229
+ /**
230
+ * emnapi's `features.setImmediate` for this binding's context. emnapi defers
231
+ * its calls back into wasm through it: `_emnapi_set_immediate` (libuv handle
232
+ * closes, threadsafe-function finalizers), threadsafe-function dispatch
233
+ * (`async-send`) and the finalizer queue. One queued before a crash disposal
234
+ * terminates the workers still runs after it, and a worker terminated while it
235
+ * held a lock in the wasm heap (napi's heap-sync allocator lock spins and never
236
+ * gives up) leaves that call spinning on this thread for good. The binding is
237
+ * unusable after a crash disposal, so those calls are dropped.
238
+ *
239
+ * Known residual, still able to enter wasm after a crash disposal because emnapi
240
+ * offers no hook for them: the `FinalizationRegistry` callbacks that free
241
+ * external memory when GC collects a value (`_free`, the shared-buffer meta
242
+ * release), threadsafe-function dispatch of `async-send` type 1 and
243
+ * `_emnapi_next_tick` (both `Promise.resolve().then`), and every deferred
244
+ * call under emnapi 1.x, whose `createContext` ignores `features`.
245
+ */
246
+ function __wasiSetImmediate(callback) {
247
+ return setImmediate(function () {
248
+ if (!__wasiReentryClosed) {
249
+ callback()
250
+ }
251
+ })
252
+ }
225
253
 
226
254
  /**
227
255
  * Stores the first error a pool worker reported, with the worker's id. Called
@@ -371,6 +399,8 @@ function __disposeWasiBindingAfterThreadCrash() {
371
399
  return __wasiThreadCrashDisposePromise
372
400
  }
373
401
  __releaseEmnapiWaitingRequestHandle()
402
+ // No call into wasm after this: see `__wasiSetImmediate`.
403
+ __wasiReentryClosed = true
374
404
  let workerResult
375
405
  try {
376
406
  workerResult = __terminateWasiWorkers()
@@ -455,6 +485,130 @@ function __rollbackWasiInitializationAfterThreadCrash() {
455
485
  return [crashError]
456
486
  }
457
487
 
488
+ const __wasiThreadPoolReconcileSymbol = Symbol.for('napi.rs.wasi.reconcileThreadPool')
489
+
490
+ /**
491
+ * Takes a Worker out of emnapi's reuse pool, if it is still there. emnapi
492
+ * terminates a pooled Worker that failed to load but (up to
493
+ * @emnapi/wasi-threads 2.1.0) leaves it in the pool, where the next thread
494
+ * spawn would pop it. A newer emnapi removes it itself, so this is a no-op
495
+ * then.
496
+ */
497
+ function __removeWasiPoolWorker(manager, worker) {
498
+ const index = manager.unusedWorkers.indexOf(worker)
499
+ if (index !== -1) {
500
+ manager.unusedWorkers.splice(index, 1)
501
+ }
502
+ }
503
+
504
+ /**
505
+ * Takes a Worker the thread manager just terminated out of `__wasiWorkers`
506
+ * once it has exited, not before. `terminateWorker` only starts Node's
507
+ * asynchronous `worker.terminate()` and drops its promise, so a disposal that
508
+ * begins before the exit has to find this Worker in the set and wait for it
509
+ * like any other. A second `terminate()` settles when the Worker has exited,
510
+ * the way `__terminateWasiWorkers` waits.
511
+ */
512
+ function __untrackWasiWorkerOnExit(worker) {
513
+ const terminated = worker.terminate()
514
+ if (__isThenable(terminated)) {
515
+ Promise.resolve(terminated).then(
516
+ () => {
517
+ __wasiWorkers.delete(worker)
518
+ },
519
+ // Left tracked: disposal terminates it again and reports the error.
520
+ () => {},
521
+ )
522
+ } else {
523
+ __wasiWorkers.delete(worker)
524
+ }
525
+ }
526
+
527
+ /**
528
+ * Matches emnapi's idle reuse pool to the addon's configured MultiThread worker
529
+ * count, which the addon exports as `napi_wasm_runtime_pool_workers`
530
+ * (napi-async-runtime; 0 under CurrentThread). `reuseWorker: true` starts the
531
+ * pool empty, so without this every pool thread the first async call spawns
532
+ * boots a Worker and loads the wasm into it first. Here each missing Worker is
533
+ * created and starts loading now; a spawn later pops one that is already
534
+ * booting. Idle Workers above the count are terminated, last in first out,
535
+ * the way a spawn takes them. A Worker a spawn already took is not in the pool
536
+ * and is left alone.
537
+ *
538
+ * Runs once after a successful load and, when the loader wraps it, after every
539
+ * successful `configureAsyncRuntime`. Also reachable as
540
+ * binding[Symbol.for('napi.rs.wasi.reconcileThreadPool')]().
541
+ * It never throws and never waits on a Worker: a Worker whose load fails is
542
+ * dropped from the pool when its load rejects. Nothing at all happens after a
543
+ * thread crash, once disposal started, or for an addon without the export.
544
+ */
545
+ function __reconcileWasiThreadPool() {
546
+ try {
547
+ if (__wasiDisposed || __wasiDisposePromise || __hasWasiThreadCrashed()) {
548
+ return
549
+ }
550
+ const read = __napiInstance?.exports?.napi_wasm_runtime_pool_workers
551
+ if (typeof read !== 'function') {
552
+ return
553
+ }
554
+ const count = read() >>> 0
555
+ const manager = __getWasiThreadManager()
556
+ if (
557
+ !manager ||
558
+ !Array.isArray(manager.unusedWorkers) ||
559
+ typeof manager.allocateUnusedWorker !== 'function' ||
560
+ typeof manager.loadWasmModuleToWorker !== 'function'
561
+ ) {
562
+ return
563
+ }
564
+ // Both loops are bounded by the difference they start from, so a manager
565
+ // that does not update `unusedWorkers` the way emnapi does cannot spin.
566
+ for (let excess = manager.unusedWorkers.length - count; excess > 0; excess--) {
567
+ const worker = manager.unusedWorkers[manager.unusedWorkers.length - 1]
568
+ manager.terminateWorker(worker)
569
+ __removeWasiPoolWorker(manager, worker)
570
+ __untrackWasiWorkerOnExit(worker)
571
+ // Compatibility with @emnapi/wasi-threads 2.1.0 and older:
572
+ // `terminateWorker` installs a reporter that logs every emnapi message
573
+ // still queued on the port, so a Worker that finished loading just
574
+ // before it was terminated prints 'received "loaded" command from
575
+ // terminated worker'. Nothing listens for that Worker any more, and a
576
+ // newer emnapi ignores the late 'loaded' itself, so this is harmless
577
+ // there. `__terminateWasiWorkers` does the same.
578
+ worker.onmessage = undefined
579
+ }
580
+ for (let missing = count - manager.unusedWorkers.length; missing > 0; missing--) {
581
+ let worker
582
+ try {
583
+ // Through `onCreateWorker`: tracked in `__wasiWorkers`, unref'd, and
584
+ // handed the crash flags like any pool Worker.
585
+ worker = manager.allocateUnusedWorker()
586
+ manager
587
+ .loadWasmModuleToWorker(worker)
588
+ .then(undefined, () => __removeWasiPoolWorker(manager, worker))
589
+ } catch {
590
+ if (worker !== undefined) {
591
+ __removeWasiPoolWorker(manager, worker)
592
+ try {
593
+ manager.terminateWorker(worker)
594
+ __untrackWasiWorkerOnExit(worker)
595
+ } catch {}
596
+ }
597
+ return
598
+ }
599
+ }
600
+ } catch {}
601
+ }
602
+
603
+ function __publishWasiThreadPoolReconcile(exports) {
604
+ Object.defineProperty(exports, __wasiThreadPoolReconcileSymbol, {
605
+ configurable: false,
606
+ enumerable: false,
607
+ value: __reconcileWasiThreadPool,
608
+ writable: false,
609
+ })
610
+ }
611
+
458
612
  const __cwd = process.cwd()
459
613
  const __rootDir = __nodePath.parse(__cwd).root
460
614
  const __hostRoot =
@@ -2011,7 +2165,7 @@ try {
2011
2165
  const __finishAutoDestroyCapture = __captureEmnapiAutoDestroyListener()
2012
2166
  try {
2013
2167
  __emnapiContext = __wrapEmnapiContextDestroyForSettlement(
2014
- __emnapiCreateContext({ autoDestroy: false }),
2168
+ __emnapiCreateContext({ autoDestroy: false, features: { setImmediate: __wasiSetImmediate } }),
2015
2169
  __prepareWasmEnvCleanup,
2016
2170
  __isPreparingWasmEnvCleanup,
2017
2171
  )
@@ -2108,6 +2262,7 @@ try {
2108
2262
  },
2109
2263
  }))
2110
2264
  __publishWasiDispose(__napiModule.exports)
2265
+ __publishWasiThreadPoolReconcile(__napiModule.exports)
2111
2266
  // The CommonJS tail below aliases `__napiModule.exports`; a named module
2112
2267
  // export does not travel with it, so carry the marker on the binding itself
2113
2268
  // too. Three things pin the stamp to exactly this spot:
@@ -2136,8 +2291,13 @@ try {
2136
2291
  __runWasiInitializationRollback(rollback)
2137
2292
  throw rollback.error
2138
2293
  }
2294
+ // Preload the pool for the count the addon configured during registration.
2295
+ // See `__reconcileWasiThreadPool`.
2296
+ try {
2297
+ __reconcileWasiThreadPool()
2298
+ } catch {}
2139
2299
  module.exports = __napiModule.exports
2140
2300
  module.exports.Peisar = __napiModule.exports.Peisar
2141
- module.exports.EmphasisLevel = __napiModule.exports.EmphasisLevel
2142
- module.exports.TableCellAlignment = __napiModule.exports.TableCellAlignment
2143
- module.exports.TaskState = __napiModule.exports.TaskState
2301
+ module.exports.PeisarCache = __napiModule.exports.PeisarCache
2302
+ module.exports.frontmatter = __napiModule.exports.frontmatter
2303
+ module.exports.yamlParser = __napiModule.exports.yamlParser
package/peisar.wasi.d.cts CHANGED
@@ -1,5 +1,7 @@
1
- /* auto-generated by NAPI-RS */
2
- /* eslint-disable */
1
+ export type PeisarEmphasisLevel = "Italic" | "Bold";
2
+ export type PeisarTableCellAlignment = "Default" | "Left" | "Center" | "Right";
3
+ export type PeisarTableCellAlignments = PeisarTableCellAlignment[];
4
+ export type PeisarTaskState = "Unchecked" | "Checked";
3
5
 
4
6
  /** The WASI flavor this loader instantiates. */
5
7
  export declare const __napiBindingTarget: 'wasm32-wasi'
@@ -65,6 +67,73 @@ export declare class Peisar {
65
67
  get astJson(): string
66
68
  }
67
69
 
70
+ /**
71
+ * In-memory cache of the Markdown and asset files under a directory tree.
72
+ *
73
+ * The cache maps absolute source paths to [`CachedContent`] entries, is
74
+ * mirrored to a `.peisar_cache` directory on disk, and — after
75
+ * [`PeisarCache::start_watching`] — tracks the source directories with a
76
+ * recursive file watcher.
77
+ *
78
+ * Rust consumers read the cache with [`PeisarCache::get`] and
79
+ * [`PeisarCache::all`]; JavaScript consumers use the N-API methods below
80
+ * (`getText`, `getBinary`, `listFiles`, `markdownFiles`, `assetFiles`, …).
81
+ */
82
+ export declare class PeisarCache {
83
+ /**
84
+ * Construct a new PeisarCache using the default discovery behavior.
85
+ *
86
+ * JS: `new PeisarCache(entryDir, assetsDir?)` — both plain strings.
87
+ */
88
+ constructor(entryDir: string, assetsDir?: string | undefined | null)
89
+ /**
90
+ * JS: same as the constructor, for callers that prefer a factory shape.
91
+ * Kept non-generic so NAPI can export it.
92
+ */
93
+ static withConfigJs(entryDir: string, assetsDir?: string | undefined | null): PeisarCache
94
+ /**
95
+ * JS: `cache.startWatchingJs()` — start watching the entry (and
96
+ * assets) directories recursively; errors surface as JS exceptions.
97
+ */
98
+ startWatchingJs(): void
99
+ /**
100
+ * ----------------------------------------------------------------
101
+ * JavaScript (NAPI) surface
102
+ * ----------------------------------------------------------------
103
+ * All JS methods take/return plain strings because `&Path`/`PathBuf`
104
+ * do not cross the NAPI boundary.
105
+ * JS: `cache.getText(absPath)` — cached text of a file, or null.
106
+ */
107
+ getText(absPath: string): string | null
108
+ /** JS: `cache.getBinary(absPath)` — cached bytes of a binary asset, or null. */
109
+ getBinary(absPath: string): Array<number> | null
110
+ /** JS: `cache.listFiles()` — absolute paths of everything cached. */
111
+ listFiles(): Array<string>
112
+ /** JS: `cache.markdownFiles()` — absolute paths of cached markdown files. */
113
+ markdownFiles(): Array<string>
114
+ /** JS: `cache.assetFiles()` — absolute paths of cached non-markdown files. */
115
+ assetFiles(): Array<string>
116
+ /**
117
+ * JS: `cache.onChange(cb)` — invoke `cb(event)` on every file change the
118
+ * watcher detects while watching is active. Returns a subscription id
119
+ * that can be passed to `offChange(id)`.
120
+ *
121
+ * The callback is wrapped in a `ThreadsafeFunction` because notify
122
+ * events fire on the watcher thread, not the JS main thread.
123
+ */
124
+ onChange(callback: (event: CacheChangeEvent) => void): number
125
+ /** JS: `cache.offChange(id)` — remove a previously registered callback. */
126
+ offChange(id: number): void
127
+ /**
128
+ * JS: `cache.dispose()` — stop the watcher and drop JS change callbacks.
129
+ * Safe to call more than once.
130
+ *
131
+ * Rust consumers do not need this: dropping the [`PeisarCache`] stops
132
+ * the watcher, closes the persistence channel, and joins the worker.
133
+ */
134
+ dispose(): void
135
+ }
136
+
68
137
  /**
69
138
  * Options that control how Markdown is parsed.
70
139
  *
@@ -149,13 +218,13 @@ export type Block =
149
218
  * Synchronous block-visitor callback. Receives a `Block`, returns
150
219
  * `VisitControlJs` (or `undefined` for no changes).
151
220
  */
152
- export type BlockCallback = (arg: [Block]) => VisitControlJs | null
221
+ export type BlockCallback = (arg: [Block]) => VisitorControl | null
153
222
 
154
223
  /**
155
224
  * Synchronous block parser hook. Receives a [`BlockParseContext`], returns
156
225
  * a [`BlockParseResultJs`] (or `undefined` to decline).
157
226
  */
158
- export type BlockParseCallback = (arg: [BlockParseContext]) => BlockParseResultJs | null
227
+ export type BlockParseCallback = (arg: [BlockParseContext]) => BlockParseResult | null
159
228
 
160
229
  /**
161
230
  * Context passed to block parser hooks.
@@ -178,13 +247,35 @@ export interface BlockParseContext {
178
247
  * All fields are optional; omitting `block` (or returning `undefined`)
179
248
  * declines the position so the next hook / built-in parser handles it.
180
249
  */
181
- export interface BlockParseResultJs {
250
+ export interface BlockParseResult {
182
251
  /** The parsed block node. */
183
252
  block?: Block
184
253
  /** Number of source lines consumed (must be at least `1`). */
185
254
  consumed?: number
186
255
  }
187
256
 
257
+ /**
258
+ * A file-change event delivered to change callbacks
259
+ * (see [`PeisarCache::on_change`]).
260
+ */
261
+ export interface CacheChangeEvent {
262
+ /** Absolute path of the changed file. */
263
+ path: string
264
+ /** `"create"`, `"modify"`, `"remove"`, or `"other"`. */
265
+ kind: string
266
+ /** `true` when the file is under the markdown entry directory. */
267
+ isMarkdown: boolean
268
+ }
269
+
270
+ /**
271
+ * An entry stored in the cache: raw UTF-8 text (markdown and textual
272
+ * assets) or raw bytes (binary assets). Exposed to JavaScript so JS
273
+ * consumers can branch on the variant.
274
+ */
275
+ export type CachedContent =
276
+ | { type: 'Text'; field0: string }
277
+ | { type: 'Binary'; field0: Array<number> }
278
+
188
279
  /**
189
280
  * A Markdown document — the root of the AST.
190
281
  *
@@ -204,12 +295,14 @@ export interface Document {
204
295
  linkReferences: Array<LinkReferenceDefinition>
205
296
  }
206
297
 
207
- /** Emphasis strength. */
208
- export declare const enum EmphasisLevel {
209
- /** `*italic*` / `_italic_` */
210
- Italic = 0,
211
- /** `**bold**` / `__bold__` */
212
- Bold = 1,
298
+ export declare function frontmatter(content: string): FrontmatterResult
299
+
300
+ /** The Markdown body and YAML metadata parsed from a front-matter document. */
301
+ export interface FrontmatterResult {
302
+ /** Markdown source after the leading YAML front matter is removed. */
303
+ pureMarkdownContent: string
304
+ /** Deserialized YAML front matter, or `null` when no front matter exists. */
305
+ yamlData?: Record<string, any>
213
306
  }
214
307
 
215
308
  /** Inline-level nodes. */
@@ -218,7 +311,7 @@ export type Inline =
218
311
  value: string; /** Source span. */
219
312
  pos: Span }
220
313
  | { type: 'Emphasis'; /** Emphasis level (italic or bold). */
221
- level: EmphasisLevel; /** Nested inline content. */
314
+ level: PeisarEmphasisLevel; /** Nested inline content. */
222
315
  children: Array<Inline>; /** Source span. */
223
316
  pos: Span }
224
317
  | { type: 'Code'; /** The code text. */
@@ -256,13 +349,13 @@ export type Inline =
256
349
  * Synchronous inline-visitor callback. Receives an `Inline`, returns
257
350
  * `InlineVisitControlJs` (or `undefined` for no changes).
258
351
  */
259
- export type InlineCallback = (arg: [Inline]) => InlineVisitControlJs | null
352
+ export type InlineCallback = (arg: [Inline]) => InlineVisitorControl | null
260
353
 
261
354
  /**
262
355
  * Synchronous inline parser hook. Receives an [`InlineParseContext`],
263
356
  * returns an [`InlineParseResultJs`] (or `undefined` to decline).
264
357
  */
265
- export type InlineParseCallback = (arg: [InlineParseContext]) => InlineParseResultJs | null
358
+ export type InlineParseCallback = (arg: [InlineParseContext]) => InlineParseResult | null
266
359
 
267
360
  /**
268
361
  * Context passed to inline parser hooks.
@@ -282,7 +375,7 @@ export interface InlineParseContext {
282
375
  * All fields are optional; omitting `inline` (or returning `undefined`)
283
376
  * declines the position so the next hook / built-in parser handles it.
284
377
  */
285
- export interface InlineParseResultJs {
378
+ export interface InlineParseResult {
286
379
  /** The parsed inline node. */
287
380
  inline?: Inline
288
381
  /** Number of characters consumed (`0` or missing declines). */
@@ -295,7 +388,7 @@ export interface InlineParseResultJs {
295
388
  * Returned from the JS `visitInline` callback. All fields are optional;
296
389
  * omitting a field means "no change" for that operation.
297
390
  */
298
- export interface InlineVisitControlJs {
391
+ export interface InlineVisitorControl {
299
392
  /** Nodes to insert before the current node. */
300
393
  insertBefore?: Array<Inline>
301
394
  /** Nodes to insert after the current node. */
@@ -325,39 +418,12 @@ export interface ListItem {
325
418
  /** Nested block content of the item. */
326
419
  children: Array<Block>
327
420
  /** GFM task-list state: `None` = not a task, `Some` = checked / unchecked. */
328
- task?: TaskState
421
+ task?: PeisarTaskState
329
422
  /** Span of the item in the *sub-document* of its enclosing list. */
330
423
  pos: Span
331
424
  }
332
425
 
333
- /**
334
- * JavaScript object shape for a parser hook pair.
335
- *
336
- * ```js
337
- * const myParser = {
338
- * parseBlock(ctx) {
339
- * if (!ctx.line.startsWith(':::')) return; // decline
340
- * const name = ctx.line.slice(3).trim();
341
- * return {
342
- * block: { type: 'HtmlBlock', html: `<div data-name="${name}"></div>`, pos: { start: {}, end: {} } },
343
- * consumed: 1,
344
- * };
345
- * },
346
- * parseInline(ctx) {
347
- * if (!ctx.rest.startsWith('@@')) return; // decline
348
- * const end = ctx.rest.indexOf(' ', 2);
349
- * const name = end === -1 ? ctx.rest.slice(2) : ctx.rest.slice(2, end);
350
- * return {
351
- * inline: { type: 'HtmlInline', html: `<span data-name="${name}"></span>`, pos: { start: {}, end: {} } },
352
- * consumed: name.length + 2,
353
- * };
354
- * },
355
- * };
356
- * document.useParser(myParser);
357
- * ```
358
- *
359
- * Either property may be omitted / `null` to skip that phase.
360
- */
426
+ /** Either property may be omitted / `null` to skip that phase. */
361
427
  export interface Parser {
362
428
  /** Optional JS block parser hook (JS: `parseBlock`). */
363
429
  parseBlock?: BlockParseCallback
@@ -365,14 +431,6 @@ export interface Parser {
365
431
  parseInline?: InlineParseCallback
366
432
  }
367
433
 
368
- /** The Markdown body and YAML metadata parsed from a front-matter document. */
369
- export interface ParseResult {
370
- /** Markdown source after the leading YAML front matter is removed. */
371
- pureMarkdownContent: string
372
- /** Deserialized YAML front matter, or `null` when no front matter exists. */
373
- yamlData?: Record<string, any>
374
- }
375
-
376
434
  /**
377
435
  * JavaScript options for Markdown parsing and HTML rendering.
378
436
  *
@@ -507,7 +565,7 @@ export interface Table {
507
565
  /** Body rows. */
508
566
  rows: Array<TableRow>
509
567
  /** Column alignment specifications (one per column). */
510
- alignments: Array<TableCellAlignment>
568
+ alignments: PeisarTableCellAlignments
511
569
  }
512
570
 
513
571
  /** A single table cell. */
@@ -516,30 +574,33 @@ export interface TableCell {
516
574
  children: Array<Inline>
517
575
  }
518
576
 
519
- /** Column alignment for table cells. */
520
- export declare const enum TableCellAlignment {
521
- /** `:---` or `---` — default (left) */
522
- Default = 0,
523
- /** `:---` */
524
- Left = 1,
525
- /** `:---:` */
526
- Center = 2,
527
- /** `---:` */
528
- Right = 3,
529
- }
530
-
531
577
  /** A single table row (header or body). */
532
578
  export interface TableRow {
533
579
  /** The cells in this row. */
534
580
  cells: Array<TableCell>
535
581
  }
536
582
 
537
- /** GFM task-list checkbox state. */
538
- export declare const enum TaskState {
539
- /** `[ ]` — unchecked */
540
- Unchecked = 0,
541
- /** `[x]` / `[X]` — checked */
542
- Checked = 1,
583
+ /**
584
+ * JavaScript object shape for a visitor callback pair.
585
+ *
586
+ * On the JS side it is a plain object with two optional
587
+ * function properties:
588
+ *
589
+ * ```js
590
+ * const myPlugin = {
591
+ * visitBlock(block) { return { recurse: true }; },
592
+ * visitInline(inline) { return {}; },
593
+ * };
594
+ * ast.addVisitor(myPlugin);
595
+ * ```
596
+ *
597
+ * Either property may be omitted / `null` to skip that node kind.
598
+ */
599
+ export interface Visitor {
600
+ /** Optional JS callback for block nodes (JS: `visitBlock`). */
601
+ visitBlock?: BlockCallback
602
+ /** Optional JS callback for inline nodes (JS: `visitInline`). */
603
+ visitInline?: InlineCallback
543
604
  }
544
605
 
545
606
  /**
@@ -548,7 +609,7 @@ export declare const enum TaskState {
548
609
  * Returned from the JS `visitBlock` callback. All fields are optional;
549
610
  * omitting a field means "no change" for that operation.
550
611
  */
551
- export interface VisitControlJs {
612
+ export interface VisitorControl {
552
613
  /** Nodes to insert before the current node. */
553
614
  insertBefore?: Array<Block>
554
615
  /** Nodes to insert after the current node. */
@@ -562,24 +623,13 @@ export interface VisitControlJs {
562
623
  }
563
624
 
564
625
  /**
565
- * JavaScript object shape for a visitor callback pair.
626
+ * Parses a YAML document into a JSON-compatible value.
566
627
  *
567
- * On the JS side it is a plain object with two optional
568
- * function properties:
628
+ * When consumed from Node.js, the result is exposed as a JavaScript object
629
+ * with the TypeScript type `Record<string, any>`.
569
630
  *
570
- * ```js
571
- * const myPlugin = {
572
- * visitBlock(block) { return { recurse: true }; },
573
- * visitInline(inline) { return {}; },
574
- * };
575
- * ast.addVisitor(myPlugin);
576
- * ```
631
+ * # Panics
577
632
  *
578
- * Either property may be omitted / `null` to skip that node kind.
633
+ * Panics when `yaml_str` is not valid YAML.
579
634
  */
580
- export interface Visitor {
581
- /** Optional JS callback for block nodes (JS: `visitBlock`). */
582
- visitBlock?: BlockCallback
583
- /** Optional JS callback for inline nodes (JS: `visitInline`). */
584
- visitInline?: InlineCallback
585
- }
635
+ export declare function yamlParser(yamlStr: string): Record<string, any>
Binary file