bitran
Version:
📜 Highly customizable text processor and transpiler.
260 lines (259 loc) • 9.19 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
import { c as textToStrBlocks, P as ProductLayout, n as normalizeText, B as BlockNode, I as InlinerNode } from "./productNode-C0XZsQy2.js";
import { d as detachMeta, p as parseMeta, s as stringifyMeta } from "./productMeta-DotuXXRl.js";
import { B as BlockParseFactory, g as getIntersection, e as RangeIntersection, T as TextNode } from "./index-DiVYKXTv.js";
import { R as RootNode } from "./root-BUkExl5d.js";
import { E as ErrorNode, B as BlocksNode, I as InlinersNode } from "./shared-B4X4KQeO.js";
class AutoId {
constructor() {
__publicField(this, "ids", {});
}
exists(id) {
return id in this.ids;
}
push(id) {
if (id in this.ids)
throw new Error(`Duplicate auto id "${id}"!`);
this.ids[id] = null;
}
}
class DefaultAutoId extends AutoId {
constructor() {
super(...arguments);
__publicField(this, "nameCounters", {});
}
generate(node) {
var _a;
const name = node.name;
(_a = this.nameCounters)[name] || (_a[name] = 0);
let autoId = `${name}:${++this.nameCounters[name]}`;
return autoId;
}
finalize(id) {
let finalId = id;
while (this.exists(finalId))
finalId += "-";
return finalId;
}
}
class Parser {
// private blockFactories: Record<string, new () => BlockParseFactory> = {};
// private inlinerFactories: Record<string, new () => InlinerParseFactory> = {};
constructor(coreConfig) {
__publicField(this, "coreConfig");
__publicField(this, "blockFactories", []);
__publicField(this, "inlinerFactories", []);
this.coreConfig = coreConfig;
for (const [productName, ProductCore] of Object.entries(coreConfig.products)) {
const factories = Array.isArray(ProductCore.Parser) ? ProductCore.Parser : [ProductCore.Parser];
for (const Factory of factories)
if (Factory)
this[Factory.prototype instanceof BlockParseFactory ? "blockFactories" : "inlinerFactories"].push([productName, Factory]);
}
}
async parse(text, options) {
[text, options] = resolveParseArgs(text, options);
const root = new RootNode();
const blocks = await this.parseBlocks(text, options);
root.setNodes(blocks);
return root;
}
//
// Block Parsing
//
async parseBlocks(text, options) {
if (typeof text !== "string")
return [];
[text, options] = resolveParseArgs(text, options);
const blocks = [];
for (const strBlock of textToStrBlocks(text)) {
const block = await this.parseBlock(strBlock, options);
if (!block)
continue;
blocks.push(block);
}
return blocks;
}
async parseBlock(strBlock, options) {
[strBlock, options] = resolveParseArgs(strBlock, options);
const { meta, restText } = detachMeta(strBlock);
for (const [blockName, BlockFactory] of this.blockFactories) {
const block = new this.coreConfig.products[blockName].Node();
block.name = blockName;
block.meta = meta;
const factory = prepareFactory(BlockFactory, this, block, options);
if (!factory.canParse(restText))
continue;
try {
block.parseData = await factory.createParseData(restText);
block.generated.autoId = createAutoId(options.autoId, factory, block);
options.step && await options.step(block);
return block;
} catch (error) {
return createErrorNode(ProductLayout.Block, blockName, strBlock, error);
}
}
return null;
}
//
// Inliner Parsing
//
async parseInliners(text, options) {
var _a, _b;
if (typeof text !== "string")
return [];
[text, options] = resolveParseArgs(text, options);
let rangeFactories = {};
let ranges = [];
for (const [inlinerName, InlinerFactory] of this.inlinerFactories) {
const factory = prepareFactory(InlinerFactory, this, null, options);
const newRanges = factory.outlineRanges(text);
for (const newRange of newRanges) {
let rangeIndex = 0;
let removeIndexes = [];
let approved = true;
for (const toCompareWithRange of ranges) {
switch (getIntersection(newRange, toCompareWithRange)) {
case RangeIntersection.Partial:
case RangeIntersection.Inside:
approved = false;
break;
case RangeIntersection.Contain:
removeIndexes.push(rangeIndex);
break;
}
if (!approved) {
removeIndexes = [];
break;
}
rangeIndex += 1;
}
if (approved) {
removeIndexes.forEach((index) => {
delete rangeFactories[index];
ranges = ranges.toSpliced(index, 1);
});
rangeFactories[ranges.push(newRange) - 1] = {
name: inlinerName,
factory
};
}
}
}
const inliners = [];
const pushTextNode = async (text2) => {
const textNode = new TextNode();
textNode.parseData = text2;
textNode.generated.autoId = createAutoId(options.autoId, null, textNode);
options.step && await options.step(textNode);
inliners.push(textNode);
};
let startText = text.slice(0, ((_a = ranges[0]) == null ? void 0 : _a.start) ?? text.length);
if (startText)
await pushTextNode(startText);
for (let i = 0; i < ranges.length; i++) {
const inlinerName = rangeFactories[i].name;
const inliner = new this.coreConfig.products[inlinerName].Node();
inliner.name = inlinerName;
const factory = rangeFactories[i].factory;
factory.productNode = inliner;
const range = ranges[i];
let afterText = text.slice(range.end, ((_b = ranges[i + 1]) == null ? void 0 : _b.start) ?? text.length);
afterText = afterText.replace(/^{(.+)}/, (match, lineMeta) => {
inliner.meta = parseMeta(lineMeta);
return "";
});
const parseText = text.slice(range.start, range.end);
try {
inliner.parseData = await factory.createParseData(parseText);
inliner.generated.autoId = createAutoId(options.autoId, factory, inliner);
options.step && await options.step(inliner);
inliners.push(inliner);
} catch (error) {
inliners.push(createErrorNode(ProductLayout.Inliner, inlinerName, parseText, error));
}
if (afterText)
await pushTextNode(afterText);
}
return inliners;
}
}
function resolveParseArgs(text, options) {
if (options == null ? void 0 : options._resolved)
return [text, options];
text = normalizeText(text);
options || (options = {});
options.autoId || (options.autoId = new DefaultAutoId());
options._resolved = true;
return [
text,
options
];
}
function prepareFactory(Factory, parser, productNode, options) {
const factory = new Factory();
factory.parser = parser;
factory.parseOptions = options;
factory.productNode = productNode;
return factory;
}
function createAutoId(autoId, factory, productNode) {
let id = autoId.generate(productNode);
if (factory)
id = factory.alterAutoId(id);
id = autoId.finalize(id);
autoId.push(id);
return id;
}
function createErrorNode(layout, name, src, error) {
const errorNode = new ErrorNode();
errorNode.layout = layout;
errorNode.name = name;
errorNode.src = src;
errorNode.error = error;
return errorNode;
}
class Stringifier {
constructor(coreConfig) {
__publicField(this, "factories", {});
for (const [productName, ProductCore] of Object.entries(coreConfig.products)) {
const Factory = ProductCore.Stringifier;
this.factories[productName] = Factory;
}
}
stringify(node, options = {}) {
const withStep = (strNode2) => {
options.step && options.step(node, strNode2);
return strNode2;
};
if (node instanceof ErrorNode)
return withStep(node.src);
if (node instanceof BlocksNode || node instanceof RootNode)
return withStep(node.children.map((childNode) => this.stringify(childNode, options)).join("\n\n"));
if (node instanceof InlinersNode)
return withStep(node.children.map((childNode) => this.stringify(childNode, options)).join(""));
const Factory = this.factories[node.name];
if (!Factory)
throw new Error(`Can't stringify unknown node type "${node.name}"!`);
const factory = new Factory();
factory.stringifier = this;
factory.strOptions = options;
factory.node = node;
const strNode = factory.stringifyNode(node);
if (node instanceof BlockNode) {
const strMeta = stringifyMeta(node.meta, true);
return withStep(strMeta + (strMeta ? "\n" : "") + strNode);
} else if (node instanceof InlinerNode) {
return withStep(strNode + stringifyMeta(node.meta, false));
}
}
}
export {
AutoId as A,
DefaultAutoId as D,
Parser as P,
Stringifier as S
};
//# sourceMappingURL=stringify-BUrbArtT.js.map