Files
outline/server/converters/BaseConverter.ts
T
000f2f98fb feat: Add TextPack (.textpack) support (#13235)
* feat: Add TextPack (.textpack) import support

Adds a single-document importer for TextPack, the zipped variant of
TextBundle used by Bear, Ulysses, iA Writer and others. Bare .textbundle
directories are not supported, as a directory cannot be delivered through
a browser file input.

The bundle's text entry may use any extension, per the spec, with
info.json's type deciding whether it can be read as markdown. Assets are
inlined as data URIs for the existing attachment pipeline to pick up,
bounded by the attachment size limit and a memory ceiling, and only for
media types markdown-it accepts as a link destination.

Also fixes an existing bug where a file embedded in an HTML or email
import as a data URI was stored in the document as base64 rather than
being uploaded as an attachment.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Refactor to individual converters

* refactor

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 20:42:05 -04:00

51 lines
1.5 KiB
TypeScript

import yaml from "js-yaml";
/**
* Base class for the individual file format converters, holding the handling
* that is common to reading any incoming file.
*/
export abstract class BaseConverter {
/**
* Convert a Buffer to a string.
*
* @param content The content as a Buffer or string.
* @returns The content as a string.
*/
protected static bufferToString(content: Buffer | string): string {
return typeof content === "string" ? content : content.toString("utf8");
}
/**
* Parse and convert frontmatter to a YAML codeblock.
*
* @param content The markdown content that may contain frontmatter.
* @returns The markdown content with frontmatter converted to a YAML codeblock.
*/
protected static processFrontmatter(content: string): string {
// Frontmatter must start at the beginning of the document
const frontmatterRegex = /^---\n([\s\S]*?)\n---(?:\n|$)/;
const match = content.match(frontmatterRegex);
if (!match) {
return content;
}
const frontmatterContent = match[1];
const remainingContent = content.slice(match[0].length);
// Validate that the frontmatter is valid YAML
try {
yaml.load(frontmatterContent);
} catch {
// If it's not valid YAML, return content unchanged
return content;
}
// Convert frontmatter to a YAML codeblock
const codeBlockDelimiter = "```";
const yamlCodeblock = `${codeBlockDelimiter}yaml\n${frontmatterContent}\n${codeBlockDelimiter}\n\n`;
return yamlCodeblock + remainingContent;
}
}