Skip to content

@ox-content/napi#

View Markdown

Ox Content の Rust コア向け Node.js バインディングです。

インストール#

vp install @ox-content/napi

プラットフォーム対応#

リリースパッケージは macOS arm64/x64、Linux arm64/x64 GNU、Windows x64 MSVC のネイティブバインディングを配ります。CI はすべての PR で、macOS、Linux、Windows に対して軽い読み込みとパース / 描画のスモークテストを走らせます。

他の Node.js プラットフォームは、Rust ツールチェーンと NAPI ビルド道具があればソースからビルドできることがありますが、事前ビルドの npm バインディングパッケージとしては公開しません。

使い方#

Markdown を AST へパース#

import { parseMarkdown } from "@ox-content/napi";

const markdown = "# Hello World\n\nThis is **bold** text.";
const ast = parseMarkdown(markdown, { gfm: true });

console.log(JSON.stringify(ast, null, 2));

パースと描画#

import { parseAndRender } from "@ox-content/napi";

const markdown = `
# Welcome

- Item 1
- Item 2
- Item 3

| Column A | Column B |
|----------|----------|
| Value 1  | Value 2  |
`;

const result = parseAndRender(markdown, {
  gfm: true,
  footnotes: true,
  tables: true,
});

console.log(result.html);

API#

parseMarkdown(content, options?)#

Markdown をパースし、AST を返します。

引数#

  • content: string — パースする Markdown
  • options: ParseOptions(任意)

戻り値#

MarkdownAst — パース済み AST

parseAndRender(content, options?)#

1 回の呼び出しで Markdown をパースし、HTML に描画します。

引数#

  • content: string — パースする Markdown
  • options: ParseOptions(任意)

戻り値#

interface RenderResult {
  html: string;
  frontmatter?: Record<string, unknown>;
  toc?: TocEntry[];
}

オプション#

interface ParseOptions {
  /** Enable GitHub Flavored Markdown */
  gfm?: boolean;

  /** Enable footnotes */
  footnotes?: boolean;

  /** Render footnotes as a semantic ordered section with numeric markers */
  semanticFootnotes?: boolean;

  /** Enable tables */
  tables?: boolean;

  /** Enable task lists */
  taskLists?: boolean;

  /** Enable strikethrough */
  strikethrough?: boolean;
}

AST の型#

AST は mdast 仕様に従います。

interface MarkdownNode {
  type: string;
  children?: MarkdownNode[];
  value?: string;
  // Additional properties based on node type
}

// Block nodes
type BlockNode =
  | "root"
  | "paragraph"
  | "heading"
  | "codeBlock"
  | "blockquote"
  | "list"
  | "listItem"
  | "table"
  | "tableRow"
  | "tableCell"
  | "thematicBreak"
  | "html";

// Inline nodes
type InlineNode =
  | "text"
  | "emphasis"
  | "strong"
  | "inlineCode"
  | "link"
  | "image"
  | "break"
  | "delete"
  | "footnoteReference";

検索 API#

NAPI バインディングには全文検索エンジンが含まれます。

buildSearchIndex(documents)#

文書配列から検索インデックスを作ります。

import { buildSearchIndex } from "@ox-content/napi";

const documents = [
  {
    id: "getting-started",
    title: "Getting Started",
    url: "/getting-started",
    body: "Welcome to the documentation...",
    headings: ["Installation", "Quick Start"],
    code: ["npm install package"],
  },
];

const indexJson = buildSearchIndex(documents);

searchIndex(indexJson, query, options?)#

直列化したインデックスを検索します。

import { searchIndex } from "@ox-content/napi";

const results = searchIndex(indexJson, "getting started", {
  limit: 10,
  prefix: true,
});

// results: Array<{
//   id: string;
//   title: string;
//   url: string;
//   score: number;
//   matches: string[];
//   snippet: string;
// }>

extractSearchContent(source, id, url, options?)#

Markdown ソースから検索可能な内容を取り出します。

