@curvenote/schema
Version:
Schema and markdown parser for @curvenote/editor
211 lines • 9.39 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.toTex = exports.toMarkdown = void 0;
const utils_1 = require("../serialize/tex/utils");
const types_1 = require("./types");
const utils_2 = require("../process/utils");
const utils_3 = require("./utils");
const types_2 = require("../types");
const code_1 = require("./code");
const utils_4 = require("../serialize/markdown/utils");
const figure = {
group: types_1.NodeGroups.block,
content: types_1.NodeGroups.insideFigure,
isolating: true,
attrs: Object.assign(Object.assign({}, (0, utils_3.getNumberedDefaultAttrs)()), { align: { default: 'center' }, multipage: { default: false }, landscape: { default: false }, fullpage: { default: false } }),
toDOM(node) {
const { align, multipage, landscape, fullpage } = node.attrs;
return [
'figure',
Object.assign(Object.assign({}, (0, utils_3.setNumberedAttrs)(node.attrs)), { align,
multipage,
landscape,
fullpage }),
0,
];
},
parseDOM: [
{
tag: 'figure',
getAttrs(dom) {
var _a;
return Object.assign(Object.assign({}, (0, utils_3.getNumberedAttrs)(dom)), { align: (_a = dom.getAttribute('align')) !== null && _a !== void 0 ? _a : 'center', multipage: (0, utils_3.readBooleanDomAttr)(dom, 'multipage'), landscape: (0, utils_3.readBooleanDomAttr)(dom, 'landscape'), fullpage: (0, utils_3.readBooleanDomAttr)(dom, 'fullpage') });
},
},
],
attrsFromMyst: (token) => {
var _a;
const match = (_a = token.class) === null || _a === void 0 ? void 0 : _a.match(/align-(left|right|center)/);
return {
id: token.identifier || null,
label: null,
numbered: token.enumerated || false,
align: (match ? match[1] : 'center'),
multipage: false,
landscape: false,
fullpage: false,
};
},
toMyst: (props, options) => {
var _a, _b, _c, _d, _e;
let containerKind = 'figure';
(_a = props.children) === null || _a === void 0 ? void 0 : _a.forEach((child) => {
if (child.type === 'image' || child.type === 'table') {
child.align = props.align || undefined;
}
if (child.type === 'table') {
containerKind = 'table';
}
});
const localizedId = (_e = (_d = (_b = options.localizeId) === null || _b === void 0 ? void 0 : _b.call(options, (_c = props.id) !== null && _c !== void 0 ? _c : '')) !== null && _d !== void 0 ? _d : props.id) !== null && _e !== void 0 ? _e : '';
return Object.assign(Object.assign({ type: 'container', kind: containerKind }, (0, utils_3.normalizeLabel)(localizedId)), { enumerated: (0, utils_3.readBooleanAttr)(props.numbered), class: props.align ? `align-${props.align}` : undefined, children: (props.children || []) });
},
};
const toMarkdown = (state, node, parent, index) => {
var _a, _b, _c, _d, _e, _f, _g;
state.ensureNewLine();
const kind = (0, utils_2.determineCaptionKind)(node);
const { id } = node.attrs;
// TODO: Translate between callout/admonition
const caption = (0, utils_3.getFirstChildWithName)(node, types_2.nodeNames.figcaption);
state.nextCaptionId = (_d = (_c = (_b = (_a = state.options).localizeId) === null || _b === void 0 ? void 0 : _b.call(_a, id !== null && id !== void 0 ? id : '')) !== null && _c !== void 0 ? _c : id) !== null && _d !== void 0 ? _d : undefined;
switch (kind) {
case types_1.CaptionKind.fig: {
const image = (0, utils_3.getFirstChildWithName)(node, [types_2.nodeNames.image, types_2.nodeNames.iframe]);
if (!image)
return;
const { src, align, width } = image === null || image === void 0 ? void 0 : image.attrs;
const href = (_g = (_f = (_e = state.options).localizeImageSrc) === null || _f === void 0 ? void 0 : _f.call(_e, src)) !== null && _g !== void 0 ? _g : src;
if (image.type.name === types_2.nodeNames.iframe) {
state.render(image, parent, index);
return;
}
state.write(`\`\`\`{figure} ${href}\n`);
const opts = { name: state.nextCaptionId, align, width: `${width}%` };
(0, utils_4.writeDirectiveOptions)(state, opts);
if (caption) {
state.renderInline(caption);
state.ensureNewLine();
}
state.write('```');
state.closeBlock(node);
return;
}
case types_1.CaptionKind.eq: {
state.renderContent(node);
return;
}
case types_1.CaptionKind.table: {
const table = (0, utils_3.getFirstChildWithName)(node, [types_2.nodeNames.table]);
if (table && (0, utils_3.hasFancyTable)(table)) {
(0, utils_3.writeMdastSnippet)(state, node);
return;
}
state.nextTableCaption = caption;
if (table)
state.render(table, parent, index);
state.closeBlock(node);
return;
}
case types_1.CaptionKind.code: {
const code = (0, utils_3.getFirstChildWithName)(node, [types_2.nodeNames.code_block]);
// TODO: add a figure caption for code
if (code)
(0, code_1.toMarkdown)(state, code, node, index);
state.closeBlock(node);
return;
}
default:
console.log(`Unknown figure kind: "${kind}", id=${id}, children=${node.childCount}`);
return;
}
};
exports.toMarkdown = toMarkdown;
function nodeToCommand(node) {
const kind = (0, utils_2.determineCaptionKind)(node);
switch (kind) {
case types_1.CaptionKind.fig:
return node.attrs.fullpage ? 'figure*' : 'figure';
case types_1.CaptionKind.table:
return node.attrs.fullpage ? 'table*' : 'table';
case types_1.CaptionKind.code:
// TODO full width code
return 'code';
case types_1.CaptionKind.eq:
return 'figure'; // not sure what to do here.
default:
return 'figure';
}
}
function nodeToLaTeXOptions(node) {
const kind = (0, utils_2.determineCaptionKind)(node);
switch (kind) {
case types_1.CaptionKind.fig:
case types_1.CaptionKind.table:
return '!htbp';
case types_1.CaptionKind.code:
return 'H';
case types_1.CaptionKind.eq:
default:
return undefined;
}
}
function figureContainsTable(node) {
const table = node.content.content.find((n) => n.type.name === types_2.nodeNames.table);
return table;
}
exports.toTex = (0, utils_1.createLatexStatement)((state, node) => {
// if the figure is in a table, skip to child content
if (state.isInTable)
return null;
// if figure contains a table, we need find out which table environment to use
state.containsTable = false;
const table = figureContainsTable(node);
let tableInfo;
if (table && node.attrs.multipage) {
state.containsTable = true;
tableInfo = (0, utils_3.getColumnWidths)(table);
}
let before;
let after;
if (node.attrs.landscape) {
// requires pdflscape package to be loaded
before = '\\begin{landscape}';
after = '\\end{landscape}';
}
// TODO for longtable to work with two columns we need to flip out to single column first
// and then back to multi column, if we were in multicolumn mode
// Q: we can know if we are in a two column mode from the template we are using, but how is this made available at this level?
return {
command: state.containsTable && node.attrs.multipage ? 'longtable' : nodeToCommand(node),
commandOpts: state.containsTable && tableInfo ? tableInfo.columnSpec : undefined,
bracketOpts: state.containsTable ? undefined : nodeToLaTeXOptions(node),
before,
after,
};
}, (state, node) => {
var _a, _b, _c, _d;
// if the figure is in a table, skip to child content
if (state.isInTable) {
state.renderContent(node);
return;
}
const { numbered, id, multipage } = node.attrs;
const localId = (_d = (_c = (_b = (_a = state.options).localizeId) === null || _b === void 0 ? void 0 : _b.call(_a, id !== null && id !== void 0 ? id : '')) !== null && _c !== void 0 ? _c : id) !== null && _d !== void 0 ? _d : undefined;
// TODO: Based on align attr
// may have to modify string returned by state.renderContent(n);
// https://tex.stackexchange.com/questions/91566/syntax-similar-to-centering-for-right-and-left
// centering does not work in a longtable environment
if (!multipage || !state.containsTable)
state.write('\\centering');
state.ensureNewLine();
// Pass the relevant information to the child nodes
state.nextCaptionNumbered = numbered;
state.nextCaptionId = localId;
state.longFigure = multipage;
state.renderContent(node);
state.longFigure = undefined;
state.containsTable = false;
});
exports.default = figure;
//# sourceMappingURL=figure.js.map
;