prosemirror-test-builder
Version:
Helpers for programatically building ProseMirror test documents
151 lines (147 loc) • 4.84 kB
JavaScript
import { schema as schema$1 } from 'prosemirror-schema-basic';
import { addListNodes } from 'prosemirror-schema-list';
import { Node, Schema } from 'prosemirror-model';
const noTag = Node.prototype.tag = Object.create(null);
function flatten(schema, children, f) {
let result = [], pos = 0, tag = noTag;
for (let i = 0; i < children.length; i++) {
let child = children[i];
if (typeof child == "string") {
let re = /<(\w+)>/g, m, at = 0, out = "";
while (m = re.exec(child)) {
out += child.slice(at, m.index);
pos += m.index - at;
at = m.index + m[0].length;
if (tag == noTag)
tag = Object.create(null);
tag[m[1]] = pos;
}
out += child.slice(at);
pos += child.length - at;
if (out)
result.push(f(schema.text(out)));
}
else {
if (child.tag && child.tag != Node.prototype.tag) {
if (tag == noTag)
tag = Object.create(null);
for (let id in child.tag)
tag[id] = child.tag[id] + (child.flat || child.isText ? 0 : 1) + pos;
}
if (child.flat) {
for (let j = 0; j < child.flat.length; j++) {
let node = f(child.flat[j]);
pos += node.nodeSize;
result.push(node);
}
}
else {
let node = f(child);
pos += node.nodeSize;
result.push(node);
}
}
}
return { nodes: result, tag };
}
function id(x) { return x; }
function takeAttrs(attrs, args) {
let a0 = args[0];
if (!args.length || (a0 && (typeof a0 == "string" || a0 instanceof Node || a0.flat)))
return attrs;
args.shift();
if (!attrs)
return a0;
if (!a0)
return attrs;
let result = {};
for (let prop in attrs)
result[prop] = attrs[prop];
for (let prop in a0)
result[prop] = a0[prop];
return result;
}
/**
Create a builder function for nodes with content.
*/
function block(type, attrs = null) {
let result = function (...args) {
let myAttrs = takeAttrs(attrs, args);
let { nodes, tag } = flatten(type.schema, args, id);
let node = type.create(myAttrs, nodes);
if (tag != noTag)
node.tag = tag;
return node;
};
if (type.isLeaf)
try {
result.flat = [type.create(attrs)];
}
catch (_) { }
return result;
}
// Create a builder function for marks.
function mark(type, attrs) {
return function (...args) {
let mark = type.create(takeAttrs(attrs, args));
let { nodes, tag } = flatten(type.schema, args, n => {
let newMarks = mark.addToSet(n.marks);
return newMarks.length > n.marks.length ? n.mark(newMarks) : n;
});
return { flat: nodes, tag };
};
}
function builders(schema, names) {
let result = { schema };
for (let name in schema.nodes)
result[name] = block(schema.nodes[name], {});
for (let name in schema.marks)
result[name] = mark(schema.marks[name], {});
if (names)
for (let name in names) {
let value = names[name], typeName = value.nodeType || value.markType || name, type;
if (type = schema.nodes[typeName])
result[name] = block(type, value);
else if (type = schema.marks[typeName])
result[name] = mark(type, value);
}
return result;
}
const schema = new Schema({
nodes: addListNodes(schema$1.spec.nodes, "paragraph block*", "block"),
marks: schema$1.spec.marks
});
let b = builders(schema, {
p: { nodeType: "paragraph" },
pre: { nodeType: "code_block" },
h1: { nodeType: "heading", level: 1 },
h2: { nodeType: "heading", level: 2 },
h3: { nodeType: "heading", level: 3 },
li: { nodeType: "list_item" },
ul: { nodeType: "bullet_list" },
ol: { nodeType: "ordered_list" },
br: { nodeType: "hard_break" },
img: { nodeType: "image", src: "img.png" },
hr: { nodeType: "horizontal_rule" },
a: { markType: "link", href: "foo" },
});
function eq(a, b) { return a.eq(b); }
const doc = b.doc;
const p = b.p;
const code_block = b.code_block;
const pre = b.pre;
const h1 = b.h1;
const h2 = b.h2;
const h3 = b.h3;
const li = b.li;
const ul = b.ul;
const ol = b.ol;
const img = b.img;
const hr = b.hr;
const br = b.br;
const blockquote = b.blockquote;
const a = b.a;
const em = b.em;
const strong = b.strong;
const code = b.code;
export { a, blockquote, br, builders, code, code_block, doc, em, eq, h1, h2, h3, hr, img, li, ol, p, pre, schema, strong, ul };