@curvenote/schema
Version:
Schema and markdown parser for @curvenote/editor
182 lines • 6.96 kB
JavaScript
import { DEFAULT_IMAGE_WIDTH } from '../defaults';
import { nodeNames } from '../types';
import { clamp, createId } from '../utils';
export const getImageWidth = (width) => {
if (typeof width === 'number') {
return clamp(width, 10, 100);
}
const widthNum = Number.parseInt((width !== null && width !== void 0 ? width : String(DEFAULT_IMAGE_WIDTH)).replace('%', ''), 10);
return clamp(widthNum || DEFAULT_IMAGE_WIDTH, 10, 100);
};
export function readBooleanAttr(val) {
if (val == null)
return false;
if (typeof val === 'boolean')
return val;
if ((val === null || val === void 0 ? void 0 : val.toLowerCase()) === 'false')
return false;
return true;
}
export function readBooleanDomAttr(dom, attr) {
return readBooleanAttr(dom.getAttribute(attr));
}
export function convertToBooleanAttribute(value) {
return value ? '' : undefined;
}
export const getNumberedDefaultAttrs = () => ({
id: { default: null },
label: { default: null },
numbered: { default: false },
});
export function getAttr(dom, name, defaultValue = '') {
var _a;
return (_a = dom.getAttribute(name)) !== null && _a !== void 0 ? _a : defaultValue;
}
export function getNumberedAttrs(dom) {
var _a, _b;
return {
id: (_a = dom.getAttribute('id')) !== null && _a !== void 0 ? _a : null,
numbered: readBooleanDomAttr(dom, 'numbered'),
label: (_b = dom.getAttribute('label')) !== null && _b !== void 0 ? _b : null,
};
}
export function setNumberedAttrs(attrs) {
return {
id: attrs.id || undefined,
numbered: convertToBooleanAttribute(attrs.numbered),
label: attrs.label || undefined,
};
}
/**
* @param node ProsemirrorNode
* @param name Name of the node(s) to find
* @param descend go through all children of the node, default=false is only direct children
* @returns The first node with the name found
*/
export function getFirstChildWithName(node, name, descend = false) {
const names = typeof name === 'string' ? new Set([name]) : new Set(name);
let child = null;
node.descendants((n) => {
if (!child && names.has(n.type.name)) {
child = n;
}
return descend;
});
return child;
}
// TODO query the table node for it's width
export const TOTAL_TABLE_WIDTH = 886;
export function renderPColumn(width) {
if (width === 1)
return `p{\\dimexpr \\linewidth-2\\tabcolsep}`;
return `p{\\dimexpr ${width.toFixed(3)}\\linewidth-2\\tabcolsep}`;
}
/**
* given a table node, return the column widths
*
* @param node - node.type.name === 'table'
* @returns
*/
export function getColumnWidths(node) {
var _a, _b, _c;
// TODO: unsure about rowspans
let bestMaybeWidths = [];
let mostNonNulls = 0;
for (let i = 0; i < node.content.content.length; i += 1) {
const row = node.content.content[i];
const maybeWidths = row.content.content.reduce((acc, cell) => {
var _a, _b, _c;
const colwidth = new Array((_b = (_a = cell.attrs) === null || _a === void 0 ? void 0 : _a.colspan) !== null && _b !== void 0 ? _b : 1).fill(((_c = cell.attrs) === null || _c === void 0 ? void 0 : _c.colwidth) ? cell.attrs.colwidth / cell.attrs.colspan : null);
return [...acc, ...colwidth];
}, []);
const nonNulls = maybeWidths.filter((maybeWidth) => maybeWidth > 0).length;
if (i === 0 || nonNulls >= mostNonNulls) {
mostNonNulls = nonNulls;
bestMaybeWidths = maybeWidths;
if (mostNonNulls === maybeWidths.length) {
break;
}
}
}
let widths;
if (mostNonNulls === bestMaybeWidths.length) {
widths = bestMaybeWidths;
}
else {
// need to fill in the null colwidths
const totalDefinedWidths = bestMaybeWidths.reduce((acc, cur) => (cur == null ? acc : acc + cur), 0);
const remainingSpace = TOTAL_TABLE_WIDTH - totalDefinedWidths;
const nullCells = bestMaybeWidths.length - mostNonNulls;
const defaultWidth = Math.floor(remainingSpace / nullCells);
widths = bestMaybeWidths.map((w) => (w == null || w === 0 ? defaultWidth : w));
}
const total = widths.reduce((acc, cur) => acc + cur, 0);
const fractionalWidths = widths.map((w) => w / total);
const columnSpec = fractionalWidths.map((w) => renderPColumn(w)).join('');
const numColumns = widths.length > 0 ? widths.length : (_c = (_b = (_a = node === null || node === void 0 ? void 0 : node.content) === null || _a === void 0 ? void 0 : _a.firstChild) === null || _b === void 0 ? void 0 : _b.content.childCount) !== null && _c !== void 0 ? _c : 0;
return { widths: fractionalWidths, columnSpec, numColumns };
}
/** Given a node, return true if there is a fancy table descendent
*
* "fancy" means there are table_cells or table_headers with
* colspan or rowspan > 1.
*/
export function hasFancyTable(node) {
let hasRowspan = false;
let hasColspan = false;
node.descendants((n) => {
if (n.type.name === nodeNames.table_cell || n.type.name === nodeNames.table_header) {
hasRowspan = hasRowspan || (n.attrs.rowspan && Number(n.attrs.rowspan) > 1);
hasColspan = hasColspan || (n.attrs.colspan && Number(n.attrs.colspan) > 1);
}
});
return hasRowspan || hasColspan;
}
export function addMdastSnippet(state, node) {
var _a, _b, _c;
if (!state.mdastSnippets)
state.mdastSnippets = {};
if (!state.mdastSerializer)
return false;
const id = (_c = (_b = (_a = state.options).createMdastImportId) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : createId();
state.mdastSnippets[id] = state.mdastSerializer(node);
return id;
}
export function writeMdastSnippet(state, node) {
const mdastId = addMdastSnippet(state, node);
if (mdastId === false) {
// If the mdast writer isn't defined (it usually is!)
state.write('No mdast writer attached.');
state.closeBlock(node);
return false; // maybe better?
}
state.write(`\`\`\`{mdast} ${mdastId}`);
state.ensureNewLine();
state.write('```');
state.closeBlock(node);
return true;
}
// TODO: this is directly from mystjs - we should export from there instead
export function normalizeLabel(label) {
if (!label)
return undefined;
const identifier = label
.replace(/[\t\n\r ]+/g, ' ')
.trim()
.toLowerCase();
return { identifier, label };
}
/**
* Take a node and return a single flattened text value from value/children
*/
export function flattenValues(node) {
const { value, children } = node;
if (value != null) {
return value;
}
if (children) {
return children.reduce((out, child) => `${out}${flattenValues(child)}`, '');
}
return '';
}
//# sourceMappingURL=utils.js.map