mirror of
https://github.com/borbann-platform/srs-document.git
synced 2025-12-20 04:54:06 +01:00
332 lines
11 KiB
JavaScript
332 lines
11 KiB
JavaScript
import { e, m } from "../../provides-yGf6-zdY.js";
|
|
import { match } from "@unified-latex/unified-latex-util-match";
|
|
import { decorateArrayForPegjs, SystemePegParser } from "@unified-latex/unified-latex-util-pegjs";
|
|
import { printRaw as printRaw$1 } from "@unified-latex/unified-latex-util-print-raw";
|
|
import { arrayJoin } from "@unified-latex/unified-latex-util-split";
|
|
import { s as structuredClone } from "../../index-NHd3tQDq.js";
|
|
import { deleteComments } from "@unified-latex/unified-latex-util-comments";
|
|
import { visit } from "@unified-latex/unified-latex-util-visit";
|
|
import { updateRenderInfo } from "@unified-latex/unified-latex-util-render-info";
|
|
import { getArgsContent } from "@unified-latex/unified-latex-util-arguments";
|
|
function createMatchers({
|
|
at = "@",
|
|
equals = "=",
|
|
equationSeparator = ",",
|
|
mathOperations = ["+", "-"],
|
|
whitelistedVariables
|
|
} = {}) {
|
|
let isVar = (node) => match.anyString(node) && !!node.content.match(/[a-zA-Z]/);
|
|
if (whitelistedVariables) {
|
|
whitelistedVariables = whitelistedVariables.map(
|
|
(v) => match.anyString(v) ? v.content : v
|
|
);
|
|
const macros = whitelistedVariables.filter(
|
|
(v) => match.anyMacro(v)
|
|
);
|
|
const strings = whitelistedVariables.filter(
|
|
(v) => typeof v === "string"
|
|
);
|
|
const macroHash = Object.fromEntries(macros.map((v) => [v.content, v]));
|
|
const stringHash = Object.fromEntries(strings.map((s) => [s, s]));
|
|
const macroMatcher = match.createMacroMatcher(macroHash);
|
|
isVar = (node) => macroMatcher(node) || match.anyString(node) && !!stringHash[node.content];
|
|
}
|
|
return {
|
|
isSep: (node) => match.string(node, equationSeparator),
|
|
isVar,
|
|
isOperation: (node) => mathOperations.some((op) => match.string(node, op)),
|
|
isEquals: (node) => match.string(node, equals),
|
|
isAt: (node) => match.string(node, at),
|
|
isSubscript: (node) => match.macro(node, "_") && node.escapeToken === "",
|
|
isWhitespace: match.whitespace,
|
|
isSameLineComment: (node) => match.comment(node) && node.sameline,
|
|
isOwnLineComment: (node) => match.comment(node) && !node.sameline
|
|
};
|
|
}
|
|
function parse(ast, options) {
|
|
if (!Array.isArray(ast)) {
|
|
throw new Error("You must pass an array of nodes");
|
|
}
|
|
ast = decorateArrayForPegjs([...ast]);
|
|
return SystemePegParser.parse(
|
|
ast,
|
|
createMatchers(options || {})
|
|
);
|
|
}
|
|
function printRaw(node, root = false) {
|
|
if (typeof node === "string") {
|
|
return node;
|
|
}
|
|
if (Array.isArray(node)) {
|
|
const sepToken = root ? " " : "";
|
|
return node.map((tok) => printRaw(tok)).join(sepToken);
|
|
}
|
|
switch (node.type) {
|
|
case "annotation":
|
|
return `${printRaw$1(node.marker)}${printRaw$1(
|
|
node.content
|
|
)}`;
|
|
case "item":
|
|
return `${node.op ? printRaw$1(node.op) : ""}${printRaw$1(
|
|
node.content
|
|
)}`;
|
|
case "equation":
|
|
const left = node.left.map((n) => printRaw(n)).join("");
|
|
const right = printRaw$1(node.right);
|
|
const equals = node.equals ? printRaw$1(node.equals) : "";
|
|
return `${left}${equals}${right}`;
|
|
case "line":
|
|
const equation = node.equation ? printRaw(node.equation) : "";
|
|
const annotation = node.annotation ? printRaw(node.annotation) : "";
|
|
const sep = node.sep ? printRaw$1(node.sep) : "";
|
|
const body = `${equation}${annotation}${sep}`;
|
|
if (node.trailingComment) {
|
|
return printRaw$1([body, node.trailingComment]);
|
|
}
|
|
return body;
|
|
default:
|
|
console.warn(
|
|
`Unknown node type "${node.type}" for node`,
|
|
node
|
|
);
|
|
return "";
|
|
}
|
|
}
|
|
const AMP = { type: "string", content: "&" };
|
|
const SEP = { type: "macro", content: "\\" };
|
|
const QUAD = { type: "macro", content: "quad" };
|
|
const PLUS = { type: "string", content: "+" };
|
|
const COLUMN_KERN_ADJUSTMENT = [
|
|
{ type: "string", content: "@" },
|
|
{
|
|
type: "group",
|
|
content: [
|
|
{ type: "macro", content: "mkern" },
|
|
{ type: "string", content: "5mu" }
|
|
]
|
|
}
|
|
];
|
|
function sortVariables(vars, whitelistedVariables) {
|
|
const varMap = new Map(vars.map((v) => [v, printRaw$1(v)]));
|
|
const varNames = Array.from(new Set(varMap.values()));
|
|
varNames.sort();
|
|
const nameToPos = whitelistedVariables ? new Map(whitelistedVariables.map((v, i) => [printRaw$1(v), i])) : new Map(varNames.map((name, i) => [name, i]));
|
|
return new Map(
|
|
Array.from(varMap.entries()).map(([variable, name]) => {
|
|
return [variable, nameToPos.get(name) ?? -1];
|
|
})
|
|
);
|
|
}
|
|
function processLine(line, numVars, varOrder, hasEquals, hasAnnotation) {
|
|
const ret = [];
|
|
if (line.equation) {
|
|
const nonVarItems = line.equation.left.filter(
|
|
(item) => item.variable == null
|
|
);
|
|
const varItems = line.equation.left.filter(
|
|
(item) => item.variable != null
|
|
);
|
|
let nonVarTerm = null;
|
|
if (nonVarItems.length === 1) {
|
|
nonVarTerm = nonVarItems[0];
|
|
} else if (nonVarItems.length > 1) {
|
|
nonVarTerm = {
|
|
...nonVarItems[0],
|
|
content: nonVarItems[0].content.concat(
|
|
nonVarItems.slice(1).flatMap((item) => {
|
|
if (item.op) {
|
|
return [item.op, ...item.content];
|
|
}
|
|
return [PLUS, ...item.content];
|
|
})
|
|
)
|
|
};
|
|
}
|
|
const allItems = nonVarTerm ? varItems.concat(nonVarTerm) : varItems;
|
|
const indexToItem = new Map(
|
|
allItems.map((item) => {
|
|
if (item.variable == null) {
|
|
return [numVars - 1, item];
|
|
}
|
|
return [varOrder.get(item.variable), item];
|
|
})
|
|
);
|
|
let isFirstItem = true;
|
|
for (let i = 0; i < numVars; i++) {
|
|
const item = indexToItem.get(i);
|
|
if (item) {
|
|
if (isFirstItem && (match.string(item.op, "+") || item.op == null)) {
|
|
ret.push([]);
|
|
ret.push(item.content);
|
|
} else {
|
|
ret.push([item.op || PLUS]);
|
|
ret.push(item.content);
|
|
}
|
|
isFirstItem = false;
|
|
} else {
|
|
ret.push([]);
|
|
ret.push([]);
|
|
}
|
|
}
|
|
if (hasEquals) {
|
|
const equalsPart = (line.equation.equals ? [line.equation.equals] : []).concat(line.equation.right);
|
|
ret.push(equalsPart);
|
|
}
|
|
}
|
|
if (hasAnnotation) {
|
|
ret.push(line.annotation ? line.annotation.content : []);
|
|
}
|
|
return ret;
|
|
}
|
|
function arraySpecToSpacedArraySpec(spec, hasAnnotation) {
|
|
const annotationSpec = hasAnnotation ? spec.charAt(spec.length - 1) : "";
|
|
const bodySpec = hasAnnotation ? spec.slice(0, spec.length - 1) : spec;
|
|
const bodyStrings = Array.from(bodySpec).map((x) => [
|
|
{ type: "string", content: x }
|
|
]);
|
|
const body = arrayJoin(bodyStrings, COLUMN_KERN_ADJUSTMENT);
|
|
return annotationSpec ? body.concat({ type: "string", content: annotationSpec }) : body;
|
|
}
|
|
function extractVariables(nodes) {
|
|
return nodes.flatMap((node) => {
|
|
if (node.type === "line" && node.equation) {
|
|
return extractVariables(node.equation.left);
|
|
}
|
|
if (node.type === "equation") {
|
|
return node.left.flatMap(
|
|
(item) => item.variable ? [item.variable] : []
|
|
);
|
|
}
|
|
if (node.type === "item") {
|
|
return node.variable ? [node.variable] : [];
|
|
}
|
|
return [];
|
|
});
|
|
}
|
|
function normalizeVariableWhitelist(vars) {
|
|
if (!vars) {
|
|
return null;
|
|
}
|
|
const normalized = vars.map(
|
|
(v) => typeof v === "string" ? { type: "string", content: v } : v
|
|
);
|
|
const ret = normalized.filter(
|
|
(v) => (match.anyMacro(v) || match.anyString(v)) && !match.string(v, " ") && !match.whitespace(v)
|
|
);
|
|
return ret;
|
|
}
|
|
function systemeContentsToArray(nodes, options) {
|
|
nodes = structuredClone(nodes);
|
|
deleteComments(nodes);
|
|
const { properSpacing = true, whitelistedVariables } = options || {};
|
|
const coercedWhitelistedVariables = normalizeVariableWhitelist(whitelistedVariables);
|
|
const systemeAst = parse(nodes, { whitelistedVariables });
|
|
const vars = extractVariables(systemeAst);
|
|
const varOrder = sortVariables(vars, coercedWhitelistedVariables);
|
|
let numVars = coercedWhitelistedVariables ? coercedWhitelistedVariables.length : Math.max(...Array.from(varOrder.values())) + 1;
|
|
if (systemeAst.some((line) => {
|
|
if (line.equation) {
|
|
return line.equation.left.some((item) => item.variable == null);
|
|
}
|
|
})) {
|
|
numVars += 1;
|
|
}
|
|
const hasEquals = systemeAst.some(
|
|
(line) => line.equation && line.equation.equals
|
|
);
|
|
const hasAnnotation = systemeAst.some((line) => line.annotation);
|
|
let rows = systemeAst.map(
|
|
(line) => processLine(line, numVars, varOrder, hasEquals, hasAnnotation)
|
|
);
|
|
const noLeadingOperation = rows.every((row) => row[0].length === 0);
|
|
let arraySignature = Array.from({ length: numVars }, () => "cr").join("");
|
|
if (noLeadingOperation) {
|
|
arraySignature = arraySignature.slice(1);
|
|
rows = rows.map((row) => row.slice(1));
|
|
}
|
|
if (hasEquals) {
|
|
arraySignature += "l";
|
|
}
|
|
if (hasAnnotation) {
|
|
arraySignature += "l";
|
|
rows = rows.map((row) => {
|
|
if (row[row.length - 1].length === 0) {
|
|
return row;
|
|
}
|
|
return [
|
|
...row.slice(0, row.length - 1),
|
|
[QUAD, { type: "whitespace" }, ...row[row.length - 1]]
|
|
];
|
|
});
|
|
}
|
|
const arraySignatureWithSpacing = properSpacing ? arraySpecToSpacedArraySpec(arraySignature, hasAnnotation) : [{ type: "string", content: arraySignature }];
|
|
const bodyRows = rows.map((row) => arrayJoin(row, AMP));
|
|
const body = arrayJoin(bodyRows, SEP);
|
|
const ret = {
|
|
type: "environment",
|
|
env: "array",
|
|
args: [
|
|
{
|
|
type: "argument",
|
|
openMark: "{",
|
|
closeMark: "}",
|
|
content: arraySignatureWithSpacing
|
|
}
|
|
],
|
|
content: body
|
|
};
|
|
return ret;
|
|
}
|
|
function attachSystemeSettingsAsRenderInfo(ast) {
|
|
const systemeMatcher = match.createMacroMatcher(["systeme", "sysdelim"]);
|
|
visit(
|
|
ast,
|
|
(nodes, info) => {
|
|
if (!info.context.inMathMode || !nodes.some(systemeMatcher)) {
|
|
return;
|
|
}
|
|
const systemeLocations = nodes.flatMap(
|
|
(node, i) => match.macro(node, "systeme") ? i : []
|
|
);
|
|
const sysdelimLocations = nodes.flatMap(
|
|
(node, i) => match.macro(node, "sysdelim") ? i : []
|
|
);
|
|
if (systemeLocations.length === 0 || sysdelimLocations.length === 0) {
|
|
return;
|
|
}
|
|
for (const i of systemeLocations) {
|
|
const lastSysdelim = Math.max(
|
|
...sysdelimLocations.filter((loc) => loc < i)
|
|
);
|
|
if (lastSysdelim >= 0) {
|
|
const node = nodes[i];
|
|
const sysdelimMacro = nodes[lastSysdelim];
|
|
if (!match.anyMacro(sysdelimMacro)) {
|
|
throw new Error(
|
|
`Expecting sysdelim macro but found "${printRaw$1(
|
|
sysdelimMacro
|
|
)}"`
|
|
);
|
|
}
|
|
const args = getArgsContent(sysdelimMacro);
|
|
updateRenderInfo(node, { sysdelims: args });
|
|
}
|
|
}
|
|
},
|
|
{
|
|
test: Array.isArray,
|
|
includeArrays: true
|
|
}
|
|
);
|
|
}
|
|
export {
|
|
attachSystemeSettingsAsRenderInfo,
|
|
e as environments,
|
|
extractVariables,
|
|
m as macros,
|
|
parse,
|
|
printRaw,
|
|
systemeContentsToArray
|
|
};
|
|
//# sourceMappingURL=index.js.map
|