Skip to content

Interchange ​

Your content must never be trapped in the editor. Ezynota treats JSON as the source of truth and treats Markdown, HTML, and plain text as lossless-or-safely-degraded projections of it.

Formats at a glance ​

FormatDirectionFidelity
JSON (EzynotaDocument)✅ nativeLossless — includes tunes, nested children, marks
Markdownin + outNear-lossless (headings, lists, tables, tasks, code fences, inline marks, callouts)
HTMLin (sanitized) + outRich export; sanitized import
Plain textin + outStructure approximated (paragraphs, list markers)
Print / PDFoutSanitized print window via printDocument

JSON ​

ts
const doc = editor.getSnapshot();      // live, frozen snapshot
const saved = await editor.save();     // validated save output

A saved document embeds a generator stamp:

json
{
  "schemaVersion": "1.0.0",
  "generator": { "name": "ezynota", "version": "0.1.4" },
  "blocks": []
}

See the document format reference.

Markdown ​

ts
import { blocksToMarkdown, markdownToBlocks, parseMarkdownInline } from "@bookklik/ezynota";

const md = blocksToMarkdown(doc.blocks, {
  noteLinkTitles: true, // render note:<id> links with their titles (workspace)
});

const blocks = markdownToBlocks(md);

Supported round-trip features: headings, bullet/ordered/task lists, quotes, fenced code, tables, delimiters, callouts (via markers), bold/italic/strike/code/marks, links (including note:<id> internal links), images.

Code exports choose a fence longer than any backtick run in the code; imports require a matching closing fence. Plain-text exports read the text directly rather than stripping Markdown syntax, preserving literal underscores, asterisks, backticks, and operators.

HTML ​

Export produces standalone HTML with tables and <details>-based toggles:

ts
import { blocksToHtml } from "@bookklik/ezynota";

const html = blocksToHtml(doc.blocks);

Import runs through a strict sanitizer — scripts, styles, event handlers, and unsafe URLs are stripped, and the parsed tree is converted to blocks:

ts
import { htmlToBlocks, textToBlocks } from "@bookklik/ezynota";

const blocks = htmlToBlocks(pastedHtml);
const fromText = textToBlocks(plainText);

File import & export ​

ts
import { parseImportFile, blocksToDocument, exportDocumentToString, downloadTextFile, detectFormat } from "@bookklik/ezynota";

// From a File/Blob (json, md, html, txt, or a workspace backup)
const parsed = await parseImportFile(file);
if (parsed.result.kind === "backup") {
  throw new Error("Restore workspace backups with editor.workspace.restoreBackup instead.");
}
const doc = parsed.result.kind === "document"
  ? parsed.result.document
  : blocksToDocument(parsed.result.blocks, "Imported note");

// Serialize & download
const text = await exportDocumentToString(doc, "md", async () => null);
downloadTextFile("my-note.md", text, "text/markdown");

detectFormat uses the filename and MIME type to pick the parser; imports are size-capped (10 MB) as a safety measure. The example has no local assets; for a workspace document, supply an asset loader as shown next.

Assets ​

Image sources can be asset:<id> references into the workspace asset store. For portable exports, resolve them to data URLs:

ts
import { resolveDocumentAssets } from "@bookklik/ezynota";

const workspace = editor.workspace;
if (!workspace) throw new Error("A workspace is required to load local assets.");
const portable = await resolveDocumentAssets(doc, (id) => workspace.state.loadAsset(id));

The loader returns a WorkspaceAsset or null, not a URL. exportDocumentToString resolves local images for JSON, Markdown, and HTML exports when given this loader. Repeated references share one asset read per export. Direct blocksToMarkdown and blocksToHtml calls remain synchronous; resolve assets first when portability is needed.

ts
import { printDocument } from "@bookklik/ezynota";

printDocument(doc); // opens a sanitized print window

The print view strips interactive chrome and uses sanitized HTML — trigger it and let the user "Save as PDF" from the browser dialog.

Workspace shortcuts ​

In workspace mode, the WorkspaceController wraps all of this:

ts
await ws.exportActiveNote("md");
await ws.importFiles(fileList);
await ws.portableSnapshot(); // assets inlined as data URLs

Released under the MIT License. Zero runtime dependencies.