import { extractSearchContent } from "@ox-content/napi";

const markdown = "# Hello World\n\nThis is content.";
const doc = extractSearchContent(markdown, "hello", "/hello", { gfm: true });

// doc: {
//   id: 'hello',
//   title: 'Hello World',
//   url: '/hello',
//   body: 'This is content.',
//   headings: ['Hello World'],
//   code: [],
// }

性能#

いまのパーサとレンダラのベンチマークスナップショットは 性能 にあります。このパッケージページは N-API 固有のマイクロベンチマーク注記だけを残します。

mdast 転送マイクロベンチマーク#

unified ブリッジが使う mdast エクスポート経路をベンチマークするには次です。

cargo bench -p ox_content_napi --bench mdast_transfer -- --sample-size 20 --warm-up-time 1 --measurement-time 2

この Criterion ベンチマークは、小さい / 中 / 大きい GFM 文書に対して parse_nativeparse_jsonparse_rawtransform_html を比べます。各フィクスチャのエクスポート JSON と raw ペイロードサイズも出すので、パーサコストと転送形式コストを分けられます。

このベンチマークは Rust 側パイプラインだけを測ります。端から端までの unified ブリッジ評価では、N-API 境界と JS 側の mdast 実体化を含む JavaScript ベンチマークと組み合わせてください。

2026-05-17 の、転送に寄せたローカル実行は Node v24.15.0、Apple M5 Pro で、--sample-size 10--warm-up-time 1--measurement-time 1 でした。大きいフィクスチャは 45,298 バイトの GFM 寄りの Markdown です。

Path Large fixture median Throughput
parse_native 314.07 us 137.55 MiB/s
parse_json 373.60 us 115.63 MiB/s
parse_raw 560.24 us 77.109 MiB/s
transform_mdast_raw 594.15 us 72.708 MiB/s
transform_html 686.09 us 62.965 MiB/s

同じ実行のペイロードサイズ:

Fixture JSON bytes Raw bytes Transform raw bytes
small 2,292 4,177 4,682
medium 22,668 40,582 45,164
large 226,428 404,632 449,984

raw 転送経路はまだ役に立ちます。パース、frontmatter 除去、ソース起源メタデータを Rust が担い続けるからです。ただしこの実行では、最初の raw 符号化は JSON 単体より小さくも速くもありません。だから端から端までの mdast ブリッジ性能は、いまは互換機能として読むべきです。次の性能目標は raw 形式と JS デシリアライザの調整です。

転送エンベロープ#

raw 転送はいま、parseTransferRaw(source, kind, options) 経由の、ペイロード種類を意識したエンベロープを使います。mdast がベースラインペイロードで、いちばん優先度の高い経路のままです。ただしエンベロープは、将来のペイロード(markdown-it トークンストリームなど)が、第二の場当たりバイナリ形式を導入せず、同じゼロコピーメモリブロック形を再利用できるように設計しています。

ネイティブ unified ブリッジはいま transformMdastRaw(source, options) も使うので、Rust が frontmatter をパースし、内容を除き、mdast を 1 つの外部 Uint8Array に直列化したあと、JavaScript がデシリアライズできます。markdown-it と独自パーサ連携では、prepareSourceRaw(source, {frontmatter}) が、除いた内容と frontmatter JSON だけを運ぶより軽い prepared-source エンベロープを提供するので、ソース準備は JavaScript 前処理に落ちず Rust に留まります。

両方のエンベロープは、frontmatter を除いたとき、コンパクトな source origin 区画も運びます。JavaScript はそのメタデータで mdast の position フィールドを再ベースし、file.datafile.data.oxContent、Ox Content mdast プラグインコンテキストに sourceOffset を出すので、unified 診断と下流プラグインのメッセージは、frontmatter 後の内容スライスではなく、元の完全ソースファイルに揃います。

parseMdastRaw(source, options) は mdast 固有の互換ラッパとして残しています。

Last updated: