From bb22b319613e09a779ca4b90f0083019bd097089 Mon Sep 17 00:00:00 2001 From: Jason Siefken Date: Tue, 14 May 2024 15:59:51 -0400 Subject: [PATCH 1/8] Initial commit --- package-lock.json | 91 +++++ packages/unified-latex-lint/README.md | 2 +- packages/unified-latex-to-pretext/README.md | 257 +++++++++++++ packages/unified-latex-to-pretext/index.ts | 62 +++ .../libs/convert-to-pretext.ts | 54 +++ .../libs/katex-support.json | 1 + .../pre-conversion-subs/environment-subs.ts | 186 +++++++++ .../libs/pre-conversion-subs/katex-subs.ts | 83 ++++ .../libs/pre-conversion-subs/macro-subs.ts | 195 ++++++++++ .../streaming-command-subs.ts | 45 +++ .../libs/pretext-subs/to-pretext-direct.ts | 62 +++ .../libs/pretext-subs/to-pretext.ts | 115 ++++++ .../libs/split-for-pars.ts | 67 ++++ .../libs/unified-latex-plugin-to-pretext.ts | 60 +++ .../libs/unified-latex-plugin-to-xml-like.ts | 153 ++++++++ .../libs/unified-latex-wrap-pars.ts | 50 +++ .../libs/wrap-pars.ts | 50 +++ .../unified-latex-to-pretext/package.json | 145 +++++++ .../tests/convert-to-pretext.test.ts | 101 +++++ .../tests/to-pretext-direct.test.ts | 27 ++ .../tests/tsconfig.json | 3 + .../tests/unified-latex-to-pretext.test.ts | 363 ++++++++++++++++++ .../tests/unified-latex-to-xml-like.test.ts | 77 ++++ .../tests/unified-latex-wrap-pars.test.ts | 53 +++ .../unified-latex-to-pretext/tsconfig.json | 8 + .../unified-latex-to-pretext/typedoc.json | 1 + .../unified-latex-to-pretext/vite.config.ts | 40 ++ packages/unified-latex-types/README.md | 4 + 28 files changed, 2354 insertions(+), 1 deletion(-) create mode 100644 packages/unified-latex-to-pretext/README.md create mode 100644 packages/unified-latex-to-pretext/index.ts create mode 100644 packages/unified-latex-to-pretext/libs/convert-to-pretext.ts create mode 120000 packages/unified-latex-to-pretext/libs/katex-support.json create mode 100644 packages/unified-latex-to-pretext/libs/pre-conversion-subs/environment-subs.ts create mode 100644 packages/unified-latex-to-pretext/libs/pre-conversion-subs/katex-subs.ts create mode 100644 packages/unified-latex-to-pretext/libs/pre-conversion-subs/macro-subs.ts create mode 100644 packages/unified-latex-to-pretext/libs/pre-conversion-subs/streaming-command-subs.ts create mode 100644 packages/unified-latex-to-pretext/libs/pretext-subs/to-pretext-direct.ts create mode 100644 packages/unified-latex-to-pretext/libs/pretext-subs/to-pretext.ts create mode 100644 packages/unified-latex-to-pretext/libs/split-for-pars.ts create mode 100644 packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-pretext.ts create mode 100644 packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-xml-like.ts create mode 100644 packages/unified-latex-to-pretext/libs/unified-latex-wrap-pars.ts create mode 100644 packages/unified-latex-to-pretext/libs/wrap-pars.ts create mode 100644 packages/unified-latex-to-pretext/package.json create mode 100644 packages/unified-latex-to-pretext/tests/convert-to-pretext.test.ts create mode 100644 packages/unified-latex-to-pretext/tests/to-pretext-direct.test.ts create mode 100644 packages/unified-latex-to-pretext/tests/tsconfig.json create mode 100644 packages/unified-latex-to-pretext/tests/unified-latex-to-pretext.test.ts create mode 100644 packages/unified-latex-to-pretext/tests/unified-latex-to-xml-like.test.ts create mode 100644 packages/unified-latex-to-pretext/tests/unified-latex-wrap-pars.test.ts create mode 100644 packages/unified-latex-to-pretext/tsconfig.json create mode 100644 packages/unified-latex-to-pretext/typedoc.json create mode 100644 packages/unified-latex-to-pretext/vite.config.ts diff --git a/package-lock.json b/package-lock.json index 042267cb..da6ada7e 100755 --- a/package-lock.json +++ b/package-lock.json @@ -2464,6 +2464,15 @@ "vfile": "*" } }, + "node_modules/@types/xast": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/xast/-/xast-2.0.4.tgz", + "integrity": "sha512-6Q6HWhHXR5EEKcxgF5YBW5XPAAtCi/GgyCWHx6wR7dZTXF5rv2B2fm0hgpSscJqaVDVm6n1DAVbsM8RSM5PlMw==", + "dev": true, + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -2509,6 +2518,10 @@ "resolved": "packages/unified-latex-to-mdast", "link": true }, + "node_modules/@unified-latex/unified-latex-to-pretext": { + "resolved": "packages/unified-latex-to-pretext", + "link": true + }, "node_modules/@unified-latex/unified-latex-types": { "resolved": "packages/unified-latex-types", "link": true @@ -16559,6 +16572,47 @@ "node": ">=6" } }, + "node_modules/xast-util-to-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xast-util-to-string/-/xast-util-to-string-3.0.0.tgz", + "integrity": "sha512-FmKJ130Fbo7SLMTLGECP0WE/bAYNC0AXeiKItv8Qk19Bb2YON09N6hbCvO4gdo4yvO4vulswCJKYQMU+Mmv+5A==", + "dev": true, + "dependencies": { + "@types/xast": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/xast-util-to-xml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xast-util-to-xml/-/xast-util-to-xml-4.0.0.tgz", + "integrity": "sha512-r1euIWS5yZJUNpfN+ReE4m7Vld2iytaOPJtuXVuRQacRZwqRN1MAb+dv0aGLrdXOZrpGLyvUFf1Upyrb3R5qBg==", + "dev": true, + "dependencies": { + "@types/xast": "^2.0.0", + "ccount": "^2.0.0", + "stringify-entities": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/xastscript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xastscript/-/xastscript-4.0.0.tgz", + "integrity": "sha512-r7a0kObEyivkML0dLrp/nOH5l51y9v5DL1MT/Xc6qUgGGNP1mZZUmT6NXtWAmx2FLfjonop++PtpVMwp1Hw/Gw==", + "dev": true, + "dependencies": { + "@types/xast": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -16882,6 +16936,43 @@ "rehype-parse": "^8.0.5" } }, + "packages/unified-latex-to-pretext": { + "name": "@unified-latex/unified-latex-to-pretext", + "version": "1.7.1", + "license": "MIT", + "dependencies": { + "@unified-latex/unified-latex": "^1.7.1", + "@unified-latex/unified-latex-builder": "^1.7.1", + "@unified-latex/unified-latex-ctan": "^1.7.1", + "@unified-latex/unified-latex-lint": "^1.7.1", + "@unified-latex/unified-latex-types": "^1.7.1", + "@unified-latex/unified-latex-util-align": "^1.7.1", + "@unified-latex/unified-latex-util-arguments": "^1.7.1", + "@unified-latex/unified-latex-util-comments": "^1.7.1", + "@unified-latex/unified-latex-util-html-like": "^1.7.1", + "@unified-latex/unified-latex-util-ligatures": "^1.7.1", + "@unified-latex/unified-latex-util-match": "^1.7.1", + "@unified-latex/unified-latex-util-print-raw": "^1.7.1", + "@unified-latex/unified-latex-util-replace": "^1.7.1", + "@unified-latex/unified-latex-util-trim": "^1.7.1", + "@unified-latex/unified-latex-util-visit": "^1.7.1", + "cssesc": "^3.0.0", + "hast": "^1.0.0", + "hastscript": "^7.2.0", + "rehype-raw": "^6.1.1", + "rehype-stringify": "^9.0.4", + "unified": "^10.1.2" + }, + "devDependencies": { + "@types/xast": "^2.0.4", + "hast-util-to-html": "^8.0.4", + "hast-util-to-string": "^3.0.0", + "prettier": "^2.8.8", + "xast-util-to-string": "^3.0.0", + "xast-util-to-xml": "^4.0.0", + "xastscript": "^4.0.0" + } + }, "packages/unified-latex-types": { "name": "@unified-latex/unified-latex-types", "version": "1.7.1", diff --git a/packages/unified-latex-lint/README.md b/packages/unified-latex-lint/README.md index 68cec17a..8020bc74 100644 --- a/packages/unified-latex-lint/README.md +++ b/packages/unified-latex-lint/README.md @@ -26,4 +26,4 @@ import the `.js` file. To explicitly access the commonjs export, import the `.cj | Name | Type | Description | | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------ | -| `lints` | `{ unifiedLatexLintArgumentColorCommands: Plugin; ... 7 more ...; unifiedLatexLintPreferSetlength: Plugin<...>; }` | Object exporting all available lints. | +| `lints` | `{ unifiedLatexLintArgumentColorCommands: Plugin; ... 7 more ...; unifiedLatexLintPreferSetlength: Plugin<...>; }` | Object exporting all available lints. | diff --git a/packages/unified-latex-to-pretext/README.md b/packages/unified-latex-to-pretext/README.md new file mode 100644 index 00000000..9df0ef19 --- /dev/null +++ b/packages/unified-latex-to-pretext/README.md @@ -0,0 +1,257 @@ + + + + +# unified-latex-to-pretext + +## What is this? + +Functions to convert `unified-latex` Abstract Syntax Tree (AST) to a XAST (xml-like) +tree in the [PreTeXt](https://pretextbook.org/) format. + +## When should I use this? + +If you want to convert LaTeX to PreTeXt for further processing with the PreTeXt compiler. + +## Controlling the PreTeXt output + +This plugin comes with presets for several common LaTeX macros/environments, but you probably want to +control how various macros evaluate yourself. For example, you may have used `\includegraphics` with `pdf`s +in your LaTeX source by want the output to reference different files. +You can accomplish this by passing `macroReplacements` (for environments, there is the similarly-named +`environmentReplacements`) to the plugin. + +For example, + +```typescript +import { unified } from "unified"; +import rehypeStringify from "rehype-stringify"; +import { htmlLike } from "@unified-latex/unified-latex-util-html-like"; +import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; +import { unifiedLatexToPretext } from "@unified-latex/unified-latex-to-pretext"; +import { unifiedLatexFromString } from "@unified-latex/unified-latex-util-parse"; +import { getArgsContent } from "@unified-latex/unified-latex-util-arguments"; + +const convert = (value) => + unified() + .use(unifiedLatexFromString) + .use(unifiedLatexToPretext, { + macroReplacements: { + includegraphics: (node) => { + const args = getArgsContent(node); + const path = printRaw( + args[args.length - 1] || [] + ).replace(/\.pdf$/, ".png"); + return htmlLike({ + tag: "img", + attributes: { src: path }, + }); + }, + }, + }) + .use(rehypeStringify) + .processSync(value).value; + +console.log(convert(`\\includegraphics{foo.pdf}`)); +``` + +`macroReplacements` and `environmentReplacements` functions can return any unified-latex `Node`, but +using the `htmlLike` utility function will return nodes that get converted to specific HTML. See `htmlLike`'s +documentation for more details. + +## Install + +```bash +npm install @unified-latex/unified-latex-to-pretext +``` + +This package contains both esm and commonjs exports. To explicitly access the esm export, +import the `.js` file. To explicitly access the commonjs export, import the `.cjs` file. + +# Plugins + +## `unifiedLatexToPretext` + +Unified plugin to convert a `unified-latex` AST into a `xast` AST representation of PreTeXt source. + +### Usage + +`unified().use(unifiedLatexToPretext[, options])` + +#### options + +```typescript +HtmlLikePluginOptions +``` + +### Type + +`Plugin` + +```typescript +function unifiedLatexToPretext( + options: HtmlLikePluginOptions +): (tree: Ast.Root, file: VFile) => Xast.Root; +``` + +where + +```typescript +type HtmlLikePluginOptions = { + /** + * Functions called to replace environments during processing. Key values should match environment names. + * You probably want to use the function `htmlLike(...)` to return a node that gets converted to specific HTML. + */ + environmentReplacements?: EnvironmentReplacements; + /** + * Functions called to replace macros during processing. Key values should match macro names. + * You probably want to use the function `htmlLike(...)` to return a node that gets converted to specific HTML. + */ + macroReplacements?: MacroReplacements; +}; +``` + +## `unifiedLatexWrapPars` + +Unified plugin to wrap paragraphs in `\html-tag:p{...}` macros. +Because `-` and `:` cannot occur in regular macros, there is no risk of +a conflict. + +### Usage + +`unified().use(unifiedLatexWrapPars[, options])` + +#### options + +```typescript +PluginOptions +``` + +### Type + +`Plugin` + +```typescript +function unifiedLatexWrapPars(options: PluginOptions): (tree: Ast.Root) => void; +``` + +## `xmlCompilePlugin` + +Unified plugin to convert a `XAST` AST to a string. + +### Usage + +`unified().use(xmlCompilePlugin)` + +### Type + +`Plugin` + +```typescript +function xmlCompilePlugin(): void; +``` + +# Functions + +## `attachNeededRenderInfo(ast)` + +Attach `renderInfo` needed for converting some macros into their +katex equivalents. + +```typescript +function attachNeededRenderInfo(ast: Ast.Ast): void; +``` + +**Parameters** + +| Param | Type | +| :---- | :-------- | +| ast | `Ast.Ast` | + +## `convertToPretext(tree, options)` + +Convert the `unified-latex` AST `tree` into an HTML string. If you need +more precise control or further processing, consider using `unified` +directly with the `unifiedLatexToPretext` plugin. + +For example, + + unified() + .use(unifiedLatexFromString) + .use(unifiedLatexToPretext) + .use(rehypeStringify) + .processSync("\\LaTeX to convert") + +```typescript +function convertToPretext( + tree: Ast.Node | Ast.Node[], + options: PluginOptions +): string; +``` + +**Parameters** + +| Param | Type | +| :------ | :----------------------- | +| tree | `Ast.Node \| Ast.Node[]` | +| options | `PluginOptions` | + +where + +```typescript +type PluginOptions = { + /** + * Functions called to replace environments during processing. Key values should match environment names. + * You probably want to use the function `htmlLike(...)` to return a node that gets converted to specific HTML. + */ + environmentReplacements?: EnvironmentReplacements; + /** + * Functions called to replace macros during processing. Key values should match macro names. + * You probably want to use the function `htmlLike(...)` to return a node that gets converted to specific HTML. + */ + macroReplacements?: MacroReplacements; +}; +``` + +## `wrapPars(nodes, options)` + +Wrap paragraphs in `

...

` tags. + +Paragraphs are inserted at + +* parbreak tokens +* macros listed in `macrosThatBreakPars` +* environments not listed in `environmentsThatDontBreakPars` + +```typescript +function wrapPars( + nodes: Ast.Node[], + options: { + macrosThatBreakPars?: string[]; + environmentsThatDontBreakPars?: string[]; + } +): Ast.Node[]; +``` + +**Parameters** + +| Param | Type | +| :------ | :-------------------------------- | +| nodes | `Ast.Node[]` | +| options | Omitted | + +# Constants + +| Name | Type | +| :------------------------------------- | :------------------------------------------------------------------ | +| `KATEX_SUPPORT` | `{ macros: any; environments: any; }` | +| `katexSpecificEnvironmentReplacements` | `Record Ast.Node \| Ast.Node[]>` | +| `katexSpecificMacroReplacements` | `Record Ast.Node \| Ast.Node[]>` | + +# Types + +## `PluginOptions` + +```typescript +export type PluginOptions = HtmlLikePluginOptions & {}; +``` diff --git a/packages/unified-latex-to-pretext/index.ts b/packages/unified-latex-to-pretext/index.ts new file mode 100644 index 00000000..2e802024 --- /dev/null +++ b/packages/unified-latex-to-pretext/index.ts @@ -0,0 +1,62 @@ +export * from "./libs/unified-latex-plugin-to-pretext"; +export * from "./libs/unified-latex-wrap-pars"; +export * from "./libs/pre-conversion-subs/katex-subs"; +export * from "./libs/wrap-pars"; +export * from "./libs/convert-to-pretext"; + +// NOTE: The docstring comment must be the last item in the index.ts file! +/** + * ## What is this? + * + * Functions to convert `unified-latex` Abstract Syntax Tree (AST) to a XAST (xml-like) + * tree in the [PreTeXt](https://pretextbook.org/) format. + * + * ## When should I use this? + * + * If you want to convert LaTeX to PreTeXt for further processing with the PreTeXt compiler. + * + * ## Controlling the PreTeXt output + * + * This plugin comes with presets for several common LaTeX macros/environments, but you probably want to + * control how various macros evaluate yourself. For example, you may have used `\includegraphics` with `pdf`s + * in your LaTeX source by want the output to reference different files. + * You can accomplish this by passing `macroReplacements` (for environments, there is the similarly-named + * `environmentReplacements`) to the plugin. + * + * For example, + * ```typescript + * import { unified } from "unified"; + * import rehypeStringify from "rehype-stringify"; + * import { htmlLike } from "@unified-latex/unified-latex-util-html-like"; + * import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; + * import { unifiedLatexToPretext } from "@unified-latex/unified-latex-to-pretext"; + * import { unifiedLatexFromString } from "@unified-latex/unified-latex-util-parse"; + * import { getArgsContent } from "@unified-latex/unified-latex-util-arguments"; + * + * const convert = (value) => + * unified() + * .use(unifiedLatexFromString) + * .use(unifiedLatexToPretext, { + * macroReplacements: { + * includegraphics: (node) => { + * const args = getArgsContent(node); + * const path = printRaw( + * args[args.length - 1] || [] + * ).replace(/\.pdf$/, ".png"); + * return htmlLike({ + * tag: "img", + * attributes: { src: path }, + * }); + * }, + * }, + * }) + * .use(rehypeStringify) + * .processSync(value).value; + * + * console.log(convert(`\\includegraphics{foo.pdf}`)); + * ``` + * + * `macroReplacements` and `environmentReplacements` functions can return any unified-latex `Node`, but + * using the `htmlLike` utility function will return nodes that get converted to specific HTML. See `htmlLike`'s + * documentation for more details. + */ diff --git a/packages/unified-latex-to-pretext/libs/convert-to-pretext.ts b/packages/unified-latex-to-pretext/libs/convert-to-pretext.ts new file mode 100644 index 00000000..b5887573 --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/convert-to-pretext.ts @@ -0,0 +1,54 @@ +import { toXml } from "xast-util-to-xml"; +import * as Ast from "@unified-latex/unified-latex-types"; +import { processLatexViaUnified } from "@unified-latex/unified-latex"; +import { + unifiedLatexToPretext, + PluginOptions, +} from "./unified-latex-plugin-to-pretext"; +import { Plugin } from "unified"; +import { Root } from "xast"; + +/** + * Unified plugin to convert a `XAST` AST to a string. + */ +export const xmlCompilePlugin: Plugin = function () { + this.Compiler = toXml; +}; + +const _processor = processLatexViaUnified() + .use(unifiedLatexToPretext) + .use(xmlCompilePlugin); + +/** + * Convert the `unified-latex` AST `tree` into an HTML string. If you need + * more precise control or further processing, consider using `unified` + * directly with the `unifiedLatexToPretext` plugin. + * + * For example, + * ``` + * unified() + * .use(unifiedLatexFromString) + * .use(unifiedLatexToPretext) + * .use(rehypeStringify) + * .processSync("\\LaTeX to convert") + * ``` + */ +export function convertToPretext( + tree: Ast.Node | Ast.Node[], + options?: PluginOptions +): string { + let processor = _processor; + if (!Array.isArray(tree) && tree.type !== "root") { + tree = { type: "root", content: [tree] }; + } + if (Array.isArray(tree)) { + tree = { type: "root", content: tree }; + } + + if (options) { + processor = _processor.use(unifiedLatexToPretext, options); + } + + const hast = processor.runSync(tree); + return processor.stringify(hast); +} diff --git a/packages/unified-latex-to-pretext/libs/katex-support.json b/packages/unified-latex-to-pretext/libs/katex-support.json new file mode 120000 index 00000000..b8546015 --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/katex-support.json @@ -0,0 +1 @@ +../../support-tables/katex-support.json \ No newline at end of file diff --git a/packages/unified-latex-to-pretext/libs/pre-conversion-subs/environment-subs.ts b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/environment-subs.ts new file mode 100644 index 00000000..e3e017a3 --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/environment-subs.ts @@ -0,0 +1,186 @@ +import cssesc from "cssesc"; +import { + parseTabularSpec, + TabularColumn, +} from "@unified-latex/unified-latex-ctan/package/tabularx"; +import { htmlLike } from "@unified-latex/unified-latex-util-html-like"; +import * as Ast from "@unified-latex/unified-latex-types"; +import { parseAlignEnvironment } from "@unified-latex/unified-latex-util-align"; +import { + getArgsContent, + getNamedArgsContent, +} from "@unified-latex/unified-latex-util-arguments"; +import { match } from "@unified-latex/unified-latex-util-match"; +import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; +import { wrapPars } from "../wrap-pars"; +import { VisitInfo } from "@unified-latex/unified-latex-util-visit"; + +const ITEM_ARG_NAMES_REG = ["label"] as const; +const ITEM_ARG_NAMES_BEAMER = [null, "label", null] as const; +type ItemArgs = Record< + (typeof ITEM_ARG_NAMES_REG)[number], + Ast.Node[] | null +> & { + body: Ast.Node[]; +}; + +/** + * Extract the arguments to an `\item` macro. + */ +function getItemArgs(node: Ast.Macro): ItemArgs { + if (!Array.isArray(node.args)) { + throw new Error( + `Cannot find \\item macros arguments; you must attach the \\item body to the macro before calling this function ${JSON.stringify( + node + )}` + ); + } + // The "body" has been added as a last argument to the `\item` node. We + // ignore this argument when comparing argument signatures. + const argNames = + node.args.length - 1 === ITEM_ARG_NAMES_BEAMER.length + ? ITEM_ARG_NAMES_BEAMER + : ITEM_ARG_NAMES_REG; + const ret = Object.assign( + { body: node.args[node.args.length - 1].content }, + getNamedArgsContent(node, argNames) + ); + return ret as ItemArgs; +} + +function enumerateFactory(parentTag = "ol", className = "enumerate") { + return function enumerateToHtml(env: Ast.Environment) { + // The body of an enumerate has already been processed and all relevant parts have + // been attached to \item macros as arguments. + const items = env.content.filter((node) => match.macro(node, "item")); + const content = items.flatMap((node) => { + if (!match.macro(node) || !node.args) { + return []; + } + + const attributes: Record> = + {}; + // Figure out if there any manually-specified item labels. If there are, + // we need to specify a custom list-style-type. + // We test the open mark to see if an optional argument was actually supplied. + const namedArgs = getItemArgs(node); + if (namedArgs.label != null) { + const formattedLabel = cssesc(printRaw(namedArgs.label || [])); + attributes.style = { + // Note the space after `formattedLabel`. That is on purpose! + "list-style-type": formattedLabel + ? `'${formattedLabel} '` + : "none", + }; + } + + const body = namedArgs.body; + return htmlLike({ + tag: "li", + content: wrapPars(body), + attributes, + }); + }); + + return htmlLike({ + tag: parentTag, + attributes: { className }, + content, + }); + }; +} + +function createCenteredElement(env: Ast.Environment) { + return htmlLike({ + tag: "center", + attributes: { className: "center" }, + content: env.content, + }); +} + +function createTableFromTabular(env: Ast.Environment) { + const tabularBody = parseAlignEnvironment(env.content); + const args = getArgsContent(env); + let columnSpecs: TabularColumn[] = []; + try { + columnSpecs = parseTabularSpec(args[1] || []); + } catch (e) {} + + const tableBody = tabularBody.map((row) => { + const content = row.cells.map((cell, i) => { + const columnSpec = columnSpecs[i]; + const styles: Record = {}; + if (columnSpec) { + const { alignment } = columnSpec; + if (alignment.alignment === "center") { + styles["text-align"] = "center"; + } + if (alignment.alignment === "right") { + styles["text-align"] = "right"; + } + if ( + columnSpec.pre_dividers.some( + (div) => div.type === "vert_divider" + ) + ) { + styles["border-left"] = "1px solid"; + } + if ( + columnSpec.post_dividers.some( + (div) => div.type === "vert_divider" + ) + ) { + styles["border-right"] = "1px solid"; + } + } + return htmlLike( + Object.keys(styles).length > 0 + ? { + tag: "td", + content: cell, + attributes: { style: styles }, + } + : { + tag: "td", + content: cell, + } + ); + }); + return htmlLike({ tag: "tr", content }); + }); + + return htmlLike({ + tag: "table", + content: [ + htmlLike({ + tag: "tbody", + content: tableBody, + }), + ], + attributes: { className: "tabular" }, + }); +} + +/** + * Rules for replacing a macro with an html-like macro + * that will render has html when printed. + */ +export const environmentReplacements: Record< + string, + ( + node: Ast.Environment, + info: VisitInfo + ) => Ast.Macro | Ast.String | Ast.Environment +> = { + enumerate: enumerateFactory("ol"), + itemize: enumerateFactory("ul", "itemize"), + center: createCenteredElement, + tabular: createTableFromTabular, + quote: (env) => { + return htmlLike({ + tag: "blockquote", + content: env.content, + attributes: { className: "environment quote" }, + }); + }, +}; diff --git a/packages/unified-latex-to-pretext/libs/pre-conversion-subs/katex-subs.ts b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/katex-subs.ts new file mode 100644 index 00000000..67e1d91f --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/katex-subs.ts @@ -0,0 +1,83 @@ +import { + attachSystemeSettingsAsRenderInfo, + systemeContentsToArray, +} from "@unified-latex/unified-latex-ctan/package/systeme"; +import * as Ast from "@unified-latex/unified-latex-types"; +import { getArgsContent } from "@unified-latex/unified-latex-util-arguments"; +import KATEX_SUPPORT_LIST from "../katex-support.json"; + +const LEFT: Ast.Macro = { type: "macro", content: "left" }; +const RIGHT: Ast.Macro = { type: "macro", content: "right" }; +const DEFAULT_LEFT_DELIM: Ast.Macro = { type: "macro", content: "{" }; +const DEFAULT_RIGHT_DELIM: Ast.String = { type: "string", content: "." }; + +export const katexSpecificMacroReplacements: Record< + string, + (node: Ast.Macro) => Ast.Node | Ast.Node[] +> = { + systeme: (node) => { + try { + const args = getArgsContent(node); + const whitelistedVariables = (args[1] || undefined) as + | (Ast.String | Ast.Macro)[] + | undefined; + const equations = args[3] || []; + const ret = systemeContentsToArray(equations, { + properSpacing: false, + whitelistedVariables, + }); + + // If we have information about the sysdelims, then apply them + if (node?._renderInfo?.sysdelims) { + const [frontDelim, backDelim]: [Ast.Node[], Ast.Node[]] = node + ._renderInfo?.sysdelims as any; + + return [ + LEFT, + ...(frontDelim || []), + ret, + RIGHT, + ...(backDelim || []), + ]; + } + + return [LEFT, DEFAULT_LEFT_DELIM, ret, RIGHT, DEFAULT_RIGHT_DELIM]; + } catch (e) { + return node; + } + }, + sysdelim: () => [], +}; + +function wrapInDisplayMath(ast: Ast.Node | Ast.Node[]): Ast.Node { + const content = Array.isArray(ast) ? ast : [ast]; + + return { type: "displaymath", content }; +} + +export const katexSpecificEnvironmentReplacements: Record< + string, + (node: Ast.Environment) => Ast.Node | Ast.Node[] +> = { + // katex supports the align environments, but it will only render them + // if you are already in math mode. Warning: these will produce invalid latex! + align: wrapInDisplayMath, + "align*": wrapInDisplayMath, + alignat: wrapInDisplayMath, + "alignat*": wrapInDisplayMath, + equation: wrapInDisplayMath, + "equation*": wrapInDisplayMath, +}; + +/** + * Attach `renderInfo` needed for converting some macros into their + * katex equivalents. + */ +export function attachNeededRenderInfo(ast: Ast.Ast) { + attachSystemeSettingsAsRenderInfo(ast); +} + +export const KATEX_SUPPORT = { + macros: KATEX_SUPPORT_LIST["KATEX_MACROS"], + environments: KATEX_SUPPORT_LIST["KATEX_ENVIRONMENTS"], +}; diff --git a/packages/unified-latex-to-pretext/libs/pre-conversion-subs/macro-subs.ts b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/macro-subs.ts new file mode 100644 index 00000000..5398ee13 --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/macro-subs.ts @@ -0,0 +1,195 @@ +import { xcolorMacroToHex } from "@unified-latex/unified-latex-ctan/package/xcolor"; +import { htmlLike } from "@unified-latex/unified-latex-util-html-like"; +import * as Ast from "@unified-latex/unified-latex-types"; +import { getArgsContent } from "@unified-latex/unified-latex-util-arguments"; +import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; +import { VisitInfo } from "@unified-latex/unified-latex-util-visit"; + +/** + * Factory function that generates html-like macros that wrap their contents. + */ +function factory( + tag: string, + attributes?: Record +): (macro: Ast.Macro) => Ast.Macro { + return (macro) => { + if (!macro.args) { + throw new Error( + `Found macro to replace but couldn't find content ${printRaw( + macro + )}` + ); + } + // Assume the meaningful argument is the last argument. This + // ensures that we can convert for default packages as well as + // packages like beamer, which may add optional arguments. + const args = getArgsContent(macro); + const content = args[args.length - 1] || []; + return htmlLike({ tag, content, attributes }); + }; +} + +function createHeading(tag: string, attrs = {}) { + return (macro: Ast.Macro) => { + const args = getArgsContent(macro); + const starred = !!args[0]; + const attributes: Record = starred + ? { className: "starred" } + : {}; + + if (attrs) { + Object.assign(attributes, attrs); + } + + return htmlLike({ + tag, + content: args[args.length - 1] || [], + attributes, + }); + }; +} + +export const macroReplacements: Record< + string, + (node: Ast.Macro, info: VisitInfo) => Ast.Node +> = { + emph: factory("em"), + textrm: factory("span", { className: "textrm" }), + textsf: factory("span", { className: "textsf" }), + texttt: factory("span", { className: "texttt" }), + textsl: factory("span", { className: "textsl" }), + textit: factory("i", { className: "textit" }), + textbf: factory("b", { className: "textbf" }), + underline: factory("span", { className: "underline" }), + mbox: factory("span", { className: "mbox" }), + phantom: factory("span", { className: "phantom" }), + part: createHeading("title"), + chapter: createHeading("title"), + section: createHeading("title"), + subsection: createHeading("title"), + subsubsection: createHeading("title"), + paragraph: createHeading("title"), + subparagraph: createHeading("title"), + appendix: createHeading("title"), + url: (node) => { + const args = getArgsContent(node); + const url = printRaw(args[0] || "#"); + return htmlLike({ + tag: "a", + attributes: { + className: "url", + href: url, + }, + content: [{ type: "string", content: url }], + }); + }, + href: (node) => { + const args = getArgsContent(node); + const url = printRaw(args[1] || "#"); + return htmlLike({ + tag: "a", + attributes: { + className: "href", + href: url, + }, + content: args[2] || [], + }); + }, + hyperref: (node) => { + const args = getArgsContent(node); + const url = "#" + printRaw(args[0] || ""); + return htmlLike({ + tag: "a", + attributes: { + className: "href", + href: url, + }, + content: args[1] || [], + }); + }, + "\\": () => + htmlLike({ + tag: "br", + attributes: { className: "linebreak" }, + }), + vspace: (node) => { + const args = getArgsContent(node); + return htmlLike({ + tag: "div", + attributes: { + className: "vspace", + "data-amount": printRaw(args[1] || []), + }, + content: [], + }); + }, + hspace: (node) => { + const args = getArgsContent(node); + return htmlLike({ + tag: "span", + attributes: { + className: "vspace", + "data-amount": printRaw(args[1] || []), + }, + content: [], + }); + }, + textcolor: (node) => { + const args = getArgsContent(node); + const computedColor = xcolorMacroToHex(node); + const color = computedColor.hex; + + if (color) { + return htmlLike({ + tag: "span", + attributes: { style: `color: ${color};` }, + content: args[2] || [], + }); + } else { + // If we couldn't compute the color, it's probably a named + // color that wasn't supplied. In this case, we fall back to a css variable + return htmlLike({ + tag: "span", + attributes: { + style: `color: var(${computedColor.cssVarName});`, + }, + content: args[2] || [], + }); + } + }, + textsize: (node) => { + const args = getArgsContent(node); + const textSize = printRaw(args[0] || []); + return htmlLike({ + tag: "span", + attributes: { + className: `textsize-${textSize}`, + }, + content: args[1] || [], + }); + }, + makebox: (node) => { + const args = getArgsContent(node); + return htmlLike({ + tag: "span", + attributes: { + className: `latex-box`, + style: "display: inline-block;", + }, + content: args[3] || [], + }); + }, + noindent: () => ({ type: "string", content: "" }), + includegraphics: (node) => { + const args = getArgsContent(node); + const src = printRaw(args[args.length - 1] || []); + return htmlLike({ + tag: "img", + attributes: { + className: "includegraphics", + src, + }, + content: [], + }); + }, +}; diff --git a/packages/unified-latex-to-pretext/libs/pre-conversion-subs/streaming-command-subs.ts b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/streaming-command-subs.ts new file mode 100644 index 00000000..49d052a7 --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/streaming-command-subs.ts @@ -0,0 +1,45 @@ +import { arg, m } from "@unified-latex/unified-latex-builder"; +import { colorToTextcolorMacro } from "@unified-latex/unified-latex-ctan/package/xcolor"; +import * as Ast from "@unified-latex/unified-latex-types"; + +/** + * Factory function that generates a macro with bound arguments. + * + * e.g. + * ``` + * factory("foo")("bar") -> `\foo{bar}` + * ``` + * + * ``` + * factory("foo", "baz")("bar") -> `\foo{baz}{bar}` + * ``` + */ +function factory( + macroName: string, + ...boundArgs: string[] +): (content: Ast.Node[], originalCommand: Ast.Macro) => Ast.Macro { + return (content, originalCommand) => { + return m(macroName, boundArgs.map((a) => arg(a)).concat(arg(content))); + }; +} + +export const streamingMacroReplacements = { + color: colorToTextcolorMacro, + bfseries: factory("textbf"), + itshape: factory("textit"), + rmfamily: factory("textrm"), + scshape: factory("textsc"), + sffamily: factory("textsf"), + slshape: factory("textsl"), + ttfamily: factory("texttt"), + Huge: factory("textsize", "Huge"), + huge: factory("textsize", "huge"), + LARGE: factory("textsize", "LARGE"), + Large: factory("textsize", "Large"), + large: factory("textsize", "large"), + normalsize: factory("textsize", "normalsize"), + small: factory("textsize", "small"), + footnotesize: factory("textsize", "footnotesize"), + scriptsize: factory("textsize", "scriptsize"), + tiny: factory("textsize", "tiny"), +}; diff --git a/packages/unified-latex-to-pretext/libs/pretext-subs/to-pretext-direct.ts b/packages/unified-latex-to-pretext/libs/pretext-subs/to-pretext-direct.ts new file mode 100644 index 00000000..851c5622 --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/pretext-subs/to-pretext-direct.ts @@ -0,0 +1,62 @@ +import * as Xast from "xast"; +import { x } from "xastscript"; +import * as Ast from "@unified-latex/unified-latex-types"; +import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; + +/** + * Direct and un-intelligent conversion of `Ast.Node` to a XAST element. + * This function is not recursive! But, it will produce an output for every input. + */ +export function toPretextDirect( + node: Ast.Node | Ast.Argument +): Xast.Element | Xast.Text | Xast.Comment { + switch (node.type) { + case "string": + return { + type: "text", + value: node.content, + position: node.position, + }; + case "comment": + return { + type: "comment", + value: node.content, + position: node.position, + }; + case "inlinemath": + return x("m", printRaw(node.content)); + case "mathenv": + case "displaymath": + return x( + "m", + { className: "display-math" }, + printRaw(node.content) + ); + case "whitespace": + return { type: "text", value: " ", position: node.position }; + case "parbreak": + return { type: "text", value: "\n", position: node.position }; + case "group": + throw new Error("Not implemented"); + case "environment": + throw new Error("Not implemented"); + case "macro": + throw new Error("Not implemented"); + case "argument": + throw new Error("Not implemented"); + case "verb": + throw new Error("Not implemented"); + case "verbatim": + throw new Error("Not implemented"); + case "root": + return x("root"); + default: { + const _exhaustiveCheck: never = node; + throw new Error( + `Unknown node type; cannot convert to HAST ${JSON.stringify( + node + )}` + ); + } + } +} diff --git a/packages/unified-latex-to-pretext/libs/pretext-subs/to-pretext.ts b/packages/unified-latex-to-pretext/libs/pretext-subs/to-pretext.ts new file mode 100644 index 00000000..c8b8fb25 --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/pretext-subs/to-pretext.ts @@ -0,0 +1,115 @@ +import * as Xast from "xast"; +import { x } from "xastscript"; +import { + extractFromHtmlLike, + isHtmlLikeTag, +} from "@unified-latex/unified-latex-util-html-like"; +import * as Ast from "@unified-latex/unified-latex-types"; +import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; + +function formatNodeForError(node: Ast.Node | any): string { + try { + return printRaw(node); + } catch {} + return JSON.stringify(node); +} + +type XastNode = Xast.Element | Xast.Text | Xast.Comment; + +/** + * Create a `toPretext` function that will log by making a call to `logger`. + */ +export function toPretextWithLoggerFactory( + logger: (message: string, node: any) => void +) { + /** + * Convert Ast.Node to Hast nodes. + */ + return function toPretext( + node: Ast.Node | Ast.Argument + ): XastNode | XastNode[] { + // Because `isHtmlLikeTag` is a type guard, if we use it directly on + // `node` here, then in the switch statement `node.type === "macro"` will be `never`. + // We rename the variable to avoid this issue. + const htmlNode = node; + if (isHtmlLikeTag(htmlNode)) { + const extracted = extractFromHtmlLike(htmlNode); + const attributes: Record = extracted.attributes; + return x( + extracted.tag, + attributes, + extracted.content.flatMap(toPretext) + ); + } + + switch (node.type) { + case "string": + return { + type: "text", + value: node.content, + position: node.position, + }; + case "comment": + return { + type: "comment", + value: node.content, + position: node.position, + }; + case "inlinemath": + return x("m", printRaw(node.content)); + case "mathenv": + case "displaymath": + return x("m", printRaw(node.content)); + case "verb": + case "verbatim": + return x("pre", { className: node.env }, node.content); + case "whitespace": + return { type: "text", value: " ", position: node.position }; + case "parbreak": + return x("br"); + case "group": + // Groups are just ignored. + return node.content.flatMap(toPretext); + case "environment": + logger( + `Unknown environment when converting to HTML \`${formatNodeForError( + node.env + )}\``, + node + ); + return x("div", node.content.flatMap(toPretext)); + case "macro": + logger( + `Unknown macro when converting to HTML \`${formatNodeForError( + node + )}\``, + node + ); + return x("span", (node.args || []).map(toPretext).flat()); + case "argument": + return x( + "span", + { + "data-open-mark": node.openMark, + "data-close-mark": node.closeMark, + }, + printRaw(node.content) + ); + case "root": + return node.content.flatMap(toPretext); + default: { + const _exhaustiveCheck: never = node; + throw new Error( + `Unknown node type; cannot convert to HAST ${JSON.stringify( + node + )}` + ); + } + } + }; +} + +/** + * Convert Ast.Node to Hast nodes. + */ +export const toPretext = toPretextWithLoggerFactory(console.warn); diff --git a/packages/unified-latex-to-pretext/libs/split-for-pars.ts b/packages/unified-latex-to-pretext/libs/split-for-pars.ts new file mode 100644 index 00000000..2d62ec5a --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/split-for-pars.ts @@ -0,0 +1,67 @@ +import * as Ast from "@unified-latex/unified-latex-types"; +import { match } from "@unified-latex/unified-latex-util-match"; +import { trim } from "@unified-latex/unified-latex-util-trim"; + +/** + * Takes an array of nodes and splits it into chunks that should be wrapped + * in HTML `

...

` tags, vs. not. By default environments are not wrapped + * unless they are specified, and macros are included in a par unless they are excluded. + * + */ +export function splitForPars( + nodes: Ast.Node[], + options: { + macrosThatBreakPars: string[]; + environmentsThatDontBreakPars: string[]; + } +): { content: Ast.Node[]; wrapInPar: boolean }[] { + const ret: { content: Ast.Node[]; wrapInPar: boolean }[] = []; + let currBody: Ast.Node[] = []; + trim(nodes); + + const isParBreakingMacro = match.createMacroMatcher( + options.macrosThatBreakPars + ); + const isEnvThatShouldNotBreakPar = match.createEnvironmentMatcher( + options.environmentsThatDontBreakPars + ); + + /** + * Push and clear the contents of `currBody` to the return array. + * If there are any contents, it should be wrapped in an array. + */ + function pushBody() { + if (currBody.length > 0) { + trim(currBody); + ret.push({ content: currBody, wrapInPar: true }); + currBody = []; + } + } + + for (const node of nodes) { + if (isParBreakingMacro(node)) { + pushBody(); + ret.push({ content: [node], wrapInPar: false }); + continue; + } + if (match.anyEnvironment(node) && !isEnvThatShouldNotBreakPar(node)) { + pushBody(); + ret.push({ content: [node], wrapInPar: false }); + continue; + } + // Display-math should always break pars + if (node.type === "displaymath") { + pushBody(); + ret.push({ content: [node], wrapInPar: false }); + continue; + } + if (match.parbreak(node) || match.macro(node, "par")) { + pushBody(); + continue; + } + currBody.push(node); + } + pushBody(); + + return ret; +} diff --git a/packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-pretext.ts b/packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-pretext.ts new file mode 100644 index 00000000..88eabd1a --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-pretext.ts @@ -0,0 +1,60 @@ +import * as Xast from "xast"; +import { x } from "xastscript"; +import { Plugin, unified } from "unified"; +import * as Ast from "@unified-latex/unified-latex-types"; +import { TypeGuard } from "@unified-latex/unified-latex-types"; +import { expandUnicodeLigatures } from "@unified-latex/unified-latex-util-ligatures"; +import { match } from "@unified-latex/unified-latex-util-match"; +import { EXIT, visit } from "@unified-latex/unified-latex-util-visit"; +import { toPretextWithLoggerFactory } from "./pretext-subs/to-pretext"; +import { + unifiedLatexToXmlLike, + PluginOptions as HtmlLikePluginOptions, +} from "./unified-latex-plugin-to-xml-like"; + +export type PluginOptions = HtmlLikePluginOptions & {}; + +/** + * Unified plugin to convert a `unified-latex` AST into a `xast` AST representation of PreTeXt source. + */ +export const unifiedLatexToPretext: Plugin< + PluginOptions[], + Ast.Root, + Xast.Root +> = function unifiedLatexAttachMacroArguments(options) { + return (tree, file) => { + unified().use(unifiedLatexToXmlLike, options).run(tree); + + // This should happen right before converting to HTML because macros like `\&` should + // be expanded via html rules first (and not turned into their corresponding ligature directly) + expandUnicodeLigatures(tree); + + // If there is a \begin{document}...\end{document}, that's the only + // content we want to convert. + let content = tree.content; + visit( + tree, + (env) => { + content = env.content; + return EXIT; + }, + { + test: ((node) => + match.environment( + node, + "document" + )) as TypeGuard, + } + ); + + const toHast = toPretextWithLoggerFactory(file.message.bind(file)); + let converted = toHast({ type: "root", content }); + if (!Array.isArray(converted)) { + converted = [converted]; + } + // Wrap everything in a Hast.Root node + let ret = x(); + ret.children = converted; + return ret; + }; +}; diff --git a/packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-xml-like.ts b/packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-xml-like.ts new file mode 100644 index 00000000..d8aeff80 --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-xml-like.ts @@ -0,0 +1,153 @@ +import * as Hast from "hast"; +import { Plugin, unified } from "unified"; +import { unifiedLatexLintNoTexFontShapingCommands } from "@unified-latex/unified-latex-lint/rules/unified-latex-lint-no-tex-font-shaping-commands"; +import * as Ast from "@unified-latex/unified-latex-types"; +import { deleteComments } from "@unified-latex/unified-latex-util-comments"; +import { match } from "@unified-latex/unified-latex-util-match"; +import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; +import { + replaceNode, + unifiedLatexReplaceStreamingCommands, +} from "@unified-latex/unified-latex-util-replace"; +import { EXIT, visit } from "@unified-latex/unified-latex-util-visit"; +import { environmentReplacements as _environmentReplacements } from "./pre-conversion-subs/environment-subs"; +import { + attachNeededRenderInfo, + katexSpecificEnvironmentReplacements, + katexSpecificMacroReplacements, +} from "./pre-conversion-subs/katex-subs"; +import { macroReplacements as _macroReplacements } from "./pre-conversion-subs/macro-subs"; +import { streamingMacroReplacements } from "./pre-conversion-subs/streaming-command-subs"; +import { unifiedLatexWrapPars } from "./unified-latex-wrap-pars"; + +type EnvironmentReplacements = typeof _environmentReplacements; +type MacroReplacements = typeof _macroReplacements; + +export type PluginOptions = { + /** + * Functions called to replace environments during processing. Key values should match environment names. + * You probably want to use the function `htmlLike(...)` to return a node that gets converted to specific HTML. + */ + environmentReplacements?: EnvironmentReplacements; + /** + * Functions called to replace macros during processing. Key values should match macro names. + * You probably want to use the function `htmlLike(...)` to return a node that gets converted to specific HTML. + */ + macroReplacements?: MacroReplacements; +}; + +/** + * Unified plugin to convert a `unified-latex` AST into an html-like AST. This replaces nodes + * with html-like macros `\html-tag:p{...}`, etc. macros. It is a step along the way to converting to HTML. + * **It is unlikely you want to use this plugin directly**. + * + * Note: this plugin only wraps paragraphs in `p` tags if there are multiple paragraphs. Otherwise it omits the

tags. + */ +export const unifiedLatexToXmlLike: Plugin< + PluginOptions[], + Ast.Root, + Hast.Root +> = function unifiedLatexToHtmlLike(options) { + const macroReplacements = Object.assign( + {}, + _macroReplacements, + options?.macroReplacements || {} + ); + const environmentReplacements = Object.assign( + {}, + _environmentReplacements, + options?.environmentReplacements || {} + ); + const isReplaceableMacro = match.createMacroMatcher(macroReplacements); + const isReplaceableEnvironment = match.createEnvironmentMatcher( + environmentReplacements + ); + const isKatexMacro = match.createMacroMatcher( + katexSpecificMacroReplacements + ); + const isKatexEnvironment = match.createEnvironmentMatcher( + katexSpecificEnvironmentReplacements + ); + + return (tree) => { + const originalTree = tree; + // NOTE: These operations need to be done in a particular order. + + // We _could_ keep comments around in html, but that can complicate dealing with whitespace, + // so we remove them. + deleteComments(tree); + let processor = unified() + // Replace `\bf` etc. with `\bfseries`. Only the latter are auto-recognized streaming commands + .use(unifiedLatexLintNoTexFontShapingCommands, { fix: true }) + .use(unifiedLatexReplaceStreamingCommands, { + replacers: streamingMacroReplacements, + }); + + // Must be done *after* streaming commands are replaced. + // We only wrap PARs if we *need* to. That is, if the content contains multiple paragraphs + if (shouldBeWrappedInPars(tree)) { + processor = processor.use(unifiedLatexWrapPars); + } + tree = processor.runSync(tree); + + // Replace text-mode environments and then macros. Environments *must* be processed first, since + // environments like tabular use `\\` as a newline indicator, but a `\\` macro gets replaced with + // a `
` during macro replacement. + replaceNode(tree, (node, info) => { + // Children of math-mode are rendered by KaTeX/MathJax and so we shouldn't touch them! + if (info.context.hasMathModeAncestor) { + return; + } + if (isReplaceableEnvironment(node)) { + return environmentReplacements[printRaw(node.env)](node, info); + } + }); + replaceNode(tree, (node, info) => { + // Children of math-mode are rendered by KaTeX/MathJax and so we shouldn't touch them! + if (info.context.hasMathModeAncestor) { + return; + } + if (isReplaceableMacro(node)) { + const replacement = macroReplacements[node.content](node, info); + return replacement; + } + }); + + // Replace math-mode macros for appropriate KaTeX rendering + attachNeededRenderInfo(tree); + replaceNode(tree, (node) => { + if (isKatexMacro(node)) { + return katexSpecificMacroReplacements[node.content](node); + } + if (isKatexEnvironment(node)) { + return katexSpecificEnvironmentReplacements[printRaw(node.env)]( + node + ); + } + }); + + // Make sure we are actually mutating the current tree. + originalTree.content = tree.content; + }; +}; + +/** + * Does the content contain multiple paragraphs? If so, it should be wrapped in `p` tags. + */ +function shouldBeWrappedInPars(tree: Ast.Root): boolean { + let content = tree.content; + visit( + tree, + (env) => { + if (match.anyEnvironment(env)) { + content = env.content; + return EXIT; + } + }, + { test: (node) => match.environment(node, "document") } + ); + + return content.some( + (node) => match.parbreak(node) || match.macro(node, "par") + ); +} diff --git a/packages/unified-latex-to-pretext/libs/unified-latex-wrap-pars.ts b/packages/unified-latex-to-pretext/libs/unified-latex-wrap-pars.ts new file mode 100644 index 00000000..49603ab1 --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/unified-latex-wrap-pars.ts @@ -0,0 +1,50 @@ +import { Plugin } from "unified"; +import * as Ast from "@unified-latex/unified-latex-types"; +import { match } from "@unified-latex/unified-latex-util-match"; +import { EXIT, visit } from "@unified-latex/unified-latex-util-visit"; +import { wrapPars } from "./wrap-pars"; + +type PluginOptions = { + macrosThatBreakPars?: string[]; + environmentsThatDontBreakPars?: string[]; +} | void; + +/** + * Unified plugin to wrap paragraphs in `\html-tag:p{...}` macros. + * Because `-` and `:` cannot occur in regular macros, there is no risk of + * a conflict. + */ +export const unifiedLatexWrapPars: Plugin = + function unifiedLatexWrapPars(options) { + const { macrosThatBreakPars, environmentsThatDontBreakPars } = + options || {}; + return (tree) => { + // If \begin{document}...\end{document} is present, we only wrap pars inside of it. + let hasDocumentEnv = false; + visit( + tree, + (env) => { + if (match.environment(env, "document")) { + hasDocumentEnv = true; + + // While we're here, we might as well wrap the pars! + env.content = wrapPars(env.content, { + macrosThatBreakPars, + environmentsThatDontBreakPars, + }); + + return EXIT; + } + }, + { test: match.anyEnvironment } + ); + + if (!hasDocumentEnv) { + // If there is no \begin{document}...\end{document}, we wrap top-level pars only. + tree.content = wrapPars(tree.content, { + macrosThatBreakPars, + environmentsThatDontBreakPars, + }); + } + }; + }; diff --git a/packages/unified-latex-to-pretext/libs/wrap-pars.ts b/packages/unified-latex-to-pretext/libs/wrap-pars.ts new file mode 100644 index 00000000..e4b83f17 --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/wrap-pars.ts @@ -0,0 +1,50 @@ +import { htmlLike } from "@unified-latex/unified-latex-util-html-like"; +import * as Ast from "@unified-latex/unified-latex-types"; +import { splitForPars } from "./split-for-pars"; + +/** + * Wrap paragraphs in `

...

` tags. + * + * Paragraphs are inserted at + * * parbreak tokens + * * macros listed in `macrosThatBreakPars` + * * environments not listed in `environmentsThatDontBreakPars` + */ +export function wrapPars( + nodes: Ast.Node[], + options?: { + macrosThatBreakPars?: string[]; + environmentsThatDontBreakPars?: string[]; + } +): Ast.Node[] { + const { + macrosThatBreakPars = [ + "part", + "chapter", + "section", + "subsection", + "subsubsection", + "paragraph", + "subparagraph", + "vspace", + "smallskip", + "medskip", + "bigskip", + "hfill", + ], + environmentsThatDontBreakPars = [], + } = options || {}; + + const parSplits = splitForPars(nodes, { + macrosThatBreakPars, + environmentsThatDontBreakPars, + }); + + return parSplits.flatMap((part) => { + if (part.wrapInPar) { + return htmlLike({ tag: "p", content: part.content }); + } else { + return part.content; + } + }); +} diff --git a/packages/unified-latex-to-pretext/package.json b/packages/unified-latex-to-pretext/package.json new file mode 100644 index 00000000..dcfaf9b3 --- /dev/null +++ b/packages/unified-latex-to-pretext/package.json @@ -0,0 +1,145 @@ +{ + "name": "@unified-latex/unified-latex-to-pretext", + "version": "1.7.1", + "description": "Convert a unified-latex AST to a PreTeXt XAST AST (for PreTeXt conversion)", + "main": "dist/index.js", + "type": "module", + "dependencies": { + "@unified-latex/unified-latex": "^1.7.1", + "@unified-latex/unified-latex-builder": "^1.7.1", + "@unified-latex/unified-latex-ctan": "^1.7.1", + "@unified-latex/unified-latex-lint": "^1.7.1", + "@unified-latex/unified-latex-types": "^1.7.1", + "@unified-latex/unified-latex-util-align": "^1.7.1", + "@unified-latex/unified-latex-util-arguments": "^1.7.1", + "@unified-latex/unified-latex-util-comments": "^1.7.1", + "@unified-latex/unified-latex-util-html-like": "^1.7.1", + "@unified-latex/unified-latex-util-ligatures": "^1.7.1", + "@unified-latex/unified-latex-util-match": "^1.7.1", + "@unified-latex/unified-latex-util-print-raw": "^1.7.1", + "@unified-latex/unified-latex-util-replace": "^1.7.1", + "@unified-latex/unified-latex-util-trim": "^1.7.1", + "@unified-latex/unified-latex-util-visit": "^1.7.1", + "cssesc": "^3.0.0", + "xastscript": "^4.0.0", + "unified": "^10.1.2" + }, + "devDependencies": { + "@types/xast": "^2.0.4", + "hast-util-to-html": "^8.0.4", + "hast-util-to-string": "^3.0.0", + "prettier": "^2.8.8", + "xast-util-to-string": "^3.0.0", + "xast-util-to-xml": "^4.0.0" + }, + "files": [ + "dist/**/*.ts", + "dist/**/*.js", + "dist/**/*.map", + "dist/**/*.json" + ], + "exports": { + ".": { + "prebuilt": "./dist/index.js", + "import": "./index.ts", + "require": "./dist/index.cjs" + }, + "./*js": "./dist/*js", + "./*": { + "prebuilt": "./dist/*.js", + "import": "./*.ts", + "require": "./dist/*.cjs" + } + }, + "scripts": { + "build": "npm run clean && mkdirp ./dist && npm run compile", + "clean": "rimraf ./dist", + "compile": "wireit", + "compile:cjs": "wireit", + "compile:esm": "wireit", + "package": "node ../../scripts/make-package.mjs", + "publish": "cd dist && npm publish", + "test": "vitest" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/siefkenj/unified-latex.git" + }, + "keywords": [ + "pegjs", + "latex", + "parser", + "prettier", + "unified-latex", + "unified" + ], + "author": "Jason Siefken", + "license": "MIT", + "bugs": { + "url": "https://github.com/siefkenj/unified-latex/issues" + }, + "homepage": "https://github.com/siefkenj/unified-latex#readme", + "private": true, + "wireit": { + "compile": { + "dependencies": [ + "compile:cjs", + "compile:esm" + ] + }, + "compile:cjs": { + "command": "vite build --mode commonjs", + "files": [ + "index.ts", + "libs/**/*.ts", + "libs/**/*.json", + "tsconfig.json", + "vite.config.ts" + ], + "output": [ + "dist/**/*.cjs*" + ], + "dependencies": [ + "deps" + ] + }, + "compile:esm": { + "command": "vite build", + "files": [ + "index.ts", + "libs/**/*.ts", + "libs/**/*.json", + "tsconfig.json", + "vite.config.ts" + ], + "output": [ + "dist/**/*.js*", + "dist/**/*.json", + "dist/**/*.d.ts", + "dist/**/*.md" + ], + "dependencies": [ + "deps" + ] + }, + "deps": { + "dependencies": [ + "../unified-latex:compile", + "../unified-latex-builder:compile", + "../unified-latex-ctan:compile", + "../unified-latex-lint:compile", + "../unified-latex-types:compile", + "../unified-latex-util-align:compile", + "../unified-latex-util-arguments:compile", + "../unified-latex-util-comments:compile", + "../unified-latex-util-html-like:compile", + "../unified-latex-util-ligatures:compile", + "../unified-latex-util-match:compile", + "../unified-latex-util-print-raw:compile", + "../unified-latex-util-replace:compile", + "../unified-latex-util-trim:compile", + "../unified-latex-util-visit:compile" + ] + } + } +} diff --git a/packages/unified-latex-to-pretext/tests/convert-to-pretext.test.ts b/packages/unified-latex-to-pretext/tests/convert-to-pretext.test.ts new file mode 100644 index 00000000..bba5f4e5 --- /dev/null +++ b/packages/unified-latex-to-pretext/tests/convert-to-pretext.test.ts @@ -0,0 +1,101 @@ +import { describe, it, expect } from "vitest"; +import Prettier from "prettier"; +import util from "util"; +import { unifiedLatexToPretext } from "../libs/unified-latex-plugin-to-pretext"; +import { htmlLike } from "@unified-latex/unified-latex-util-html-like"; +import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; +import { convertToPretext, xmlCompilePlugin } from "../libs/convert-to-pretext"; +import { Node } from "@unified-latex/unified-latex-types"; +import { + getParser, + unifiedLatexFromString, +} from "@unified-latex/unified-latex-util-parse"; +import { unified } from "unified"; +import { getArgsContent } from "@unified-latex/unified-latex-util-arguments"; + +function normalizeHtml(str: string) { + try { + return Prettier.format(str, { parser: "html" }); + } catch { + console.warn("Could not format HTML string", str); + return str; + } +} +/* eslint-env jest */ + +// Make console.log pretty-print by default +const origLog = console.log; +console.log = (...args) => { + origLog(...args.map((x) => util.inspect(x, false, 10, true))); +}; + +describe("unified-latex-to-pretext:convert-to-pretext", () => { + let html: string; + + it("custom replacers work", () => { + const process = (value: string) => + getParser({ + macros: { xxx: { signature: "m m" } }, + }).parse({ value }); + + const convert = (value: Node) => + convertToPretext(value, { + macroReplacements: { + xxx: (node) => + htmlLike({ + tag: "xxx", + attributes: Object.fromEntries( + (node.args || []).map((x, i) => [ + `arg${i}`, + printRaw(x.content), + ]) + ), + }), + textbf: (node) => + htmlLike({ + tag: "my-bold", + content: node.args?.[0]?.content || [], + }), + }, + environmentReplacements: { + yyy: (node) => + htmlLike({ tag: "yyy", content: node.content }), + }, + }); + let ast; + + ast = process(`\\xxx{a}{b}`); + expect(normalizeHtml(convert(ast))).toEqual( + normalizeHtml(``) + ); + }); + + it("full unified pipeline with custom processing", () => { + const convert = (value: string) => + unified() + .use(unifiedLatexFromString) + .use(unifiedLatexToPretext, { + macroReplacements: { + includegraphics: (node) => { + const args = getArgsContent(node); + const path = printRaw( + args[args.length - 1] || [] + ).replace(/\.pdf$/, ".png"); + return htmlLike({ + tag: "img", + attributes: { src: path }, + }); + }, + }, + }) + .use(xmlCompilePlugin) + .processSync(value).value as string; + + let ast: string; + + ast = convert(`\\includegraphics{myfile.pdf}`); + expect(normalizeHtml(ast)).toEqual( + normalizeHtml(``) + ); + }); +}); diff --git a/packages/unified-latex-to-pretext/tests/to-pretext-direct.test.ts b/packages/unified-latex-to-pretext/tests/to-pretext-direct.test.ts new file mode 100644 index 00000000..3229520b --- /dev/null +++ b/packages/unified-latex-to-pretext/tests/to-pretext-direct.test.ts @@ -0,0 +1,27 @@ +import { describe, it, expect } from "vitest"; +import { toXml } from "xast-util-to-xml"; +import util from "util"; +import { strToNodes } from "../../test-common"; +import { toPretextDirect } from "../libs/pretext-subs/to-pretext-direct"; + +// Make console.log pretty-print by default +const origLog = console.log; +console.log = (...args) => { + origLog(...args.map((x) => util.inspect(x, false, 10, true))); +}; + +describe("unified-latex-to-pretext:to-pretext-direct", () => { + it("can non-recursively convert to hast", () => { + expect(toXml(strToNodes("foo bar").map(toPretextDirect))).toEqual( + "foo bar" + ); + + expect(toXml(strToNodes("$foo bar$").map(toPretextDirect))).toEqual( + "foo bar" + ); + + expect(toXml(strToNodes("%foo").map(toPretextDirect))).toEqual( + "" + ); + }); +}); diff --git a/packages/unified-latex-to-pretext/tests/tsconfig.json b/packages/unified-latex-to-pretext/tests/tsconfig.json new file mode 100644 index 00000000..ecae1701 --- /dev/null +++ b/packages/unified-latex-to-pretext/tests/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../../tsconfig.test.json" +} diff --git a/packages/unified-latex-to-pretext/tests/unified-latex-to-pretext.test.ts b/packages/unified-latex-to-pretext/tests/unified-latex-to-pretext.test.ts new file mode 100644 index 00000000..d1e8f59d --- /dev/null +++ b/packages/unified-latex-to-pretext/tests/unified-latex-to-pretext.test.ts @@ -0,0 +1,363 @@ +import { describe, it, expect } from "vitest"; +import Prettier from "prettier"; +import util from "util"; +import { processLatexViaUnified } from "@unified-latex/unified-latex"; +import { unifiedLatexToPretext } from "../libs/unified-latex-plugin-to-pretext"; +import { htmlLike } from "@unified-latex/unified-latex-util-html-like"; +import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; +import { match } from "@unified-latex/unified-latex-util-match"; +import { xmlCompilePlugin } from "../libs/convert-to-pretext"; + +function normalizeHtml(str: string) { + try { + return Prettier.format(str, { parser: "html" }); + } catch { + console.warn("Could not format HTML string", str); + return str; + } +} +/* eslint-env jest */ + +// Make console.log pretty-print by default +const origLog = console.log; +console.log = (...args) => { + origLog(...args.map((x) => util.inspect(x, false, 10, true))); +}; + +describe("unified-latex-to-pretext:unified-latex-to-pretext", () => { + let html: string; + + const process = (value: string) => + processLatexViaUnified({ macros: { xxx: { signature: "m m" } } }) + .use(unifiedLatexToPretext) + .use(xmlCompilePlugin) + .processSync({ value }).value as string; + + it.skip("wrap pars and streaming commands", () => { + html = process("a\n\nb"); + expect(html).toEqual("

a

b

"); + + html = process("\\bfseries a\n\nb"); + expect(html).toEqual( + '

a

b

' + ); + + html = process("\\bf a\n\nb"); + expect(html).toEqual( + '

a

b

' + ); + }); + + it.skip("Can replace text-style macros", () => { + html = process(String.raw`a \textbf{different} word`); + expect(normalizeHtml(html)).toEqual( + normalizeHtml(`a different word`) + ); + + html = process(String.raw`a \textsf{different} word`); + expect(normalizeHtml(html)).toEqual( + normalizeHtml(`a different word`) + ); + + html = process(String.raw`a \textrm{different} word`); + expect(normalizeHtml(html)).toEqual( + normalizeHtml(`a different word`) + ); + + html = process(String.raw`a \emph{different} word`); + expect(normalizeHtml(html)).toEqual( + normalizeHtml(`a different word`) + ); + }); + it.skip("Can replace headings", () => { + html = process(String.raw`\chapter{My Chapter}`); + expect(normalizeHtml(html)).toEqual( + normalizeHtml(`

My Chapter

`) + ); + + html = process(String.raw`\section{My Section}`); + expect(normalizeHtml(html)).toEqual( + normalizeHtml(`My Section`) + ); + + html = process(String.raw`\section*{My Section}`); + expect(normalizeHtml(html)).toEqual( + normalizeHtml(`My Section`) + ); + }); + + it("Comments are removed from HTML", () => { + html = process(`a % foo\nb`); + expect(normalizeHtml(html)).toEqual(normalizeHtml(`a b`)); + + html = process(`a% foo\nb`); + expect(normalizeHtml(html)).toEqual(normalizeHtml(`ab`)); + + html = process(`a% foo\n\nb`); + expect(normalizeHtml(html)).toEqual(normalizeHtml(`

a

b

`)); + + html = process(`a % foo\n\nb`); + expect(normalizeHtml(html)).toEqual(normalizeHtml(`

a

b

`)); + }); + + it.skip("Wraps URLs", () => { + html = process(`a\\url{foo.com}b`); + expect(normalizeHtml(html)).toEqual( + normalizeHtml(`afoo.comb`) + ); + + html = process(`a\\href{foo.com}{FOO}b`); + expect(normalizeHtml(html)).toEqual( + normalizeHtml(`aFOOb`) + ); + }); + + it.skip("Converts enumerate environments", () => { + html = process(`\\begin{enumerate}\\item a\\item b\\end{enumerate}`); + expect(normalizeHtml(html)).toEqual( + normalizeHtml( + `
  1. a

  2. b

` + ) + ); + + // Any content before an \item is ignored + html = process( + `\\begin{enumerate}before content\\item a\\item b\\end{enumerate}` + ); + expect(normalizeHtml(html)).toEqual( + normalizeHtml( + `
  1. a

  2. b

` + ) + ); + + // Custom labels are handled + html = process( + `\\begin{enumerate}before content\\item[x)] a\\item[] b\\end{enumerate}` + ); + expect(normalizeHtml(html)).toEqual( + normalizeHtml(`
    +
  1. a

  2. +
  3. b

  4. +
`) + ); + }); + it.skip("Converts itemize environments", () => { + html = process(`\\begin{itemize}\\item a\\item b\\end{itemize}`); + expect(normalizeHtml(html)).toEqual( + normalizeHtml( + `
  • a

  • b

` + ) + ); + + // Any content before an \item is ignored + html = process( + `\\begin{itemize}before content\\item a\\item b\\end{itemize}` + ); + expect(normalizeHtml(html)).toEqual( + normalizeHtml( + `
  • a

  • b

` + ) + ); + + // Custom labels are handled + html = process( + `\\begin{itemize}before content\\item[x)] a\\item[] b\\end{itemize}` + ); + expect(normalizeHtml(html)).toEqual( + normalizeHtml(`
    +
  • a

  • +
  • b

  • +
`) + ); + }); + + it.skip("Converts tabular environment", () => { + html = process(`\\begin{tabular}{l l}a & b\\\\c & d\\end{tabular}`); + expect(normalizeHtml(html)).toEqual( + normalizeHtml( + ` + + + + + + + + + + +
ab
cd
` + ) + ); + }); + + it("Can wrap in

...

tags", () => { + html = process(`a\\par b`); + expect(normalizeHtml(html)).toEqual(normalizeHtml(`

a

b

`)); + + html = process(`a\n\n b`); + expect(normalizeHtml(html)).toEqual(normalizeHtml(`

a

b

`)); + + html = process(`a\n b\n\nc`); + expect(normalizeHtml(html)).toEqual( + normalizeHtml(`

a b

c

`) + ); + html = process(`a\\section{foo} b\n\nc`); + expect(normalizeHtml(html)).toEqual( + normalizeHtml(`

a

foo

b

c

`) + ); + html = process(`a\\section{foo} b\\section{bar}\n\nc`); + expect(normalizeHtml(html)).toEqual( + normalizeHtml( + `

a

foo

b

bar

c

` + ) + ); + html = process(`a\n \\emph{b}\n\nc`); + expect(normalizeHtml(html)).toEqual( + normalizeHtml(`

a b

c

`) + ); + html = process(`a\n b\\begin{foo}x\\end{foo}c\n\nd`); + expect(normalizeHtml(html)).toEqual( + normalizeHtml(`

a b

x

c

d

`) + ); + }); + + it.skip("Macros aren't replaced with html code in math mode", () => { + let ast; + + // Custom labels are handled + ast = process(`\\[a\\\\b\\]`); + expect(normalizeHtml(ast)).toEqual( + normalizeHtml(`
a\\\\b
`) + ); + }); + + it("Ligatures that are nested inside of math mode are not replaced", () => { + let ast; + + // Custom labels are handled + ast = process(`$a\\text{\\#}b$`); + expect(normalizeHtml(ast)).toEqual( + normalizeHtml(`a\\text{\\#}b`) + ); + }); + + it.skip("Pars are broken at display math", () => { + let ast; + + ast = process(`x\n\ny\\[a\\\\b\\]z`); + expect(normalizeHtml(ast)).toEqual( + normalizeHtml( + `

x

y

a\\\\b

z

` + ) + ); + }); + it.skip("replaces command inside argument", () => { + let ast; + + ast = process(`\\emph{\\bfseries b}`); + expect(normalizeHtml(ast)).toEqual( + normalizeHtml('b') + ); + }); + it.skip("replaces command inside enumerate", () => { + let ast; + + ast = process(`\\begin{enumerate}\\item\\bfseries b\\end{enumerate}`); + expect(normalizeHtml(ast)).toEqual( + normalizeHtml(`
    +
  1. +

    b

    +
  2. +
`) + ); + }); + it("replaces paragraphs", () => { + let ast; + + ast = process(`\\paragraph{Important.} Paragraph`); + expect(normalizeHtml(ast)).toEqual( + normalizeHtml(` + Important. Paragraph + `) + ); + }); + it("custom replacers work", () => { + const process = (value: string) => + processLatexViaUnified({ macros: { xxx: { signature: "m m" } } }) + .use(unifiedLatexToPretext, { + macroReplacements: { + xxx: (node) => + htmlLike({ + tag: "xxx", + attributes: Object.fromEntries( + (node.args || []).map((x, i) => [ + `arg${i}`, + printRaw(x.content), + ]) + ), + }), + textbf: (node) => + htmlLike({ + tag: "my-bold", + content: node.args?.[0]?.content || [], + }), + }, + environmentReplacements: { + yyy: (node) => + htmlLike({ tag: "yyy", content: node.content }), + }, + }) + .use(xmlCompilePlugin) + .processSync({ value }).value as string; + let ast; + + ast = process(`\\xxx{a}{b}`); + expect(normalizeHtml(ast)).toEqual( + normalizeHtml(``) + ); + + ast = process(`\\begin{yyy}a\\end{yyy}`); + expect(normalizeHtml(ast)).toEqual(normalizeHtml(`a`)); + + // Can override default-defined macros + ast = process(`\\textbf{a}`); + expect(normalizeHtml(ast)).toEqual( + normalizeHtml(`a`) + ); + }); + it("can use VisitInfo to render nodes differently depending on the parent", () => { + const process = (value: string) => + processLatexViaUnified() + .use(unifiedLatexToPretext, { + environmentReplacements: { + yyy: (node, info) => { + if ( + info.parents.some((x) => + match.environment(x, "yyy") + ) + ) { + return htmlLike({ + tag: "yyy-child", + content: node.content, + }); + } + return htmlLike({ + tag: "yyy", + content: node.content, + }); + }, + }, + }) + .use(xmlCompilePlugin) + .processSync({ value }).value as string; + let ast; + + ast = process( + `\\begin{yyy}a\\end{yyy}\\begin{yyy}\\begin{yyy}b\\end{yyy}c\\end{yyy}` + ); + expect(normalizeHtml(ast)).toEqual( + normalizeHtml(`abc`) + ); + }); +}); diff --git a/packages/unified-latex-to-pretext/tests/unified-latex-to-xml-like.test.ts b/packages/unified-latex-to-pretext/tests/unified-latex-to-xml-like.test.ts new file mode 100644 index 00000000..2f613e84 --- /dev/null +++ b/packages/unified-latex-to-pretext/tests/unified-latex-to-xml-like.test.ts @@ -0,0 +1,77 @@ +import { describe, it, expect } from "vitest"; +import { processLatexViaUnified } from "@unified-latex/unified-latex"; +import { VFile } from "unified-lint-rule/lib"; +import util from "util"; +import { unifiedLatexToXmlLike } from "../libs/unified-latex-plugin-to-xml-like"; +import { htmlLike } from "@unified-latex/unified-latex-util-html-like"; +import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; + +/* eslint-env jest */ + +// Make console.log pretty-print by default +const origLog = console.log; +console.log = (...args) => { + origLog(...args.map((x) => util.inspect(x, false, 10, true))); +}; + +describe("unified-latex-to-pretext:unified-latex-to-xml-like", () => { + let file: VFile; + const process = (value: string) => + processLatexViaUnified() + .use(unifiedLatexToXmlLike) + .processSync({ value }); + + it("wrap pars and streaming commands", () => { + file = process("a\n\nb"); + expect(file.value).toEqual("\\html-tag:p{a}\\html-tag:p{b}"); + + file = process("\\bfseries a\n\nb"); + expect(file.value).toEqual( + '\\html-tag:p{\\html-tag:b{\\html-attr:className{"textbf"}a}}\\html-tag:p{\\html-tag:b{\\html-attr:className{"textbf"}b}}' + ); + + file = process("\\bf a\n\nb"); + expect(file.value).toEqual( + '\\html-tag:p{\\html-tag:b{\\html-attr:className{"textbf"}a}}\\html-tag:p{\\html-tag:b{\\html-attr:className{"textbf"}b}}' + ); + + file = process( + "\\begin{enumerate}\\item foo\\item bar\\end{enumerate}" + ); + expect(file.value).toEqual( + '\\html-tag:ol{\\html-attr:className{"enumerate"}\\html-tag:li{\\html-tag:p{foo}}\\html-tag:li{\\html-tag:p{bar}}}' + ); + }); + + it("can accept custom replacers", () => { + const process = (value: string) => + processLatexViaUnified({ macros: { xxx: { signature: "m m" } } }) + .use(unifiedLatexToXmlLike, { + macroReplacements: { + xxx: (node) => + htmlLike({ + tag: "xxx", + attributes: Object.fromEntries( + (node.args || []).map((x, i) => [ + i, + printRaw(x.content), + ]) + ), + }), + }, + environmentReplacements: { + yyy: (node) => + htmlLike({ tag: "yyy", content: node.content }), + }, + }) + .processSync({ value }); + + file = process("\\xxx{a}{b}"); + expect(file.value).toEqual( + `\\html-tag:xxx{\\html-attr:0{"a"}\\html-attr:1{"b"}}` + ); + + file = process("\\begin{yyy}a\\end{yyy}"); + expect(file.value).toEqual(`\\html-tag:yyy{a}`); + }); +}); diff --git a/packages/unified-latex-to-pretext/tests/unified-latex-wrap-pars.test.ts b/packages/unified-latex-to-pretext/tests/unified-latex-wrap-pars.test.ts new file mode 100644 index 00000000..ad25a4fc --- /dev/null +++ b/packages/unified-latex-to-pretext/tests/unified-latex-wrap-pars.test.ts @@ -0,0 +1,53 @@ +import { describe, it, expect } from "vitest"; +import { processLatexViaUnified } from "@unified-latex/unified-latex"; +import { VFile } from "unified-lint-rule/lib"; +import util from "util"; +import { unifiedLatexWrapPars } from "../libs/unified-latex-wrap-pars"; + +/* eslint-env jest */ + +// Make console.log pretty-print by default +const origLog = console.log; +console.log = (...args) => { + origLog(...args.map((x) => util.inspect(x, false, 10, true))); +}; + +describe("unified-latex-to-pretext:unified-latex-wrap-pars", () => { + let file: VFile; + + it("Can wrap pars", () => { + const process = (value: string) => + processLatexViaUnified() + .use(unifiedLatexWrapPars) + .processSync({ value }); + + file = process("a\\par b"); + expect(file.value).toEqual("\\html-tag:p{a}\\html-tag:p{b}"); + + file = process("a\n\n b"); + expect(file.value).toEqual("\\html-tag:p{a}\\html-tag:p{b}"); + + file = process("a\\section{foo} b"); + expect(file.value).toEqual( + "\\html-tag:p{a}\n\\section{foo}\n\\html-tag:p{b}" + ); + + file = process("a\\section{foo} b\\section{bar}"); + expect(file.value).toEqual( + "\\html-tag:p{a}\n\\section{foo}\n\\html-tag:p{b}\n\\section{bar}" + ); + + file = process("a\n \\emph{b}"); + expect(file.value).toEqual("\\html-tag:p{a \\emph{b}}"); + + file = process("a\n b\\begin{foo}x\\end{foo}c"); + expect(file.value).toEqual( + "\\html-tag:p{a b}\n\\begin{foo}\n\tx\n\\end{foo}\\html-tag:p{c}" + ); + + file = process("a\\begin{document}b\\end{document}"); + expect(file.value).toEqual( + "a\n\\begin{document}\n\t\\html-tag:p{b}\n\\end{document}" + ); + }); +}); diff --git a/packages/unified-latex-to-pretext/tsconfig.json b/packages/unified-latex-to-pretext/tsconfig.json new file mode 100644 index 00000000..b047bba7 --- /dev/null +++ b/packages/unified-latex-to-pretext/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.build.json", + "compilerOptions": { + "outDir": "./dist/", + "rootDir": "." + }, + "include": ["./**/*.ts", "./libs/**/*.json"] +} diff --git a/packages/unified-latex-to-pretext/typedoc.json b/packages/unified-latex-to-pretext/typedoc.json new file mode 100644 index 00000000..a6b2352d --- /dev/null +++ b/packages/unified-latex-to-pretext/typedoc.json @@ -0,0 +1 @@ +{ "extends": ["../../typedoc.base.json"], "entryPoints": ["index.ts"] } diff --git a/packages/unified-latex-to-pretext/vite.config.ts b/packages/unified-latex-to-pretext/vite.config.ts new file mode 100644 index 00000000..7cee3987 --- /dev/null +++ b/packages/unified-latex-to-pretext/vite.config.ts @@ -0,0 +1,40 @@ +import { LibraryOptions, defineConfig } from "vite"; +import dts from "vite-plugin-dts"; +import { isCjsPackage } from "../../scripts/esbuild-module-check.mjs"; +import { packageReadmeAndPackageJson } from "../../scripts/vite-plugins"; + +// Any dependencies we have listed in package.json will be externalized +import packageJson from "./package.json"; +const explicitDeps = Object.keys(packageJson.dependencies || {}); + +export default defineConfig(({ mode }) => { + const formats: LibraryOptions["formats"] = + mode === "commonjs" ? ["cjs"] : ["es"]; + const externalList = + mode === "commonjs" ? explicitDeps.filter(isCjsPackage) : explicitDeps; + + const plugins = + mode === "commonjs" + ? [] + : [dts({ rollupTypes: true }), packageReadmeAndPackageJson()]; + console.log(`Building in mode: ${mode}.\n`); + + return { + plugins, + build: { + emptyOutDir: false, + minify: false, + sourcemap: true, + outDir: "dist", + lib: { + entry: "index.ts", + fileName: (format) => `index.${format === "es" ? "js" : "cjs"}`, + formats, + }, + rollupOptions: { + external: (id) => + externalList.some((dep) => id.startsWith(dep)), + }, + }, + }; +}); diff --git a/packages/unified-latex-types/README.md b/packages/unified-latex-types/README.md index 4afc6325..057b6ab0 100644 --- a/packages/unified-latex-types/README.md +++ b/packages/unified-latex-types/README.md @@ -176,6 +176,10 @@ export type MacroInfo = { * @type {boolean} */ tikzPathCommand?: boolean; + /** + * If `\sysdelims` is present, this contains the global information about the delimiters. + */ + sysdelims?: (Ast.Node[] | null)[]; }; /** * The macro signature as an xparse argument specification string. From d5cbad97efef0cb5ff28d43defffa61c7124b15b Mon Sep 17 00:00:00 2001 From: Renee <95993773+renee-k@users.noreply.github.com> Date: Wed, 12 Jun 2024 16:46:06 -0400 Subject: [PATCH 2/8] report unsupported macros by katex and expand user-define commands (#99) Report unsupported macros by katex and expand user-define commands --- .github/workflows/on-pull-request.yml | 4 +- .../expand-user-defined-macros.ts | 49 ++++++++++++ .../report-unsupported-macro-katex.ts | 27 +++++++ .../tests/expand-user-defined-macros.test.ts | 74 +++++++++++++++++++ .../report-unsupported-macro-katex.test.ts | 71 ++++++++++++++++++ 5 files changed, 223 insertions(+), 2 deletions(-) create mode 100644 packages/unified-latex-to-pretext/libs/pre-conversion-subs/expand-user-defined-macros.ts create mode 100644 packages/unified-latex-to-pretext/libs/pre-conversion-subs/report-unsupported-macro-katex.ts create mode 100644 packages/unified-latex-to-pretext/tests/expand-user-defined-macros.test.ts create mode 100644 packages/unified-latex-to-pretext/tests/report-unsupported-macro-katex.test.ts diff --git a/.github/workflows/on-pull-request.yml b/.github/workflows/on-pull-request.yml index 6b263a4f..7a41557a 100644 --- a/.github/workflows/on-pull-request.yml +++ b/.github/workflows/on-pull-request.yml @@ -2,9 +2,9 @@ name: Node.js CI on: push: - branches: ["main"] + branches: ["main", "pretext"] pull_request: - branches: ["main"] + branches: ["main", "pretext"] jobs: build: diff --git a/packages/unified-latex-to-pretext/libs/pre-conversion-subs/expand-user-defined-macros.ts b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/expand-user-defined-macros.ts new file mode 100644 index 00000000..2c241d01 --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/expand-user-defined-macros.ts @@ -0,0 +1,49 @@ +import * as Ast from "@unified-latex/unified-latex-types"; +import { + expandMacrosExcludingDefinitions, + listNewcommands, +} from "@unified-latex/unified-latex-util-macros"; +import { attachMacroArgs } from "@unified-latex/unified-latex-util-arguments"; +import { anyMacro } from "@unified-latex/unified-latex-util-match"; +import { EXIT, visit } from "@unified-latex/unified-latex-util-visit"; + +type NewCommandSpec = ReturnType[number]; + +/** + * Expands user-defined macros + */ +export function expandUserDefinedMacros(ast: Ast.Ast): void { + const newcommands = listNewcommands(ast); + + // get a set of all macros to be expanded + const macrosToExpand = new Set(newcommands.map((command) => command.name)); + + const macroInfo = Object.fromEntries( + newcommands.map((m) => [m.name, { signature: m.signature }]) + ); + + // recursively expand at most 100 times + for (let i = 0; i < 100; i++) { + // check if any macros still need expanding + if (!needToExpand(ast, macrosToExpand)) { + break; + } + + // attach the arguments to each macro before processing it + attachMacroArgs(ast, macroInfo); + expandMacrosExcludingDefinitions(ast, newcommands); + } +} + +function needToExpand(ast: Ast.Ast, macros: Set): boolean { + let needExpand = false; + + visit(ast, (node) => { + if (anyMacro(node) && macros.has(node.content)) { + needExpand = true; + EXIT; + } + }); + + return needExpand; +} diff --git a/packages/unified-latex-to-pretext/libs/pre-conversion-subs/report-unsupported-macro-katex.ts b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/report-unsupported-macro-katex.ts new file mode 100644 index 00000000..38651036 --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/report-unsupported-macro-katex.ts @@ -0,0 +1,27 @@ +import * as Ast from "@unified-latex/unified-latex-types"; +import { anyMacro, match } from "@unified-latex/unified-latex-util-match"; +import { visit } from "@unified-latex/unified-latex-util-visit"; +import { KATEX_SUPPORT } from "./katex-subs"; + +/** + * Return a list of macros used in ast that are unsupported by KaTeX + */ +export function reportMacrosUnsupportedByKatex(ast: Ast.Ast): string[] { + const unsupported: string[] = []; + + // match a macro supported by Katex + const isSupported = match.createMacroMatcher(KATEX_SUPPORT.macros); + + // visit all nodes + visit(ast, (node, info) => { + // macro in math mode + if (anyMacro(node) && info.context.hasMathModeAncestor) { + // check if not supported by katex + if (!isSupported(node)) { + unsupported.push((node as Ast.Macro).content); + } + } + }); + + return unsupported; +} diff --git a/packages/unified-latex-to-pretext/tests/expand-user-defined-macros.test.ts b/packages/unified-latex-to-pretext/tests/expand-user-defined-macros.test.ts new file mode 100644 index 00000000..6a31b1b7 --- /dev/null +++ b/packages/unified-latex-to-pretext/tests/expand-user-defined-macros.test.ts @@ -0,0 +1,74 @@ +import { describe, it, expect } from "vitest"; +import util from "util"; +import { getParser } from "@unified-latex/unified-latex-util-parse"; +import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; +import { expandUserDefinedMacros } from "@unified-latex/unified-latex-to-pretext/libs/pre-conversion-subs/expand-user-defined-macros"; + +// Make console.log pretty-print by default +const origLog = console.log; +console.log = (...args) => { + origLog(...args.map((x) => util.inspect(x, false, 10, true))); +}; + +describe("unified-latex-to-pretext:expand-user-deifned-macros", () => { + let value: string; + + it("can expand newcommand", () => { + value = String.raw`\newcommand{\foo}{\bar} \foo`; + + const parser = getParser(); + const ast = parser.parse(value); + + expandUserDefinedMacros(ast); + + expect(printRaw(ast)).toEqual(String.raw`\newcommand{\foo}{\bar} \bar`); + }); + + it("can expand renewcommand", () => { + value = String.raw`\renewcommand{\O}{\mathcal{O}} \O`; + + const parser = getParser(); + const ast = parser.parse(value); + + expandUserDefinedMacros(ast); + + expect(printRaw(ast)).toEqual( + String.raw`\renewcommand{\O}{\mathcal{O}} \mathcal{O}` + ); + }); + + it("can recursively expand multiple user-defined commands", () => { + value = + String.raw`\newcommand{\join}{\vee}` + + String.raw`\join` + + String.raw`\renewcommand{\vee}{\foo}` + + String.raw`\vee` + + String.raw`\renewcommand{\foo}{\bar}` + + String.raw`\foo`; + + const parser = getParser(); + const ast = parser.parse(value); + + expandUserDefinedMacros(ast); + + expect(printRaw(ast)).toEqual( + String.raw`\newcommand{\join}{\vee}` + + String.raw`\bar` + + String.raw`\renewcommand{\vee}{\foo}` + + String.raw`\bar` + + String.raw`\renewcommand{\foo}{\bar}` + + String.raw`\bar` + ); + }); + + it("can expand providecommand", () => { + value = String.raw`\providecommand{\bar}{\b} \bar`; + + const parser = getParser(); + const ast = parser.parse(value); + + expandUserDefinedMacros(ast); + + expect(printRaw(ast)).toEqual(String.raw`\providecommand{\bar}{\b} \b`); + }); +}); diff --git a/packages/unified-latex-to-pretext/tests/report-unsupported-macro-katex.test.ts b/packages/unified-latex-to-pretext/tests/report-unsupported-macro-katex.test.ts new file mode 100644 index 00000000..be40a3d8 --- /dev/null +++ b/packages/unified-latex-to-pretext/tests/report-unsupported-macro-katex.test.ts @@ -0,0 +1,71 @@ +import { describe, it, expect } from "vitest"; +import util from "util"; +import { getParser } from "@unified-latex/unified-latex-util-parse"; +import { reportMacrosUnsupportedByKatex } from "@unified-latex/unified-latex-to-pretext/libs/pre-conversion-subs/report-unsupported-macro-katex"; + +// Make console.log pretty-print by default +const origLog = console.log; +console.log = (...args) => { + origLog(...args.map((x) => util.inspect(x, false, 10, true))); +}; + +describe("unified-latex-to-pretext:report-unsupported-macro-katex", () => { + let value: string; + + it("can report unsupported macros in inline mathmode", () => { + value = String.raw`$\mathbb{R} \fakemacro{X}$`; + + const parser = getParser(); + const ast = parser.parse(value); + + expect(reportMacrosUnsupportedByKatex(ast)).toEqual(["fakemacro"]); + }); + + it("can report no unsupported macros in mathmode", () => { + value = String.raw`$\mathbb{R} \frac{1}{2} \cup$`; + + const parser = getParser(); + const ast = parser.parse(value); + + expect(reportMacrosUnsupportedByKatex(ast)).toEqual([]); + }); + + it("doesn't report unsupported macros outside of math mode", () => { + value = String.raw`\fakemacro`; + + const parser = getParser(); + const ast = parser.parse(value); + + expect(reportMacrosUnsupportedByKatex(ast)).toEqual([]); + }); + + it("reports unsupported macros in text mode with a math anscestor", () => { + value = String.raw`$\frac{1}{\text{ hi \unsupported}}$`; + + const parser = getParser(); + const ast = parser.parse(value); + + expect(reportMacrosUnsupportedByKatex(ast)).toEqual(["unsupported"]); + }); + + it("can report unsupported macros in display mathmode", () => { + value = String.raw`\[ \frac{a}{b} \fake \text{bar \baz}\] \bang`; + + const parser = getParser(); + const ast = parser.parse(value); + + expect(reportMacrosUnsupportedByKatex(ast)).toEqual(["fake", "baz"]); + }); + + it("can report unsupported macros in equation environment", () => { + value = String.raw`\unsupported \begin{equation} \mathbb{N} \unsupported \text{\baz}\end{equation}`; + + const parser = getParser(); + const ast = parser.parse(value); + + expect(reportMacrosUnsupportedByKatex(ast)).toEqual([ + "unsupported", + "baz", + ]); + }); +}); From 2e30cf10d0059e19edbb04dce2200a61ae276a9a Mon Sep 17 00:00:00 2001 From: Renee <95993773+renee-k@users.noreply.github.com> Date: Wed, 24 Jul 2024 15:13:25 -0400 Subject: [PATCH 3/8] Break Up LaTeX Source on Section Macros (#101) Break up a latex source by divisions (`\section` , `\subsection`, etc.) and turn those divisions into environments. E.g., `\section{foo}XXX\section{bar}YYY` becomes ``` \begin{_section}[foo]XXX\end{_section} \begin{_section}[bar]YYY\end{_section} ``` This is an intermediate step in the PreTeXt conversion. --- .../break-on-boundaries.ts | 160 ++++++++++++++++++ .../tests/break-on-boundaries.test.ts | 159 +++++++++++++++++ 2 files changed, 319 insertions(+) create mode 100644 packages/unified-latex-to-pretext/libs/pre-conversion-subs/break-on-boundaries.ts create mode 100644 packages/unified-latex-to-pretext/tests/break-on-boundaries.test.ts diff --git a/packages/unified-latex-to-pretext/libs/pre-conversion-subs/break-on-boundaries.ts b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/break-on-boundaries.ts new file mode 100644 index 00000000..83cf2b38 --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/break-on-boundaries.ts @@ -0,0 +1,160 @@ +import { env, arg } from "@unified-latex/unified-latex-builder"; +import * as Ast from "@unified-latex/unified-latex-types"; +import { getNamedArgsContent } from "@unified-latex/unified-latex-util-arguments"; +import { + anyEnvironment, + anyMacro, + match, +} from "@unified-latex/unified-latex-util-match"; +import { replaceNode } from "@unified-latex/unified-latex-util-replace"; +import { + splitOnMacro, + unsplitOnMacro, +} from "@unified-latex/unified-latex-util-split"; +import { visit } from "@unified-latex/unified-latex-util-visit"; +import { VFileMessage } from "vfile-message"; + +/** + * All the divisions, where each item is {division macro, mapped environment}. + * Note that this is ordered from the "largest" division to the "smallest" division. + */ +const divisions: { division: string; mappedEnviron: string }[] = [ + { division: "part", mappedEnviron: "_part" }, + { division: "chapter", mappedEnviron: "_chapter" }, + { division: "section", mappedEnviron: "_section" }, + { division: "subsection", mappedEnviron: "_subsection" }, + { division: "subsubsection", mappedEnviron: "_subsubsection" }, + { division: "paragraph", mappedEnviron: "_paragraph" }, + { division: "subparagraph", mappedEnviron: "_subparagraph" }, +]; + +// check if a macro is a division macro +const isDivisionMacro = match.createMacroMatcher( + divisions.map((x) => x.division) +); + +// check if an environment is a newly created environment +const isMappedEnviron = match.createEnvironmentMatcher( + divisions.map((x) => x.mappedEnviron) +); + +/** + * Breaks up division macros into environments. Returns an object of warning messages + * for any groups that were removed. + */ +export function breakOnBoundaries(ast: Ast.Ast): { messages: VFileMessage[] } { + // messages for any groups removed + const messagesLst: { messages: VFileMessage[] } = { messages: [] }; + + replaceNode(ast, (node) => { + if (match.group(node)) { + // remove if it contains a division as an immediate child + if ( + node.content.some((child) => { + return anyMacro(child) && isDivisionMacro(child); + }) + ) { + const message = new VFileMessage( + "Warning: hoisted out of a group, which might break the LaTeX code." + ); + + // add the position of the group if available + if (node.position) { + message.line = node.position.start.line; + message.column = node.position.start.column; + message.position = { + start: { + line: node.position.start.line, + column: node.position.start.column, + }, + end: { + line: node.position.end.line, + column: node.position.end.column, + }, + }; + } + + message.source = "LatexConversion"; + messagesLst.messages.push(message); + + return node.content; + } + } + }); + + visit(ast, (node, info) => { + // needs to be an environment, root, or group node + if ( + !( + anyEnvironment(node) || + node.type === "root" || + match.group(node) + ) || + // skip math mode + info.context.hasMathModeAncestor + ) { + return; + } + // if it's an environment, make sure it isn't a newly created one + else if (anyEnvironment(node) && isMappedEnviron(node)) { + return; + } + + // now break up the divisions, starting at part + node.content = breakUp(node.content, 0); + }); + + replaceNode(ast, (node) => { + // remove all old division nodes + if (anyMacro(node) && isDivisionMacro(node)) { + return null; + } + }); + + return messagesLst; +} + +/** + * Recursively breaks up the AST at the division macros. + */ +function breakUp(content: Ast.Node[], depth: number): Ast.Node[] { + // broke up all divisions + if (depth > 6) { + return content; + } + + const splits = splitOnMacro(content, divisions[depth].division); + + // go through each segment to recursively break + for (let i = 0; i < splits.segments.length; i++) { + splits.segments[i] = breakUp(splits.segments[i], depth + 1); + } + + createEnvironments(splits, divisions[depth].mappedEnviron); + + // rebuild this part of the AST + return unsplitOnMacro(splits); +} + +/** + * Create the new environments that replace the division macros. + */ +function createEnvironments( + splits: { segments: Ast.Node[][]; macros: Ast.Macro[] }, + newEnviron: string +): void { + // loop through segments (skipping first segment) + for (let i = 1; i < splits.segments.length; i++) { + // get the title + const title = getNamedArgsContent(splits.macros[i - 1])["title"]; + const titleArg: Ast.Argument[] = []; + + // create title argument + if (title) { + titleArg.push(arg(title, { braces: "[]" })); + } + + // wrap segment with a new environment + splits.segments[i] = [env(newEnviron, splits.segments[i], titleArg)]; + } +} diff --git a/packages/unified-latex-to-pretext/tests/break-on-boundaries.test.ts b/packages/unified-latex-to-pretext/tests/break-on-boundaries.test.ts new file mode 100644 index 00000000..69a16ae9 --- /dev/null +++ b/packages/unified-latex-to-pretext/tests/break-on-boundaries.test.ts @@ -0,0 +1,159 @@ +import { describe, it, expect } from "vitest"; +import util from "util"; +import { getParser } from "@unified-latex/unified-latex-util-parse"; +import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; +import { breakOnBoundaries } from "../libs/pre-conversion-subs/break-on-boundaries"; + +// Make console.log pretty-print by default +const origLog = console.log; +console.log = (...args) => { + origLog(...args.map((x) => util.inspect(x, false, 10, true))); +}; + +describe("unified-latex-to-pretext:break-on-boundaries", () => { + let value: string; + + it("can break on parts", () => { + value = String.raw`\part{Foo}Hi, this is a part\part{Bar}This is another part`; + + const parser = getParser(); + const ast = parser.parse(value); + + expect(breakOnBoundaries(ast)).toEqual({ messages: [] }); + + expect(printRaw(ast)).toEqual( + String.raw`\begin{_part}[Foo]Hi, this is a part\end{_part}\begin{_part}[Bar]This is another part\end{_part}` + ); + }); + + it("can break on a combination of divisions", () => { + value = String.raw`\part{part1}\section{Section1}Hi, this is a section\chapter{chap1}This is a chapter\section{Subsection2}`; + + const parser = getParser(); + const ast = parser.parse(value); + + expect(breakOnBoundaries(ast)).toEqual({ messages: [] }); + + expect(printRaw(ast)).toEqual( + "" + + String.raw`\begin{_part}[part1]` + + String.raw`\begin{_section}[Section1]Hi, this is a section\end{_section}` + + String.raw`\begin{_chapter}[chap1]This is a chapter` + + String.raw`\begin{_section}[Subsection2]\end{_section}\end{_chapter}\end{_part}` + ); + }); + + it("can break on divisions wrapped around by a document environment", () => { + value = String.raw`\begin{document}\section{Baz}Hi, this is a subsection\subsubsection{Foo}description.\end{document}`; + + const parser = getParser(); + const ast = parser.parse(value); + + expect(breakOnBoundaries(ast)).toEqual({ messages: [] }); + + expect(printRaw(ast)).toEqual( + String.raw`\begin{document}\begin{_section}[Baz]Hi, this is a subsection` + + String.raw`\begin{_subsubsection}[Foo]description.\end{_subsubsection}` + + String.raw`\end{_section}\end{document}` + ); + }); + + it("can break on divisions wrapped around by different environments", () => { + value = + String.raw`\begin{center}\part{name}Hi, this is a part\begin{environ}` + + String.raw`\subparagraph{title}description.\end{environ}\end{center}`; + + const parser = getParser(); + const ast = parser.parse(value); + + expect(breakOnBoundaries(ast).messages.length).toEqual(0); + + expect(printRaw(ast)).toEqual( + String.raw`\begin{center}\begin{_part}[name]Hi, this is a part` + + String.raw`\begin{environ}\begin{_subparagraph}[title]description.` + + String.raw`\end{_subparagraph}\end{environ}\end{_part}\end{center}` + ); + }); + + it("can break on divisions in a group", () => { + value = + String.raw`\begin{document}\chapter{Chap}` + + String.raw`{\paragraph{Intro}Introduction.\begin{center}\subparagraph{Conclusion}Conclusion.\end{center}}` + + String.raw`Chapter finished.\end{document}`; + + const parser = getParser(); + const ast = parser.parse(value); + + expect(breakOnBoundaries(ast).messages.length).toEqual(1); + + expect(printRaw(ast)).toEqual( + String.raw`\begin{document}\begin{_chapter}[Chap]\begin{_paragraph}[Intro]Introduction.` + + String.raw`\begin{center}\begin{_subparagraph}[Conclusion]Conclusion.\end{_subparagraph}` + + String.raw`\end{center}Chapter finished.\end{_paragraph}\end{_chapter}\end{document}` + ); + }); + + it("can break on divisions in nested groups", () => { + value = + String.raw`\part{part1}{\subsection{Intro}description.` + + String.raw`\subsubsection{body}more text.{\subparagraph{Conclusion}Conclusion.}}`; + + const parser = getParser(); + const ast = parser.parse(value); + + expect(breakOnBoundaries(ast).messages.length).toEqual(2); + + expect(printRaw(ast)).toEqual( + String.raw`\begin{_part}[part1]\begin{_subsection}[Intro]description.` + + String.raw`\begin{_subsubsection}[body]more text.\begin{_subparagraph}[Conclusion]Conclusion.` + + String.raw`\end{_subparagraph}\end{_subsubsection}\end{_subsection}\end{_part}` + ); + }); + + it("doesn't break on groups without a division as an immediate child", () => { + value = + String.raw`\part{part1}{\subsection{Intro}` + + String.raw`\subsubsection{body}{$\mathbb{N}$\subparagraph{Conclusion}{no divisions 1}Conclusion.}}{no divisions 2}`; + + const parser = getParser(); + const ast = parser.parse(value); + + expect(breakOnBoundaries(ast).messages.length).toEqual(2); + + expect(printRaw(ast)).toEqual( + String.raw`\begin{_part}[part1]\begin{_subsection}[Intro]\begin{_subsubsection}[body]` + + String.raw`$\mathbb{N}$\begin{_subparagraph}[Conclusion]{no divisions 1}Conclusion.{no divisions 2}` + + String.raw`\end{_subparagraph}\end{_subsubsection}\end{_subsection}\end{_part}` + ); + }); + + it("can break on divisions with latex in their titles", () => { + value = String.raw`\chapter{$x = \frac{1}{2}$}Chapter 1\subsection{\"name\_1\" \$}This is subsection`; + + const parser = getParser(); + const ast = parser.parse(value); + + expect(breakOnBoundaries(ast).messages.length).toEqual(0); + + expect(printRaw(ast)).toEqual( + String.raw`\begin{_chapter}[$x = \frac{1}{2}$]Chapter 1` + + String.raw`\begin{_subsection}[\"name\_1\" \$]This is subsection` + + String.raw`\end{_subsection}\end{_chapter}` + ); + }); + + it("can break on divisions and trim whitespace around division beginnings and endings", () => { + value = String.raw` \subsubsection{first}subsection 1 \paragraph{body}This is paragraph `; + + const parser = getParser(); + const ast = parser.parse(value); + + expect(breakOnBoundaries(ast).messages.length).toEqual(0); + + expect(printRaw(ast)).toEqual( + String.raw`\begin{_subsubsection}[first]subsection 1 ` + + String.raw`\begin{_paragraph}[body]This is paragraph` + + String.raw`\end{_paragraph}\end{_subsubsection}` + ); + }); +}); From 419b8dff53c81521de194b22f95bf4ff1bd519cb Mon Sep 17 00:00:00 2001 From: Bo-Y-G Date: Wed, 7 Aug 2024 13:47:35 -0700 Subject: [PATCH 4/8] [WIP] author-info (#100) Add function to extract information from the `\author{...}` tag that appears before `\begin{document}...` --- .../libs/author-info.ts | 88 ++++++++++++++ .../tests/author-info.test.ts | 111 ++++++++++++++++++ 2 files changed, 199 insertions(+) create mode 100644 packages/unified-latex-to-pretext/libs/author-info.ts create mode 100644 packages/unified-latex-to-pretext/tests/author-info.test.ts diff --git a/packages/unified-latex-to-pretext/libs/author-info.ts b/packages/unified-latex-to-pretext/libs/author-info.ts new file mode 100644 index 00000000..b80337f9 --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/author-info.ts @@ -0,0 +1,88 @@ +import * as Ast from "@unified-latex/unified-latex-types"; +import { visit } from "@unified-latex/unified-latex-util-visit"; +import { match } from "@unified-latex/unified-latex-util-match"; +import { htmlLike } from "@unified-latex/unified-latex-util-html-like"; +import { VFileMessage } from "vfile-message"; +import { VFile } from "vfile"; + +export type AuthorInfo = Record; + +/** + * Visits all the matching nodes and gathers author information, then send them to render and output pretext. + */ +export function gatherAuthorInfo(ast: Ast.Ast, file: VFile): AuthorInfo[] { + const authorList: AuthorInfo[] = []; + + visit(ast, (node) => { + if (match.macro(node, "author") && node.args) { + const authorName = Object.fromEntries( + node.args.map((x) => ["personname", x.content]) + ); + authorList.push(authorName); + } else if (match.macro(node, "address") && node.args) { + const authorAdd = Object.fromEntries( + node.args.map((x) => ["institution", x.content]) + ); + authorList.push(authorAdd); + } else if (match.macro(node, "email") && node.args) { + const authorEmail = Object.fromEntries( + node.args.map((x) => ["email", x.content]) + ); + authorList.push(authorEmail); + } else if (match.macro(node, "affil")) { + const message = createVFileMessage(node); + file.message( + message, + message.position, + "latex-to-pretext:warning" + ) + } + }); + return authorList; +} + +/** + * This function is called after the author information is collected, and integrate them into one htmlLike node with "author" tag. + */ +export function renderCollectedAuthorInfo(authorList: AuthorInfo[]): Ast.Macro { + let authorInfo: Ast.Macro[] = []; + for (const info of authorList) { + for (const key in info) { + const renderInfo = htmlLike({ + tag: key, + content: info[key], + }); + authorInfo.push(renderInfo); + } + } + const renderedAuthorList = htmlLike({ + tag: "author", + content: authorInfo, + }); + return renderedAuthorList; +} + +function createVFileMessage(node: Ast.Macro): VFileMessage { + const message = new VFileMessage( + `Macro \"${node.content}\" is not supported` + ); + + // add the position of the macro if available + if (node.position) { + message.line = node.position.start.line; + message.column = node.position.start.column; + message.position = { + start: { + line: node.position.start.line, + column: node.position.start.column, + }, + end: { + line: node.position.end.line, + column: node.position.end.column, + }, + }; + } + + message.source = "latex-to-pretext:warning"; + return message; +} diff --git a/packages/unified-latex-to-pretext/tests/author-info.test.ts b/packages/unified-latex-to-pretext/tests/author-info.test.ts new file mode 100644 index 00000000..54eda6f8 --- /dev/null +++ b/packages/unified-latex-to-pretext/tests/author-info.test.ts @@ -0,0 +1,111 @@ +import { describe, it, expect } from "vitest"; +import Prettier from "prettier"; +import util from "util"; +import { getParser } from "@unified-latex/unified-latex-util-parse"; +import { toXml } from "xast-util-to-xml"; +import { xmlCompilePlugin } from "../libs/convert-to-pretext"; +import { unified } from "unified"; +import { + gatherAuthorInfo, + renderCollectedAuthorInfo, +} from "../libs/author-info"; +import { VFile } from "vfile"; +import { toPretextWithLoggerFactory } from "../libs/pretext-subs/to-pretext"; + +function normalizeHtml(str: string) { + try { + return Prettier.format(str, { parser: "html" }); + } catch { + console.warn("Could not format HTML string", str); + return str; + } +} +/* eslint-env jest */ + +// Make console.log pretty-print by default +const origLog = console.log; +console.log = (...args) => { + origLog(...args.map((x) => util.inspect(x, false, 10, true))); +}; + +describe("unified-latex-to-pretext:author-info", () => { + let sample: string; + const parser = getParser(); + let file: VFile; + + it("collects author name, address, institution, and email information", () => { + file = new VFile(); + sample = + "\\author{First Middle LastName} \n \\address{Department, Address}"; + let input = " First Middle LastName"; + let input1 = + " \n Department, Address"; + expect(gatherAuthorInfo(parser.parse(sample), file)).toEqual([ + { personname: parser.parse(input).content }, + { institution: parser.parse(input1).content }, + ]); + + sample = "\\address{Affiliation}"; + input = " Affiliation"; + expect(gatherAuthorInfo(parser.parse(sample), file)).toEqual([ + { institution: parser.parse(input).content }, + ]); + + sample = "\\affil{Affiliation}"; + expect(gatherAuthorInfo(parser.parse(sample), file)).toEqual([]); + + sample = + "\\author{First Author} \\email{example@example.com} \\author{Second Author}"; + input = " First Author"; + input1 = " example@example.com"; + let input2 = + " Second Author"; + expect(gatherAuthorInfo(parser.parse(sample), file)).toEqual([ + { personname: parser.parse(input).content }, + { email: parser.parse(input1).content }, + { personname: parser.parse(input2).content }, + ]); + }); + + it("parses author name, address, and email information", () => { + sample = + "\\author{First Middle LastName} \n \\address{Department, Address}"; + let rendered = renderCollectedAuthorInfo( + gatherAuthorInfo(parser.parse(sample), file) + ); + const toXast = toPretextWithLoggerFactory(file.message.bind(file)); + const xxx = unified() + .use(xmlCompilePlugin) + .runSync({ type: "root", children: [toXast(rendered)].flat() }); + expect(normalizeHtml(toXml(xxx))).toEqual( + normalizeHtml( + "First Middle LastNameDepartment, Address" + ) + ); + + sample = "\\address{Affiliation}"; + rendered = renderCollectedAuthorInfo( + gatherAuthorInfo(parser.parse(sample), file) + ); + const xxx1 = unified() + .use(xmlCompilePlugin) + .runSync({ type: "root", children: [toXast(rendered)].flat() }); + expect(normalizeHtml(toXml(xxx1))).toEqual( + normalizeHtml("Affiliation") + ); + + sample = + "\\author{First Author} \\email{example@example.com} \\author{Second Author}"; + rendered = renderCollectedAuthorInfo( + gatherAuthorInfo(parser.parse(sample), file) + ); + const xxx2 = unified() + .use(xmlCompilePlugin) + .runSync({ type: "root", children: [toXast(rendered)].flat() }); + expect(normalizeHtml(toXml(xxx2))).toEqual( + normalizeHtml( + "First Authorexample@example.comSecond Author" + ) + ); + }); +}); From 27e9fbfd1b037d89e60ff8de81453419905a7580 Mon Sep 17 00:00:00 2001 From: Renee <95993773+renee-k@users.noreply.github.com> Date: Thu, 15 Aug 2024 15:46:29 -0400 Subject: [PATCH 5/8] Fix the skipped test cases in the PreTeXt package (#103) Necessary macro subs and environment subs to create valid PreTeXt from LaTeX. --- .../break-on-boundaries.ts | 33 +--- .../create-table-from-tabular.ts | 111 +++++++++++ .../pre-conversion-subs/environment-subs.ts | 148 +++++--------- .../libs/pre-conversion-subs/macro-subs.ts | 185 ++++++++--------- .../report-unsupported-macro-katex.ts | 19 +- .../libs/pre-conversion-subs/utils.ts | 46 +++++ .../libs/pretext-subs/to-pretext.ts | 96 +++++++-- .../libs/split-for-pars.ts | 6 - ...> unified-latex-plugin-to-pretext-like.ts} | 186 ++++++++++++++++-- .../libs/unified-latex-plugin-to-pretext.ts | 49 ++++- .../libs/unified-latex-wrap-pars.ts | 16 +- .../tests/convert-to-pretext.test.ts | 2 + .../report-unsupported-macro-katex.test.ts | 15 +- .../tests/unified-latex-to-pretext.test.ts | 149 +++++++------- .../tests/unified-latex-to-xml-like.test.ts | 15 +- 15 files changed, 699 insertions(+), 377 deletions(-) create mode 100644 packages/unified-latex-to-pretext/libs/pre-conversion-subs/create-table-from-tabular.ts create mode 100644 packages/unified-latex-to-pretext/libs/pre-conversion-subs/utils.ts rename packages/unified-latex-to-pretext/libs/{unified-latex-plugin-to-xml-like.ts => unified-latex-plugin-to-pretext-like.ts} (51%) diff --git a/packages/unified-latex-to-pretext/libs/pre-conversion-subs/break-on-boundaries.ts b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/break-on-boundaries.ts index 83cf2b38..be9684cb 100644 --- a/packages/unified-latex-to-pretext/libs/pre-conversion-subs/break-on-boundaries.ts +++ b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/break-on-boundaries.ts @@ -13,12 +13,13 @@ import { } from "@unified-latex/unified-latex-util-split"; import { visit } from "@unified-latex/unified-latex-util-visit"; import { VFileMessage } from "vfile-message"; +import { makeWarningMessage } from "./utils"; /** * All the divisions, where each item is {division macro, mapped environment}. * Note that this is ordered from the "largest" division to the "smallest" division. */ -const divisions: { division: string; mappedEnviron: string }[] = [ +export const divisions: { division: string; mappedEnviron: string }[] = [ { division: "part", mappedEnviron: "_part" }, { division: "chapter", mappedEnviron: "_chapter" }, { division: "section", mappedEnviron: "_section" }, @@ -34,7 +35,7 @@ const isDivisionMacro = match.createMacroMatcher( ); // check if an environment is a newly created environment -const isMappedEnviron = match.createEnvironmentMatcher( +export const isMappedEnviron = match.createEnvironmentMatcher( divisions.map((x) => x.mappedEnviron) ); @@ -54,29 +55,15 @@ export function breakOnBoundaries(ast: Ast.Ast): { messages: VFileMessage[] } { return anyMacro(child) && isDivisionMacro(child); }) ) { - const message = new VFileMessage( - "Warning: hoisted out of a group, which might break the LaTeX code." + // add a warning message + messagesLst.messages.push( + makeWarningMessage( + node, + "Warning: hoisted out of a group, which might break the LaTeX code.", + "break-on-boundaries" + ) ); - // add the position of the group if available - if (node.position) { - message.line = node.position.start.line; - message.column = node.position.start.column; - message.position = { - start: { - line: node.position.start.line, - column: node.position.start.column, - }, - end: { - line: node.position.end.line, - column: node.position.end.column, - }, - }; - } - - message.source = "LatexConversion"; - messagesLst.messages.push(message); - return node.content; } } diff --git a/packages/unified-latex-to-pretext/libs/pre-conversion-subs/create-table-from-tabular.ts b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/create-table-from-tabular.ts new file mode 100644 index 00000000..e51494ab --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/create-table-from-tabular.ts @@ -0,0 +1,111 @@ +import * as Ast from "@unified-latex/unified-latex-types"; +import { htmlLike } from "@unified-latex/unified-latex-util-html-like"; +import { + parseTabularSpec, + TabularColumn, +} from "@unified-latex/unified-latex-ctan/package/tabularx"; +import { parseAlignEnvironment } from "@unified-latex/unified-latex-util-align"; +import { getArgsContent } from "@unified-latex/unified-latex-util-arguments"; +import { trim } from "@unified-latex/unified-latex-util-trim"; + +type Attributes = Record>; + +/** + * Convert env into a tabular in PreTeXt. + */ +export function createTableFromTabular(env: Ast.Environment) { + const tabularBody = parseAlignEnvironment(env.content); + const args = getArgsContent(env); + let columnSpecs: TabularColumn[] = []; + try { + columnSpecs = parseTabularSpec(args[1] || []); + } catch (e) {} + + // for the tabular tag + const attributes: Attributes = {}; + + // we only need the col tags if one of the columns aren't left aligned/have a border + let notLeftAligned: boolean = false; + + // stores which columns have borders to the right + // number is the column's index in columnSpecs + const columnRightBorder: Record = {}; + + const tableBody = tabularBody.map((row) => { + const content = row.cells.map((cell, i) => { + const columnSpec = columnSpecs[i]; + + if (columnSpec) { + const { alignment } = columnSpec; + + // this will need to be in the tabular tag + if ( + columnSpec.pre_dividers.some( + (div) => div.type === "vert_divider" + ) + ) { + attributes["left"] = "minor"; + } + + // check if the column has a right border + if ( + columnSpec.post_dividers.some( + (div) => div.type === "vert_divider" + ) + ) { + columnRightBorder[i] = true; + } + + // check if the default alignment isn't used + if (alignment.alignment !== "left") { + notLeftAligned = true; + } + } + + // trim whitespace off cell + trim(cell); + + return htmlLike({ + tag: "cell", + content: cell, + }); + }); + return htmlLike({ tag: "row", content }); + }); + + // add col tags if needed + if (notLeftAligned || Object.values(columnRightBorder).some((b) => b)) { + // go backwards since adding col tags to the front of the tableBody list + // otherwise, col tags will be in the reversed order + for (let i = columnSpecs.length; i >= 0; i--) { + const columnSpec = columnSpecs[i]; + + if (!columnSpec) { + continue; + } + + const colAttributes: Attributes = {}; + const { alignment } = columnSpec; + + // add h-align attribute if not default + if (alignment.alignment !== "left") { + colAttributes["halign"] = alignment.alignment; + } + + // if there is a right border add it + if (columnRightBorder[i] === true) { + colAttributes["right"] = "minor"; + } + + tableBody.unshift( + htmlLike({ tag: "col", attributes: colAttributes }) + ); + } + } + + return htmlLike({ + tag: "tabular", + content: tableBody, + attributes: attributes, + }); +} diff --git a/packages/unified-latex-to-pretext/libs/pre-conversion-subs/environment-subs.ts b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/environment-subs.ts index e3e017a3..7f6ab9a6 100644 --- a/packages/unified-latex-to-pretext/libs/pre-conversion-subs/environment-subs.ts +++ b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/environment-subs.ts @@ -1,19 +1,12 @@ -import cssesc from "cssesc"; -import { - parseTabularSpec, - TabularColumn, -} from "@unified-latex/unified-latex-ctan/package/tabularx"; import { htmlLike } from "@unified-latex/unified-latex-util-html-like"; import * as Ast from "@unified-latex/unified-latex-types"; -import { parseAlignEnvironment } from "@unified-latex/unified-latex-util-align"; -import { - getArgsContent, - getNamedArgsContent, -} from "@unified-latex/unified-latex-util-arguments"; +import { getNamedArgsContent } from "@unified-latex/unified-latex-util-arguments"; import { match } from "@unified-latex/unified-latex-util-match"; -import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; import { wrapPars } from "../wrap-pars"; import { VisitInfo } from "@unified-latex/unified-latex-util-visit"; +import { VFile } from "vfile"; +import { makeWarningMessage } from "./utils"; +import { createTableFromTabular } from "./create-table-from-tabular"; const ITEM_ARG_NAMES_REG = ["label"] as const; const ITEM_ARG_NAMES_BEAMER = [null, "label", null] as const; @@ -48,139 +41,92 @@ function getItemArgs(node: Ast.Macro): ItemArgs { return ret as ItemArgs; } -function enumerateFactory(parentTag = "ol", className = "enumerate") { +function enumerateFactory(parentTag = "ol") { return function enumerateToHtml(env: Ast.Environment) { // The body of an enumerate has already been processed and all relevant parts have // been attached to \item macros as arguments. const items = env.content.filter((node) => match.macro(node, "item")); + + // Figure out if there any manually-specified item labels. If there are, + // we need to add a title tag + let isDescriptionList = false; + const content = items.flatMap((node) => { if (!match.macro(node) || !node.args) { return []; } - const attributes: Record> = - {}; - // Figure out if there any manually-specified item labels. If there are, - // we need to specify a custom list-style-type. // We test the open mark to see if an optional argument was actually supplied. const namedArgs = getItemArgs(node); + + // if there are custom markers, don't want the title tag to be wrapped in pars + // so we wrap the body first + namedArgs.body = wrapPars(namedArgs.body); + + // check if a custom marker is used if (namedArgs.label != null) { - const formattedLabel = cssesc(printRaw(namedArgs.label || [])); - attributes.style = { - // Note the space after `formattedLabel`. That is on purpose! - "list-style-type": formattedLabel - ? `'${formattedLabel} '` - : "none", - }; + isDescriptionList = true; + + // add title tag containing custom marker + namedArgs.body.unshift( + htmlLike({ + tag: "title", + content: namedArgs.label, + }) + ); } const body = namedArgs.body; + return htmlLike({ tag: "li", - content: wrapPars(body), - attributes, + content: body, }); }); return htmlLike({ - tag: parentTag, - attributes: { className }, + tag: isDescriptionList ? "dl" : parentTag, content, }); }; } -function createCenteredElement(env: Ast.Environment) { - return htmlLike({ - tag: "center", - attributes: { className: "center" }, - content: env.content, - }); -} - -function createTableFromTabular(env: Ast.Environment) { - const tabularBody = parseAlignEnvironment(env.content); - const args = getArgsContent(env); - let columnSpecs: TabularColumn[] = []; - try { - columnSpecs = parseTabularSpec(args[1] || []); - } catch (e) {} - - const tableBody = tabularBody.map((row) => { - const content = row.cells.map((cell, i) => { - const columnSpec = columnSpecs[i]; - const styles: Record = {}; - if (columnSpec) { - const { alignment } = columnSpec; - if (alignment.alignment === "center") { - styles["text-align"] = "center"; - } - if (alignment.alignment === "right") { - styles["text-align"] = "right"; - } - if ( - columnSpec.pre_dividers.some( - (div) => div.type === "vert_divider" - ) - ) { - styles["border-left"] = "1px solid"; - } - if ( - columnSpec.post_dividers.some( - (div) => div.type === "vert_divider" - ) - ) { - styles["border-right"] = "1px solid"; - } - } - return htmlLike( - Object.keys(styles).length > 0 - ? { - tag: "td", - content: cell, - attributes: { style: styles }, - } - : { - tag: "td", - content: cell, - } - ); - }); - return htmlLike({ tag: "tr", content }); - }); +/** + * Remove the env environment by returning the content in env only. + */ +function removeEnv(env: Ast.Environment, info: VisitInfo, file?: VFile) { + // add warning + file?.message( + makeWarningMessage( + env, + `Warning: There is no equivalent tag for \"${env.env}\", so the ${env.env} environment was removed.`, + "environment-subs" + ) + ); - return htmlLike({ - tag: "table", - content: [ - htmlLike({ - tag: "tbody", - content: tableBody, - }), - ], - attributes: { className: "tabular" }, - }); + return env.content; } /** * Rules for replacing a macro with an html-like macro - * that will render has html when printed. + * that will render has pretext when printed. */ export const environmentReplacements: Record< string, ( node: Ast.Environment, - info: VisitInfo - ) => Ast.Macro | Ast.String | Ast.Environment + info: VisitInfo, + file?: VFile + ) => Ast.Macro | Ast.String | Ast.Environment | Ast.Node[] > = { enumerate: enumerateFactory("ol"), - itemize: enumerateFactory("ul", "itemize"), - center: createCenteredElement, + itemize: enumerateFactory("ul"), + center: removeEnv, tabular: createTableFromTabular, quote: (env) => { return htmlLike({ tag: "blockquote", content: env.content, - attributes: { className: "environment quote" }, }); }, }; diff --git a/packages/unified-latex-to-pretext/libs/pre-conversion-subs/macro-subs.ts b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/macro-subs.ts index 5398ee13..93e37f13 100644 --- a/packages/unified-latex-to-pretext/libs/pre-conversion-subs/macro-subs.ts +++ b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/macro-subs.ts @@ -1,18 +1,22 @@ -import { xcolorMacroToHex } from "@unified-latex/unified-latex-ctan/package/xcolor"; import { htmlLike } from "@unified-latex/unified-latex-util-html-like"; import * as Ast from "@unified-latex/unified-latex-types"; import { getArgsContent } from "@unified-latex/unified-latex-util-arguments"; import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; import { VisitInfo } from "@unified-latex/unified-latex-util-visit"; +import { VFile } from "unified-lint-rule/lib"; +import { makeWarningMessage, emptyStringWithWarningFactory } from "./utils"; /** * Factory function that generates html-like macros that wrap their contents. + * warningMessage is a warning for any latex macros that don't have an equivalent + * pretext tag. */ function factory( tag: string, + warningMessage: string = "", attributes?: Record -): (macro: Ast.Macro) => Ast.Macro { - return (macro) => { +): (macro: Ast.Macro, info: VisitInfo, file?: VFile) => Ast.Macro { + return (macro, info, file) => { if (!macro.args) { throw new Error( `Found macro to replace but couldn't find content ${printRaw( @@ -20,6 +24,17 @@ function factory( )}` ); } + + // add a warning message to the file if needed + if (warningMessage && file) { + const message = makeWarningMessage( + macro, + `Warning: There is no equivalent tag for \"${macro.content}\", \"${tag}\" was used as a replacement.`, + "macro-subs" + ); + file.message(message, message.position, message.source); + } + // Assume the meaningful argument is the last argument. This // ensures that we can convert for default packages as well as // packages like beamer, which may add optional arguments. @@ -32,10 +47,7 @@ function factory( function createHeading(tag: string, attrs = {}) { return (macro: Ast.Macro) => { const args = getArgsContent(macro); - const starred = !!args[0]; - const attributes: Record = starred - ? { className: "starred" } - : {}; + const attributes: Record = {}; if (attrs) { Object.assign(attributes, attrs); @@ -51,33 +63,44 @@ function createHeading(tag: string, attrs = {}) { export const macroReplacements: Record< string, - (node: Ast.Macro, info: VisitInfo) => Ast.Node + (node: Ast.Macro, info: VisitInfo, file?: VFile) => Ast.Node > = { emph: factory("em"), - textrm: factory("span", { className: "textrm" }), - textsf: factory("span", { className: "textsf" }), - texttt: factory("span", { className: "texttt" }), - textsl: factory("span", { className: "textsl" }), - textit: factory("i", { className: "textit" }), - textbf: factory("b", { className: "textbf" }), - underline: factory("span", { className: "underline" }), - mbox: factory("span", { className: "mbox" }), - phantom: factory("span", { className: "phantom" }), - part: createHeading("title"), - chapter: createHeading("title"), - section: createHeading("title"), - subsection: createHeading("title"), - subsubsection: createHeading("title"), - paragraph: createHeading("title"), - subparagraph: createHeading("title"), - appendix: createHeading("title"), + textrm: factory( + "em", + `Warning: There is no equivalent tag for \"textrm\", \"em\" was used as a replacement.` + ), + textsf: factory( + "em", + `Warning: There is no equivalent tag for \"textsf\", \"em\" was used as a replacement.` + ), + texttt: factory( + "em", + `Warning: There is no equivalent tag for \"textsf\", \"em\" was used as a replacement.` + ), + textsl: factory( + "em", + `Warning: There is no equivalent tag for \"textsl\", \"em\" was used as a replacement.` + ), + textit: factory("em"), + textbf: factory("alert"), + underline: factory( + "em", + `Warning: There is no equivalent tag for \"underline\", \"em\" was used as a replacement.` + ), + mbox: emptyStringWithWarningFactory( + `Warning: There is no equivalent tag for \"mbox\", an empty Ast.String was used as a replacement.` + ), + phantom: emptyStringWithWarningFactory( + `Warning: There is no equivalent tag for \"phantom\", an empty Ast.String was used as a replacement.` + ), + appendix: createHeading("appendix"), url: (node) => { const args = getArgsContent(node); const url = printRaw(args[0] || "#"); return htmlLike({ - tag: "a", + tag: "url", attributes: { - className: "url", href: url, }, content: [{ type: "string", content: url }], @@ -87,9 +110,8 @@ export const macroReplacements: Record< const args = getArgsContent(node); const url = printRaw(args[1] || "#"); return htmlLike({ - tag: "a", + tag: "url", attributes: { - className: "href", href: url, }, content: args[2] || [], @@ -99,95 +121,42 @@ export const macroReplacements: Record< const args = getArgsContent(node); const url = "#" + printRaw(args[0] || ""); return htmlLike({ - tag: "a", + tag: "url", attributes: { - className: "href", href: url, }, content: args[1] || [], }); }, - "\\": () => - htmlLike({ - tag: "br", - attributes: { className: "linebreak" }, - }), - vspace: (node) => { - const args = getArgsContent(node); - return htmlLike({ - tag: "div", - attributes: { - className: "vspace", - "data-amount": printRaw(args[1] || []), - }, - content: [], - }); - }, - hspace: (node) => { - const args = getArgsContent(node); - return htmlLike({ - tag: "span", - attributes: { - className: "vspace", - "data-amount": printRaw(args[1] || []), - }, - content: [], - }); - }, - textcolor: (node) => { - const args = getArgsContent(node); - const computedColor = xcolorMacroToHex(node); - const color = computedColor.hex; - - if (color) { - return htmlLike({ - tag: "span", - attributes: { style: `color: ${color};` }, - content: args[2] || [], - }); - } else { - // If we couldn't compute the color, it's probably a named - // color that wasn't supplied. In this case, we fall back to a css variable - return htmlLike({ - tag: "span", - attributes: { - style: `color: var(${computedColor.cssVarName});`, - }, - content: args[2] || [], - }); - } - }, - textsize: (node) => { - const args = getArgsContent(node); - const textSize = printRaw(args[0] || []); - return htmlLike({ - tag: "span", - attributes: { - className: `textsize-${textSize}`, - }, - content: args[1] || [], - }); - }, - makebox: (node) => { - const args = getArgsContent(node); - return htmlLike({ - tag: "span", - attributes: { - className: `latex-box`, - style: "display: inline-block;", - }, - content: args[3] || [], - }); - }, - noindent: () => ({ type: "string", content: "" }), + "\\": emptyStringWithWarningFactory( + `Warning: There is no equivalent tag for \"\\\", an empty Ast.String was used as a replacement.` + ), + vspace: emptyStringWithWarningFactory( + `Warning: There is no equivalent tag for \"vspace\", an empty Ast.String was used as a replacement.` + ), + hspace: emptyStringWithWarningFactory( + `Warning: There is no equivalent tag for \"hspace\", an empty Ast.String was used as a replacement.` + ), + textcolor: factory( + "em", + `Warning: There is no equivalent tag for \"textcolor\", \"em\" was used as a replacement.` + ), + textsize: emptyStringWithWarningFactory( + `Warning: There is no equivalent tag for \"textsize\", an empty Ast.String was used as a replacement.` + ), + makebox: emptyStringWithWarningFactory( + `Warning: There is no equivalent tag for \"makebox\", an empty Ast.String was used as a replacement.` + ), + noindent: emptyStringWithWarningFactory( + `Warning: There is no equivalent tag for \"noindent\", an empty Ast.String was used as a replacement.` + ), includegraphics: (node) => { const args = getArgsContent(node); - const src = printRaw(args[args.length - 1] || []); + const source = printRaw(args[args.length - 1] || []); return htmlLike({ - tag: "img", + tag: "image", attributes: { - className: "includegraphics", - src, + source, }, content: [], }); diff --git a/packages/unified-latex-to-pretext/libs/pre-conversion-subs/report-unsupported-macro-katex.ts b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/report-unsupported-macro-katex.ts index 38651036..152e1f4d 100644 --- a/packages/unified-latex-to-pretext/libs/pre-conversion-subs/report-unsupported-macro-katex.ts +++ b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/report-unsupported-macro-katex.ts @@ -2,12 +2,16 @@ import * as Ast from "@unified-latex/unified-latex-types"; import { anyMacro, match } from "@unified-latex/unified-latex-util-match"; import { visit } from "@unified-latex/unified-latex-util-visit"; import { KATEX_SUPPORT } from "./katex-subs"; +import { VFileMessage } from "vfile-message"; +import { makeWarningMessage } from "./utils"; /** * Return a list of macros used in ast that are unsupported by KaTeX */ -export function reportMacrosUnsupportedByKatex(ast: Ast.Ast): string[] { - const unsupported: string[] = []; +export function reportMacrosUnsupportedByKatex(ast: Ast.Ast): { + messages: VFileMessage[]; +} { + const unsupported: { messages: VFileMessage[] } = { messages: [] }; // match a macro supported by Katex const isSupported = match.createMacroMatcher(KATEX_SUPPORT.macros); @@ -18,7 +22,16 @@ export function reportMacrosUnsupportedByKatex(ast: Ast.Ast): string[] { if (anyMacro(node) && info.context.hasMathModeAncestor) { // check if not supported by katex if (!isSupported(node)) { - unsupported.push((node as Ast.Macro).content); + // add a warning message + unsupported.messages.push( + makeWarningMessage( + node, + `Warning: \"${ + (node as Ast.Macro).content + }\" is unsupported by Katex.`, + "report-unsupported-macro-katex" + ) + ); } } }); diff --git a/packages/unified-latex-to-pretext/libs/pre-conversion-subs/utils.ts b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/utils.ts new file mode 100644 index 00000000..5b958af5 --- /dev/null +++ b/packages/unified-latex-to-pretext/libs/pre-conversion-subs/utils.ts @@ -0,0 +1,46 @@ +import * as Ast from "@unified-latex/unified-latex-types"; +import { VisitInfo } from "@unified-latex/unified-latex-util-visit"; +import { VFile } from "unified-lint-rule/lib"; +import { s } from "@unified-latex/unified-latex-builder"; +import { VFileMessage } from "vfile-message"; + +/** + * Create a warning message about node from the given source file. + */ +export function makeWarningMessage( + node: Ast.Node, + message: string, + warningType: string +): VFileMessage { + const newMessage = new VFileMessage(message, node); + + newMessage.source = `unified-latex-to-pretext:${warningType}`; + + return newMessage; +} + +/** + * Create an empty Ast.String node, adding a warning message from + * the source file into the VFile. + */ +export function emptyStringWithWarningFactory( + warningMessage: string +): (node: Ast.Node, info: VisitInfo, file?: VFile) => Ast.String { + return (node, info, file) => { + // add a warning message + if (file) { + const message = makeWarningMessage( + node, + warningMessage, + "macro-subs" + ); + file.message( + message, + message.position, + `unified-latex-to-pretext:macro-subs` + ); + } + + return s(""); + }; +} diff --git a/packages/unified-latex-to-pretext/libs/pretext-subs/to-pretext.ts b/packages/unified-latex-to-pretext/libs/pretext-subs/to-pretext.ts index c8b8fb25..a76f553b 100644 --- a/packages/unified-latex-to-pretext/libs/pretext-subs/to-pretext.ts +++ b/packages/unified-latex-to-pretext/libs/pretext-subs/to-pretext.ts @@ -6,6 +6,11 @@ import { } from "@unified-latex/unified-latex-util-html-like"; import * as Ast from "@unified-latex/unified-latex-types"; import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; +import { + divisions, + isMappedEnviron, +} from "../pre-conversion-subs/break-on-boundaries"; +import { getArgsContent } from "@unified-latex/unified-latex-util-arguments"; function formatNodeForError(node: Ast.Node | any): string { try { @@ -23,7 +28,7 @@ export function toPretextWithLoggerFactory( logger: (message: string, node: any) => void ) { /** - * Convert Ast.Node to Hast nodes. + * Convert Ast.Node to Xast nodes. */ return function toPretext( node: Ast.Node | Ast.Argument @@ -59,48 +64,105 @@ export function toPretextWithLoggerFactory( return x("m", printRaw(node.content)); case "mathenv": case "displaymath": - return x("m", printRaw(node.content)); + return x("me", printRaw(node.content)); case "verb": case "verbatim": - return x("pre", { className: node.env }, node.content); + return x("pre", node.content); case "whitespace": return { type: "text", value: " ", position: node.position }; case "parbreak": - return x("br"); + // warn first + logger( + `There is no equivalent for parbreak, so it was replaced with an empty string.`, + node + ); + + // return an empty string + return { + type: "text", + value: "", + position: node.position, + }; case "group": // Groups are just ignored. return node.content.flatMap(toPretext); case "environment": + // check if it's a new environment made to replace a division node + if (isMappedEnviron(node)) { + // get the division macro associated with this node + let divisionName = divisions.find( + (x) => x.mappedEnviron === node.env + )?.division; + + // for subparagraph, give a warning since pretext has no equivalent tag + if (divisionName === "subparagraph") { + logger( + `Warning: There is no equivalent tag for "subparagraph", "paragraphs" was used as a replacement.`, + node + ); + } + + // paragraph and subparagraph become paragraphs + if ( + divisionName === "paragraph" || + divisionName === "subparagraph" + ) { + divisionName = "paragraphs"; + } + + // create a title tag containing the division macro's title arg + const title = getArgsContent(node)[0]; + + if (!title) { + logger( + `Warning: No title was given, so an empty title tag was used.`, + node + ); + } + + const titleTag = x("title", title?.flatMap(toPretext)); + + if (divisionName) { + return x(divisionName, [ + titleTag, + ...node.content.flatMap(toPretext), + ]); + } + } + logger( - `Unknown environment when converting to HTML \`${formatNodeForError( + `Unknown environment when converting to XML \`${formatNodeForError( node.env )}\``, node ); - return x("div", node.content.flatMap(toPretext)); + return node.content.flatMap(toPretext); // just remove the environment case "macro": logger( - `Unknown macro when converting to HTML \`${formatNodeForError( + `Unknown macro when converting to XML \`${formatNodeForError( node )}\``, node ); - return x("span", (node.args || []).map(toPretext).flat()); + return (node.args || []).map(toPretext).flat(); case "argument": - return x( - "span", - { - "data-open-mark": node.openMark, - "data-close-mark": node.closeMark, - }, - printRaw(node.content) + logger( + `Unknown argument when converting to XML \`${formatNodeForError( + node + )}\``, + node ); + return { + type: "text", + value: printRaw(node.content), + position: node.position, + }; case "root": return node.content.flatMap(toPretext); default: { const _exhaustiveCheck: never = node; throw new Error( - `Unknown node type; cannot convert to HAST ${JSON.stringify( + `Unknown node type; cannot convert to XAST ${JSON.stringify( node )}` ); @@ -110,6 +172,6 @@ export function toPretextWithLoggerFactory( } /** - * Convert Ast.Node to Hast nodes. + * Convert Ast.Node to Xast nodes. */ export const toPretext = toPretextWithLoggerFactory(console.warn); diff --git a/packages/unified-latex-to-pretext/libs/split-for-pars.ts b/packages/unified-latex-to-pretext/libs/split-for-pars.ts index 2d62ec5a..b0d449a2 100644 --- a/packages/unified-latex-to-pretext/libs/split-for-pars.ts +++ b/packages/unified-latex-to-pretext/libs/split-for-pars.ts @@ -49,12 +49,6 @@ export function splitForPars( ret.push({ content: [node], wrapInPar: false }); continue; } - // Display-math should always break pars - if (node.type === "displaymath") { - pushBody(); - ret.push({ content: [node], wrapInPar: false }); - continue; - } if (match.parbreak(node) || match.macro(node, "par")) { pushBody(); continue; diff --git a/packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-xml-like.ts b/packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-pretext-like.ts similarity index 51% rename from packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-xml-like.ts rename to packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-pretext-like.ts index d8aeff80..56d51e85 100644 --- a/packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-xml-like.ts +++ b/packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-pretext-like.ts @@ -3,13 +3,17 @@ import { Plugin, unified } from "unified"; import { unifiedLatexLintNoTexFontShapingCommands } from "@unified-latex/unified-latex-lint/rules/unified-latex-lint-no-tex-font-shaping-commands"; import * as Ast from "@unified-latex/unified-latex-types"; import { deleteComments } from "@unified-latex/unified-latex-util-comments"; -import { match } from "@unified-latex/unified-latex-util-match"; +import { + anyEnvironment, + anyMacro, + match, +} from "@unified-latex/unified-latex-util-match"; import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; import { replaceNode, unifiedLatexReplaceStreamingCommands, } from "@unified-latex/unified-latex-util-replace"; -import { EXIT, visit } from "@unified-latex/unified-latex-util-visit"; +import { EXIT, SKIP, visit } from "@unified-latex/unified-latex-util-visit"; import { environmentReplacements as _environmentReplacements } from "./pre-conversion-subs/environment-subs"; import { attachNeededRenderInfo, @@ -19,6 +23,14 @@ import { import { macroReplacements as _macroReplacements } from "./pre-conversion-subs/macro-subs"; import { streamingMacroReplacements } from "./pre-conversion-subs/streaming-command-subs"; import { unifiedLatexWrapPars } from "./unified-latex-wrap-pars"; +import { + breakOnBoundaries, + isMappedEnviron, +} from "./pre-conversion-subs/break-on-boundaries"; +import { reportMacrosUnsupportedByKatex } from "./pre-conversion-subs/report-unsupported-macro-katex"; +import { htmlLike } from "@unified-latex/unified-latex-util-html-like"; +import { getArgsContent } from "@unified-latex/unified-latex-util-arguments"; +import { s } from "@unified-latex/unified-latex-builder"; type EnvironmentReplacements = typeof _environmentReplacements; type MacroReplacements = typeof _macroReplacements; @@ -34,6 +46,12 @@ export type PluginOptions = { * You probably want to use the function `htmlLike(...)` to return a node that gets converted to specific HTML. */ macroReplacements?: MacroReplacements; + + /** + * A boolean where if it's true then the output won't be wrapped in the
... etc. tags. + * If it's false (default), a valid and complete PreTeXt document is returned. + */ + producePretextFragment?: boolean; }; /** @@ -43,7 +61,7 @@ export type PluginOptions = { * * Note: this plugin only wraps paragraphs in `p` tags if there are multiple paragraphs. Otherwise it omits the

tags. */ -export const unifiedLatexToXmlLike: Plugin< +export const unifiedLatexToPretextLike: Plugin< PluginOptions[], Ast.Root, Hast.Root @@ -58,6 +76,10 @@ export const unifiedLatexToXmlLike: Plugin< _environmentReplacements, options?.environmentReplacements || {} ); + const producePretextFragment = options?.producePretextFragment + ? options?.producePretextFragment + : false; + const isReplaceableMacro = match.createMacroMatcher(macroReplacements); const isReplaceableEnvironment = match.createEnvironmentMatcher( environmentReplacements @@ -69,7 +91,7 @@ export const unifiedLatexToXmlLike: Plugin< katexSpecificEnvironmentReplacements ); - return (tree) => { + return (tree, file) => { const originalTree = tree; // NOTE: These operations need to be done in a particular order. @@ -83,36 +105,69 @@ export const unifiedLatexToXmlLike: Plugin< replacers: streamingMacroReplacements, }); + // convert division macros into environments + const warningMessages = breakOnBoundaries(tree); + + // add warning messages into the file one at a time + for (const warningMessage of warningMessages.messages) { + file.message( + warningMessage, + warningMessage.position, + "unified-latex-to-pretext:break-on-boundaries" + ); + } + // Must be done *after* streaming commands are replaced. // We only wrap PARs if we *need* to. That is, if the content contains multiple paragraphs if (shouldBeWrappedInPars(tree)) { processor = processor.use(unifiedLatexWrapPars); } - tree = processor.runSync(tree); + tree = processor.runSync(tree, file); // Replace text-mode environments and then macros. Environments *must* be processed first, since // environments like tabular use `\\` as a newline indicator, but a `\\` macro gets replaced with - // a `
` during macro replacement. + // an empty Ast.String during macro replacement. replaceNode(tree, (node, info) => { // Children of math-mode are rendered by KaTeX/MathJax and so we shouldn't touch them! if (info.context.hasMathModeAncestor) { return; } if (isReplaceableEnvironment(node)) { - return environmentReplacements[printRaw(node.env)](node, info); + return environmentReplacements[printRaw(node.env)]( + node, + info, + file + ); } }); + replaceNode(tree, (node, info) => { // Children of math-mode are rendered by KaTeX/MathJax and so we shouldn't touch them! if (info.context.hasMathModeAncestor) { return; } if (isReplaceableMacro(node)) { - const replacement = macroReplacements[node.content](node, info); + const replacement = macroReplacements[node.content]( + node, + info, + file + ); return replacement; } }); + // before replacing math-mode macros, report any macros that can't be replaced + const unsupportedByKatex = reportMacrosUnsupportedByKatex(tree); + + // add these warning messages into the file one at a time + for (const warningMessage of unsupportedByKatex.messages) { + file.message( + warningMessage, + warningMessage.position, + "unified-latex-to-pretext:report-unsupported-macro-katex" + ); + } + // Replace math-mode macros for appropriate KaTeX rendering attachNeededRenderInfo(tree); replaceNode(tree, (node) => { @@ -126,8 +181,20 @@ export const unifiedLatexToXmlLike: Plugin< } }); + // Wrap in enough tags to ensure a valid pretext document + if (!producePretextFragment) { + // choose a book or article tag + createValidPretextDoc(tree); + + // wrap around with pretext tag + tree.content = [ + htmlLike({ tag: "pretext", content: tree.content }), + ]; + } + // Make sure we are actually mutating the current tree. originalTree.content = tree.content; + console.log(file.messages); }; }; @@ -147,7 +214,104 @@ function shouldBeWrappedInPars(tree: Ast.Root): boolean { { test: (node) => match.environment(node, "document") } ); - return content.some( - (node) => match.parbreak(node) || match.macro(node, "par") - ); + return containsPar(content); +} + +function containsPar(content: Ast.Node[]): boolean { + return content.some((node) => { + if (isMappedEnviron(node)) { + return containsPar(node.content); + } + + return match.parbreak(node) || match.macro(node, "par"); + }); +} + +/** + * Wrap the tree content in a book or article tag. + */ +function createValidPretextDoc(tree: Ast.Root): void { + // this will be incomplete since the author info isn't pushed yet, which obtains documentclass, title, etc. + let isBook: boolean = false; + + // look for a \documentclass (this will need to change, as this info will be gotten earlier) + const docClass = findMacro(tree, "documentclass"); + + // check if there was a documentclass + if (docClass) { + const docClassArg = getArgsContent(docClass)[0]; + + // get the actual class + if (docClassArg) { + const docClassTitle = docClassArg[0] as Ast.String; + + // memoirs will be books too + if ( + docClassTitle.content == "book" || + docClassTitle.content == "memoir" + ) { + isBook = true; + } + } + } + + // if we still don't know if it's a book, look for _chapters environments (since breakonboundaries was called before) + if (!isBook) { + visit(tree, (node) => { + if (anyEnvironment(node) && node.env == "_chapter") { + isBook = true; + return EXIT; + } + }); + } + + // a book and article tag must have a title tag right after it + // extract the title first + const title = findMacro(tree, "title"); + + if (title) { + const titleArg = getArgsContent(title)[1]; + + // get the actual title + if (titleArg) { + const titleString = titleArg[0] as Ast.String; + tree.content.unshift( + htmlLike({ tag: "title", content: titleString }) + ); + } + // if no title name was given, make an empty tag + else { + tree.content.unshift(htmlLike({ tag: "title", content: s("") })); + } + } + // if there is no title, add an empty title tag + else { + tree.content.unshift(htmlLike({ tag: "title", content: s("") })); + } + + // now create a book or article tag + if (isBook) { + tree.content = [htmlLike({ tag: "book", content: tree.content })]; + } else { + tree.content = [htmlLike({ tag: "article", content: tree.content })]; + } +} + +// this will likely be removed +function findMacro(tree: Ast.Root, content: string): Ast.Macro | null { + let macro: Ast.Macro | null = null; + + // look for the macro + visit(tree, (node) => { + // skip visiting the children of environments + if (anyEnvironment(node)) { + return SKIP; + } + if (anyMacro(node) && node.content === content) { + macro = node; + return EXIT; + } + }); + + return macro; } diff --git a/packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-pretext.ts b/packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-pretext.ts index 88eabd1a..63cba56f 100644 --- a/packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-pretext.ts +++ b/packages/unified-latex-to-pretext/libs/unified-latex-plugin-to-pretext.ts @@ -8,11 +8,18 @@ import { match } from "@unified-latex/unified-latex-util-match"; import { EXIT, visit } from "@unified-latex/unified-latex-util-visit"; import { toPretextWithLoggerFactory } from "./pretext-subs/to-pretext"; import { - unifiedLatexToXmlLike, + unifiedLatexToPretextLike, PluginOptions as HtmlLikePluginOptions, -} from "./unified-latex-plugin-to-xml-like"; +} from "./unified-latex-plugin-to-pretext-like"; +import { expandUserDefinedMacros } from "./pre-conversion-subs/expand-user-defined-macros"; -export type PluginOptions = HtmlLikePluginOptions & {}; +export type PluginOptions = HtmlLikePluginOptions & { + /** + * A boolean where if it's true then the output won't be wrapped in the

... etc. tags. + * If it's false (default), a valid and complete PreTeXt document is returned. + */ + producePretextFragment?: boolean; +}; /** * Unified plugin to convert a `unified-latex` AST into a `xast` AST representation of PreTeXt source. @@ -23,11 +30,12 @@ export const unifiedLatexToPretext: Plugin< Xast.Root > = function unifiedLatexAttachMacroArguments(options) { return (tree, file) => { - unified().use(unifiedLatexToXmlLike, options).run(tree); + const producePretextFragment = options?.producePretextFragment + ? options?.producePretextFragment + : false; - // This should happen right before converting to HTML because macros like `\&` should - // be expanded via html rules first (and not turned into their corresponding ligature directly) - expandUnicodeLigatures(tree); + // expand user defined macros + expandUserDefinedMacros(tree); // If there is a \begin{document}...\end{document}, that's the only // content we want to convert. @@ -47,14 +55,35 @@ export const unifiedLatexToPretext: Plugin< } ); - const toHast = toPretextWithLoggerFactory(file.message.bind(file)); - let converted = toHast({ type: "root", content }); + // since we don't want to wrap content outside of \begin{document}...\end{document} with ... + tree.content = content; + + unified().use(unifiedLatexToPretextLike, options).run(tree, file); + + // This should happen right before converting to PreTeXt because macros like `\&` should + // be expanded via html rules first (and not turned into their corresponding ligature directly) + expandUnicodeLigatures(tree); + + // update content + content = tree.content; + + const toXast = toPretextWithLoggerFactory(file.message.bind(file)); + let converted = toXast({ type: "root", content }); if (!Array.isArray(converted)) { converted = [converted]; } - // Wrap everything in a Hast.Root node + // Wrap everything in a Xast.Root node let ret = x(); ret.children = converted; + + // add boilerplate + if (!producePretextFragment) { + ret.children.unshift({ + type: "instruction", + name: "xml", + value: "version='1.0' encoding='utf-8'", + }); + } return ret; }; }; diff --git a/packages/unified-latex-to-pretext/libs/unified-latex-wrap-pars.ts b/packages/unified-latex-to-pretext/libs/unified-latex-wrap-pars.ts index 49603ab1..a6f193ca 100644 --- a/packages/unified-latex-to-pretext/libs/unified-latex-wrap-pars.ts +++ b/packages/unified-latex-to-pretext/libs/unified-latex-wrap-pars.ts @@ -1,9 +1,9 @@ import { Plugin } from "unified"; import * as Ast from "@unified-latex/unified-latex-types"; import { match } from "@unified-latex/unified-latex-util-match"; -import { EXIT, visit } from "@unified-latex/unified-latex-util-visit"; +import { visit } from "@unified-latex/unified-latex-util-visit"; import { wrapPars } from "./wrap-pars"; - +import { isMappedEnviron } from "./pre-conversion-subs/break-on-boundaries"; type PluginOptions = { macrosThatBreakPars?: string[]; environmentsThatDontBreakPars?: string[]; @@ -20,20 +20,24 @@ export const unifiedLatexWrapPars: Plugin = options || {}; return (tree) => { // If \begin{document}...\end{document} is present, we only wrap pars inside of it. + let hasDocumentEnv = false; visit( tree, (env) => { - if (match.environment(env, "document")) { - hasDocumentEnv = true; + if ( + match.environment(env, "document") || + isMappedEnviron(env) + ) { + if (match.environment(env, "document")) { + hasDocumentEnv = true; + } // While we're here, we might as well wrap the pars! env.content = wrapPars(env.content, { macrosThatBreakPars, environmentsThatDontBreakPars, }); - - return EXIT; } }, { test: match.anyEnvironment } diff --git a/packages/unified-latex-to-pretext/tests/convert-to-pretext.test.ts b/packages/unified-latex-to-pretext/tests/convert-to-pretext.test.ts index bba5f4e5..12703dda 100644 --- a/packages/unified-latex-to-pretext/tests/convert-to-pretext.test.ts +++ b/packages/unified-latex-to-pretext/tests/convert-to-pretext.test.ts @@ -61,6 +61,7 @@ describe("unified-latex-to-pretext:convert-to-pretext", () => { yyy: (node) => htmlLike({ tag: "yyy", content: node.content }), }, + producePretextFragment: true, }); let ast; @@ -87,6 +88,7 @@ describe("unified-latex-to-pretext:convert-to-pretext", () => { }); }, }, + producePretextFragment: true, }) .use(xmlCompilePlugin) .processSync(value).value as string; diff --git a/packages/unified-latex-to-pretext/tests/report-unsupported-macro-katex.test.ts b/packages/unified-latex-to-pretext/tests/report-unsupported-macro-katex.test.ts index be40a3d8..f0a2f4f6 100644 --- a/packages/unified-latex-to-pretext/tests/report-unsupported-macro-katex.test.ts +++ b/packages/unified-latex-to-pretext/tests/report-unsupported-macro-katex.test.ts @@ -18,7 +18,7 @@ describe("unified-latex-to-pretext:report-unsupported-macro-katex", () => { const parser = getParser(); const ast = parser.parse(value); - expect(reportMacrosUnsupportedByKatex(ast)).toEqual(["fakemacro"]); + expect(reportMacrosUnsupportedByKatex(ast).messages.length).toEqual(1); }); it("can report no unsupported macros in mathmode", () => { @@ -27,7 +27,7 @@ describe("unified-latex-to-pretext:report-unsupported-macro-katex", () => { const parser = getParser(); const ast = parser.parse(value); - expect(reportMacrosUnsupportedByKatex(ast)).toEqual([]); + expect(reportMacrosUnsupportedByKatex(ast).messages.length).toEqual(0); }); it("doesn't report unsupported macros outside of math mode", () => { @@ -36,7 +36,7 @@ describe("unified-latex-to-pretext:report-unsupported-macro-katex", () => { const parser = getParser(); const ast = parser.parse(value); - expect(reportMacrosUnsupportedByKatex(ast)).toEqual([]); + expect(reportMacrosUnsupportedByKatex(ast).messages.length).toEqual(0); }); it("reports unsupported macros in text mode with a math anscestor", () => { @@ -45,7 +45,7 @@ describe("unified-latex-to-pretext:report-unsupported-macro-katex", () => { const parser = getParser(); const ast = parser.parse(value); - expect(reportMacrosUnsupportedByKatex(ast)).toEqual(["unsupported"]); + expect(reportMacrosUnsupportedByKatex(ast).messages.length).toEqual(1); }); it("can report unsupported macros in display mathmode", () => { @@ -54,7 +54,7 @@ describe("unified-latex-to-pretext:report-unsupported-macro-katex", () => { const parser = getParser(); const ast = parser.parse(value); - expect(reportMacrosUnsupportedByKatex(ast)).toEqual(["fake", "baz"]); + expect(reportMacrosUnsupportedByKatex(ast).messages.length).toEqual(2); }); it("can report unsupported macros in equation environment", () => { @@ -63,9 +63,6 @@ describe("unified-latex-to-pretext:report-unsupported-macro-katex", () => { const parser = getParser(); const ast = parser.parse(value); - expect(reportMacrosUnsupportedByKatex(ast)).toEqual([ - "unsupported", - "baz", - ]); + expect(reportMacrosUnsupportedByKatex(ast).messages.length).toEqual(2); }); }); diff --git a/packages/unified-latex-to-pretext/tests/unified-latex-to-pretext.test.ts b/packages/unified-latex-to-pretext/tests/unified-latex-to-pretext.test.ts index d1e8f59d..f3e3f026 100644 --- a/packages/unified-latex-to-pretext/tests/unified-latex-to-pretext.test.ts +++ b/packages/unified-latex-to-pretext/tests/unified-latex-to-pretext.test.ts @@ -29,39 +29,35 @@ describe("unified-latex-to-pretext:unified-latex-to-pretext", () => { const process = (value: string) => processLatexViaUnified({ macros: { xxx: { signature: "m m" } } }) - .use(unifiedLatexToPretext) + .use(unifiedLatexToPretext, { producePretextFragment: true }) .use(xmlCompilePlugin) .processSync({ value }).value as string; - it.skip("wrap pars and streaming commands", () => { + it("wrap pars and streaming commands", () => { html = process("a\n\nb"); expect(html).toEqual("

a

b

"); html = process("\\bfseries a\n\nb"); - expect(html).toEqual( - '

a

b

' - ); + expect(html).toEqual("

a

b

"); html = process("\\bf a\n\nb"); - expect(html).toEqual( - '

a

b

' - ); + expect(html).toEqual("

a

b

"); }); - it.skip("Can replace text-style macros", () => { + it("Can replace text-style macros", () => { html = process(String.raw`a \textbf{different} word`); expect(normalizeHtml(html)).toEqual( - normalizeHtml(`a different word`) + normalizeHtml(`a different word`) ); html = process(String.raw`a \textsf{different} word`); expect(normalizeHtml(html)).toEqual( - normalizeHtml(`a different word`) + normalizeHtml(`a different word`) ); html = process(String.raw`a \textrm{different} word`); expect(normalizeHtml(html)).toEqual( - normalizeHtml(`a different word`) + normalizeHtml(`a different word`) ); html = process(String.raw`a \emph{different} word`); @@ -69,20 +65,21 @@ describe("unified-latex-to-pretext:unified-latex-to-pretext", () => { normalizeHtml(`a different word`) ); }); - it.skip("Can replace headings", () => { + + it("Can replace headings", () => { html = process(String.raw`\chapter{My Chapter}`); expect(normalizeHtml(html)).toEqual( - normalizeHtml(`

My Chapter

`) + normalizeHtml(`My Chapter`) ); html = process(String.raw`\section{My Section}`); expect(normalizeHtml(html)).toEqual( - normalizeHtml(`My Section`) + normalizeHtml(`
My Section
`) ); html = process(String.raw`\section*{My Section}`); expect(normalizeHtml(html)).toEqual( - normalizeHtml(`My Section`) + normalizeHtml(`
My Section
`) ); }); @@ -100,24 +97,22 @@ describe("unified-latex-to-pretext:unified-latex-to-pretext", () => { expect(normalizeHtml(html)).toEqual(normalizeHtml(`

a

b

`)); }); - it.skip("Wraps URLs", () => { + it("Wraps URLs", () => { html = process(`a\\url{foo.com}b`); expect(normalizeHtml(html)).toEqual( - normalizeHtml(`afoo.comb`) + normalizeHtml(`afoo.comb`) ); html = process(`a\\href{foo.com}{FOO}b`); expect(normalizeHtml(html)).toEqual( - normalizeHtml(`aFOOb`) + normalizeHtml(`aFOOb`) ); }); - it.skip("Converts enumerate environments", () => { + it("Converts enumerate environments", () => { html = process(`\\begin{enumerate}\\item a\\item b\\end{enumerate}`); expect(normalizeHtml(html)).toEqual( - normalizeHtml( - `
  1. a

  2. b

` - ) + normalizeHtml(`
  1. a

  2. b

`) ); // Any content before an \item is ignored @@ -125,28 +120,28 @@ describe("unified-latex-to-pretext:unified-latex-to-pretext", () => { `\\begin{enumerate}before content\\item a\\item b\\end{enumerate}` ); expect(normalizeHtml(html)).toEqual( - normalizeHtml( - `
  1. a

  2. b

` - ) + normalizeHtml(`
  1. a

  2. b

`) ); // Custom labels are handled html = process( `\\begin{enumerate}before content\\item[x)] a\\item[] b\\end{enumerate}` ); + expect(normalizeHtml(html)).toEqual( - normalizeHtml(`
    -
  1. a

  2. -
  3. b

  4. -
`) + normalizeHtml( + `
+
  • x)

    a

  • +
  • b

  • +
    ` + ) ); }); - it.skip("Converts itemize environments", () => { + + it("Converts itemize environments", () => { html = process(`\\begin{itemize}\\item a\\item b\\end{itemize}`); expect(normalizeHtml(html)).toEqual( - normalizeHtml( - `
    • a

    • b

    ` - ) + normalizeHtml(`
    • a

    • b

    `) ); // Any content before an \item is ignored @@ -154,39 +149,40 @@ describe("unified-latex-to-pretext:unified-latex-to-pretext", () => { `\\begin{itemize}before content\\item a\\item b\\end{itemize}` ); expect(normalizeHtml(html)).toEqual( - normalizeHtml( - `
    • a

    • b

    ` - ) + normalizeHtml(`
    • a

    • b

    `) ); // Custom labels are handled html = process( `\\begin{itemize}before content\\item[x)] a\\item[] b\\end{itemize}` ); + expect(normalizeHtml(html)).toEqual( - normalizeHtml(`
      -
    • a

    • -
    • b

    • -
    `) + normalizeHtml( + `
    +
  • x)

    a

  • +
  • b

  • +
    ` + ) ); }); - it.skip("Converts tabular environment", () => { + it("Converts tabular environment", () => { html = process(`\\begin{tabular}{l l}a & b\\\\c & d\\end{tabular}`); + + expect(normalizeHtml(html)).toEqual( + normalizeHtml( + `abcd` + ) + ); + }); + + it("Converts tabular environment with different column alignments and borders", () => { + html = process(`\\begin{tabular}{|r||l|}a & b\\\\c & d\\end{tabular}`); expect(normalizeHtml(html)).toEqual( normalizeHtml( - ` - - - - - - - - - - -
    ab
    cd
    ` + `` + + `abcd` ) ); }); @@ -204,12 +200,14 @@ describe("unified-latex-to-pretext:unified-latex-to-pretext", () => { ); html = process(`a\\section{foo} b\n\nc`); expect(normalizeHtml(html)).toEqual( - normalizeHtml(`

    a

    foo

    b

    c

    `) + normalizeHtml( + `

    a

    foo

    b

    c

    ` + ) ); html = process(`a\\section{foo} b\\section{bar}\n\nc`); expect(normalizeHtml(html)).toEqual( normalizeHtml( - `

    a

    foo

    b

    bar

    c

    ` + `

    a

    foo

    b

    bar

    c

    ` ) ); html = process(`a\n \\emph{b}\n\nc`); @@ -218,18 +216,16 @@ describe("unified-latex-to-pretext:unified-latex-to-pretext", () => { ); html = process(`a\n b\\begin{foo}x\\end{foo}c\n\nd`); expect(normalizeHtml(html)).toEqual( - normalizeHtml(`

    a b

    x

    c

    d

    `) + normalizeHtml(`

    a b

    x

    c

    d

    `) ); }); - it.skip("Macros aren't replaced with html code in math mode", () => { + it("Macros aren't replaced with html code in math mode", () => { let ast; // Custom labels are handled ast = process(`\\[a\\\\b\\]`); - expect(normalizeHtml(ast)).toEqual( - normalizeHtml(`
    a\\\\b
    `) - ); + expect(normalizeHtml(ast)).toEqual(normalizeHtml(`a\\\\b`)); }); it("Ligatures that are nested inside of math mode are not replaced", () => { @@ -242,34 +238,33 @@ describe("unified-latex-to-pretext:unified-latex-to-pretext", () => { ); }); - it.skip("Pars are broken at display math", () => { + it("Pars are broken at display math", () => { let ast; ast = process(`x\n\ny\\[a\\\\b\\]z`); expect(normalizeHtml(ast)).toEqual( - normalizeHtml( - `

    x

    y

    a\\\\b

    z

    ` - ) + normalizeHtml(`

    x

    ya\\\\bz

    `) ); }); - it.skip("replaces command inside argument", () => { + it("replaces command inside argument", () => { let ast; ast = process(`\\emph{\\bfseries b}`); expect(normalizeHtml(ast)).toEqual( - normalizeHtml('b') + normalizeHtml("b") ); }); - it.skip("replaces command inside enumerate", () => { + + it("replaces command inside enumerate", () => { let ast; ast = process(`\\begin{enumerate}\\item\\bfseries b\\end{enumerate}`); expect(normalizeHtml(ast)).toEqual( - normalizeHtml(`
      -
    1. -

      b

      -
    2. -
    `) + normalizeHtml(`
      +
    1. +

      b

      +
    2. +
    `) ); }); it("replaces paragraphs", () => { @@ -277,9 +272,9 @@ describe("unified-latex-to-pretext:unified-latex-to-pretext", () => { ast = process(`\\paragraph{Important.} Paragraph`); expect(normalizeHtml(ast)).toEqual( - normalizeHtml(` - Important. Paragraph - `) + normalizeHtml( + `Important. Paragraph` + ) ); }); it("custom replacers work", () => { @@ -307,6 +302,7 @@ describe("unified-latex-to-pretext:unified-latex-to-pretext", () => { yyy: (node) => htmlLike({ tag: "yyy", content: node.content }), }, + producePretextFragment: true, }) .use(xmlCompilePlugin) .processSync({ value }).value as string; @@ -348,6 +344,7 @@ describe("unified-latex-to-pretext:unified-latex-to-pretext", () => { }); }, }, + producePretextFragment: true, }) .use(xmlCompilePlugin) .processSync({ value }).value as string; diff --git a/packages/unified-latex-to-pretext/tests/unified-latex-to-xml-like.test.ts b/packages/unified-latex-to-pretext/tests/unified-latex-to-xml-like.test.ts index 2f613e84..4fbb6545 100644 --- a/packages/unified-latex-to-pretext/tests/unified-latex-to-xml-like.test.ts +++ b/packages/unified-latex-to-pretext/tests/unified-latex-to-xml-like.test.ts @@ -1,8 +1,8 @@ import { describe, it, expect } from "vitest"; import { processLatexViaUnified } from "@unified-latex/unified-latex"; -import { VFile } from "unified-lint-rule/lib"; +import { VFile } from "vfile"; import util from "util"; -import { unifiedLatexToXmlLike } from "../libs/unified-latex-plugin-to-xml-like"; +import { unifiedLatexToPretextLike } from "../libs/unified-latex-plugin-to-pretext-like"; import { htmlLike } from "@unified-latex/unified-latex-util-html-like"; import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; @@ -18,7 +18,7 @@ describe("unified-latex-to-pretext:unified-latex-to-xml-like", () => { let file: VFile; const process = (value: string) => processLatexViaUnified() - .use(unifiedLatexToXmlLike) + .use(unifiedLatexToPretextLike, { producePretextFragment: true }) .processSync({ value }); it("wrap pars and streaming commands", () => { @@ -27,26 +27,26 @@ describe("unified-latex-to-pretext:unified-latex-to-xml-like", () => { file = process("\\bfseries a\n\nb"); expect(file.value).toEqual( - '\\html-tag:p{\\html-tag:b{\\html-attr:className{"textbf"}a}}\\html-tag:p{\\html-tag:b{\\html-attr:className{"textbf"}b}}' + "\\html-tag:p{\\html-tag:alert{a}}\\html-tag:p{\\html-tag:alert{b}}" ); file = process("\\bf a\n\nb"); expect(file.value).toEqual( - '\\html-tag:p{\\html-tag:b{\\html-attr:className{"textbf"}a}}\\html-tag:p{\\html-tag:b{\\html-attr:className{"textbf"}b}}' + "\\html-tag:p{\\html-tag:alert{a}}\\html-tag:p{\\html-tag:alert{b}}" ); file = process( "\\begin{enumerate}\\item foo\\item bar\\end{enumerate}" ); expect(file.value).toEqual( - '\\html-tag:ol{\\html-attr:className{"enumerate"}\\html-tag:li{\\html-tag:p{foo}}\\html-tag:li{\\html-tag:p{bar}}}' + "\\html-tag:ol{\\html-tag:li{\\html-tag:p{foo}}\\html-tag:li{\\html-tag:p{bar}}}" ); }); it("can accept custom replacers", () => { const process = (value: string) => processLatexViaUnified({ macros: { xxx: { signature: "m m" } } }) - .use(unifiedLatexToXmlLike, { + .use(unifiedLatexToPretextLike, { macroReplacements: { xxx: (node) => htmlLike({ @@ -63,6 +63,7 @@ describe("unified-latex-to-pretext:unified-latex-to-xml-like", () => { yyy: (node) => htmlLike({ tag: "yyy", content: node.content }), }, + producePretextFragment: true, }) .processSync({ value }); From 3581267a8f4fb58368bd9e6d360d3831dca28c3c Mon Sep 17 00:00:00 2001 From: Renee <95993773+renee-k@users.noreply.github.com> Date: Tue, 20 Aug 2024 11:41:52 -0400 Subject: [PATCH 6/8] Added LaTeX to PreTeXt Plugin to the CLI package (#113) * started adding pretext package to cli --- packages/unified-latex-cli/libs/unified-args/index.ts | 6 ++++++ packages/unified-latex-cli/libs/unified-args/options.ts | 2 ++ packages/unified-latex-cli/libs/unified-args/schema.ts | 7 +++++++ 3 files changed, 15 insertions(+) diff --git a/packages/unified-latex-cli/libs/unified-args/index.ts b/packages/unified-latex-cli/libs/unified-args/index.ts index 47d814aa..f4e12060 100644 --- a/packages/unified-latex-cli/libs/unified-args/index.ts +++ b/packages/unified-latex-cli/libs/unified-args/index.ts @@ -12,6 +12,7 @@ import { } from "unified-engine"; import { unifiedLatexToHast } from "@unified-latex/unified-latex-to-hast"; import { unifiedLatexToMdast } from "@unified-latex/unified-latex-to-mdast"; +import { unifiedLatexToPretext } from "@unified-latex/unified-latex-to-pretext"; import { options, Options } from "./options"; import { availableLints } from "../lints"; import { statsJsonPlugin, statsPlugin } from "../stats"; @@ -168,6 +169,11 @@ export function unifiedArgs(cliConfig: Options) { config.plugins.push([remarkStringify as any]); } + if (config.pretext) { + config.plugins.push([unifiedLatexToPretext]); + config.plugins.push([prettyPrintHtmlPlugin]); + } + /** * Handle complete run. * diff --git a/packages/unified-latex-cli/libs/unified-args/options.ts b/packages/unified-latex-cli/libs/unified-args/options.ts index 2e1c81f5..8f9f74c5 100644 --- a/packages/unified-latex-cli/libs/unified-args/options.ts +++ b/packages/unified-latex-cli/libs/unified-args/options.ts @@ -158,6 +158,7 @@ export function options(flags: string[], configuration: Options) { ), html: config.html, markdown: config.markdown, + pretext: config.pretext, } as EngineOptions & { help: boolean; helpMessage: string; @@ -172,6 +173,7 @@ export function options(flags: string[], configuration: Options) { macro: { name: string; signature: string }[]; html: boolean; markdown: boolean; + pretext: boolean; }; } diff --git a/packages/unified-latex-cli/libs/unified-args/schema.ts b/packages/unified-latex-cli/libs/unified-args/schema.ts index e209256b..a15e4365 100644 --- a/packages/unified-latex-cli/libs/unified-args/schema.ts +++ b/packages/unified-latex-cli/libs/unified-args/schema.ts @@ -191,6 +191,13 @@ export const schema: Option[] = [ type: "boolean", default: false, }, + { + long: "pretext", + description: + "Convert the output to PreTeXt. Note, you should expand/replace any macros not recognized by the converter", + type: "boolean", + default: false, + }, { long: "stdout", description: "[Don't] write the processed file's contents to stdout", From f5c61ff1faa9d6aa6ee8d1ffd2fc98aaccea5ff1 Mon Sep 17 00:00:00 2001 From: Jason Siefken Date: Tue, 20 Aug 2024 11:50:00 -0400 Subject: [PATCH 7/8] Upgrade deps --- CHANGELOG.md | 9 + package-lock.json | 1916 ++++++++++++++++++++------------------------- package.json | 22 +- 3 files changed, 857 insertions(+), 1090 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 005f119a..146a7ff6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # unified-latex Changelog +### v1.8.0 + +- Added initial PreTeXt conversion support +- Upgraded deps +- Added `amsart` macros +- Consume the whitespace after special character macros when expanding ligatures. For example `\o y` produces `øy` instead of `ø y` +- Fix signatures of `\hyphenation` + + ### v1.7.1 - Types fix for `@unified-latex/unified-latex-types` diff --git a/package-lock.json b/package-lock.json index da6ada7e..9b1b4246 100755 --- a/package-lock.json +++ b/package-lock.json @@ -33,12 +33,12 @@ "unified-engine": "^10.1.0", "unified-lint-rule": "^2.1.1", "unist-util-position": "^4.0.4", - "vfile-reporter-json": "^3.2.0", + "vfile-reporter-json": "^3.3.0", "vfile-reporter-position": "^0.1.7", "vfile-reporter-pretty": "^6.1.1" }, "devDependencies": { - "@types/node": "^20.12.12", + "@types/node": "^20.16.1", "@types/prettier": "^2.7.3", "@types/shelljs": "^0.8.15", "esbuild": "^0.21.2", @@ -54,16 +54,29 @@ "remark-gfm": "^3.0.1", "remark-parse": "^10.0.2", "remark-stringify": "^10.0.3", - "rimraf": "^5.0.7", + "rimraf": "^6.0.1", "shx": "^0.3.4", - "ts-morph": "^22.0.0", - "typedoc": "^0.25.13", - "typescript": "^5.4.5", - "vite": "^5.2.11", - "vite-plugin-dts": "^3.9.1", - "vite-plugin-static-copy": "^1.0.4", - "vitest": "^1.6.0", - "wireit": "^0.14.4" + "ts-morph": "^23.0.0", + "typedoc": "^0.26.6", + "typescript": "^5.5.4", + "vite": "^5.4.2", + "vite-plugin-dts": "^4.0.3", + "vite-plugin-static-copy": "^1.0.6", + "vitest": "^2.0.5", + "wireit": "^0.14.7" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/@babel/code-frame": { @@ -134,10 +147,19 @@ "node": ">=4" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "engines": { "node": ">=6.9.0" } @@ -212,10 +234,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", - "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", + "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", "dev": true, + "dependencies": { + "@babel/types": "^7.25.2" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -223,10 +248,24 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/types": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", + "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.2.tgz", - "integrity": "sha512-/c7hocx0pm14bHQlqUVKmxwdT/e5/KkyoY1W8F9lk/8CkE037STDDz8PXUP/LE6faj2HqchvDs9GcShxFhI78Q==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ "ppc64" ], @@ -240,9 +279,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.2.tgz", - "integrity": "sha512-G1ve3b4FeyJeyCjB4MX1CiWyTaIJwT9wAYE+8+IRA53YoN/reC/Bf2GDRXAzDTnh69Fpl+1uIKg76DiB3U6vwQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], @@ -256,9 +295,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.2.tgz", - "integrity": "sha512-SGZKngoTWVUriO5bDjI4WDGsNx2VKZoXcds+ita/kVYB+8IkSCKDRDaK+5yu0b5S0eq6B3S7fpiEvpsa2ammlQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], @@ -272,9 +311,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.2.tgz", - "integrity": "sha512-1wzzNoj2QtNkAYwIcWJ66UTRA80+RTQ/kuPMtEuP0X6dp5Ar23Dn566q3aV61h4EYrrgGlOgl/HdcqN/2S/2vg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], @@ -288,9 +327,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.2.tgz", - "integrity": "sha512-ZyMkPWc5eTROcLOA10lEqdDSTc6ds6nuh3DeHgKip/XJrYjZDfnkCVSty8svWdy+SC1f77ULtVeIqymTzaB6/Q==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -304,9 +343,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.2.tgz", - "integrity": "sha512-K4ZdVq1zP9v51h/cKVna7im7G0zGTKKB6bP2yJiSmHjjOykbd8DdhrSi8V978sF69rkwrn8zCyL2t6I3ei6j9A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], @@ -320,9 +359,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.2.tgz", - "integrity": "sha512-4kbOGdpA61CXqadD+Gb/Pw3YXamQGiz9mal/h93rFVSjr5cgMnmJd/gbfPRm+3BMifvnaOfS1gNWaIDxkE2A3A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], @@ -336,9 +375,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.2.tgz", - "integrity": "sha512-ShS+R09nuHzDBfPeMUliKZX27Wrmr8UFp93aFf/S8p+++x5BZ+D344CLKXxmY6qzgTL3mILSImPCNJOzD6+RRg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], @@ -352,9 +391,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.2.tgz", - "integrity": "sha512-nnGXjOAv+7cM3LYRx4tJsYdgy8dGDGkAzF06oIDGppWbUkUKN9SmgQA8H0KukpU0Pjrj9XmgbWqMVSX/U7eeTA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], @@ -368,9 +407,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.2.tgz", - "integrity": "sha512-Hdu8BL+AmO+eCDvvT6kz/fPQhvuHL8YK4ExKZfANWsNe1kFGOHw7VJvS/FKSLFqheXmB3rTF3xFQIgUWPYsGnA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], @@ -384,9 +423,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.2.tgz", - "integrity": "sha512-m73BOCW2V9lcj7RtEMi+gBfHC6n3+VHpwQXP5offtQMPLDkpVolYn1YGXxOZ9hp4h3UPRKuezL7WkBsw+3EB3Q==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], @@ -400,9 +439,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.2.tgz", - "integrity": "sha512-84eYHwwWHq3myIY/6ikALMcnwkf6Qo7NIq++xH0x+cJuUNpdwh8mlpUtRY+JiGUc60yu7ElWBbVHGWTABTclGw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], @@ -416,9 +455,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.2.tgz", - "integrity": "sha512-9siSZngT0/ZKG+AH+/agwKF29LdCxw4ODi/PiE0F52B2rtLozlDP92umf8G2GPoVV611LN4pZ+nSTckebOscUA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], @@ -432,9 +471,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.2.tgz", - "integrity": "sha512-y0T4aV2CA+ic04ULya1A/8M2RDpDSK2ckgTj6jzHKFJvCq0jQg8afQQIn4EM0G8u2neyOiNHgSF9YKPfuqKOVw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], @@ -448,9 +487,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.2.tgz", - "integrity": "sha512-x5ssCdXmZC86L2Li1qQPF/VaC4VP20u/Zm8jlAu9IiVOVi79YsSz6cpPDYZl1rfKSHYCJW9XBfFCo66S5gVPSA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], @@ -464,9 +503,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.2.tgz", - "integrity": "sha512-NP7fTpGSFWdXyvp8iAFU04uFh9ARoplFVM/m+8lTRpaYG+2ytHPZWyscSsMM6cvObSIK2KoPHXiZD4l99WaxbQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], @@ -480,9 +519,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.2.tgz", - "integrity": "sha512-giZ/uOxWDKda44ZuyfKbykeXznfuVNkTgXOUOPJIjbayJV6FRpQ4zxUy9JMBPLaK9IJcdWtaoeQrYBMh3Rr4vQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -496,9 +535,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.2.tgz", - "integrity": "sha512-IeFMfGFSQfIj1d4XU+6lkbFzMR+mFELUUVYrZ+jvWzG4NGvs6o53ReEHLHpYkjRbdEjJy2W3lTekTxrFHW7YJg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], @@ -512,9 +551,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.2.tgz", - "integrity": "sha512-48QhWD6WxcebNNaE4FCwgvQVUnAycuTd+BdvA/oZu+/MmbpU8pY2dMEYlYzj5uNHWIG5jvdDmFXu0naQeOWUoA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], @@ -528,9 +567,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.2.tgz", - "integrity": "sha512-90r3nTBLgdIgD4FCVV9+cR6Hq2Dzs319icVsln+NTmTVwffWcCqXGml8rAoocHuJ85kZK36DCteii96ba/PX8g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], @@ -544,9 +583,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.2.tgz", - "integrity": "sha512-sNndlsBT8OeE/MZDSGpRDJlWuhjuUz/dn80nH0EP4ZzDUYvMDVa7G87DVpweBrn4xdJYyXS/y4CQNrf7R2ODXg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], @@ -560,9 +599,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.2.tgz", - "integrity": "sha512-Ti2QChGNFzWhUNNVuU4w21YkYTErsNh3h+CzvlEhzgRbwsJ7TrWQqRzW3bllLKKvTppuF3DJ3XP1GEg11AfrEQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], @@ -576,9 +615,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.2.tgz", - "integrity": "sha512-VEfTCZicoZnZ6sGkjFPGRFFJuL2fZn2bLhsekZl1CJslflp2cJS/VoKs1jMk+3pDfsGW6CfQVUckP707HwbXeQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], @@ -701,12 +740,54 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@lerna/create": { "version": "8.1.3", "resolved": "https://registry.npmjs.org/@lerna/create/-/create-8.1.3.tgz", @@ -904,18 +985,18 @@ } }, "node_modules/@microsoft/api-extractor": { - "version": "7.43.0", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.43.0.tgz", - "integrity": "sha512-GFhTcJpB+MI6FhvXEI9b2K0snulNLWHqC/BbcJtyNYcKUiw7l3Lgis5ApsYncJ0leALX7/of4XfmXk+maT111w==", - "dev": true, - "dependencies": { - "@microsoft/api-extractor-model": "7.28.13", - "@microsoft/tsdoc": "0.14.2", - "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "4.0.2", - "@rushstack/rig-package": "0.5.2", - "@rushstack/terminal": "0.10.0", - "@rushstack/ts-command-line": "4.19.1", + "version": "7.47.4", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.47.4.tgz", + "integrity": "sha512-HKm+P4VNzWwvq1Ey+Jfhhj/3MjsD+ka2hbt8L5AcRM95lu1MFOYnz3XlU7Gr79Q/ZhOb7W/imAKeYrOI0bFydg==", + "dev": true, + "dependencies": { + "@microsoft/api-extractor-model": "7.29.4", + "@microsoft/tsdoc": "~0.15.0", + "@microsoft/tsdoc-config": "~0.17.0", + "@rushstack/node-core-library": "5.5.1", + "@rushstack/rig-package": "0.5.3", + "@rushstack/terminal": "0.13.3", + "@rushstack/ts-command-line": "4.22.3", "lodash": "~4.17.15", "minimatch": "~3.0.3", "resolve": "~1.22.1", @@ -928,14 +1009,14 @@ } }, "node_modules/@microsoft/api-extractor-model": { - "version": "7.28.13", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.13.tgz", - "integrity": "sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw==", + "version": "7.29.4", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.29.4.tgz", + "integrity": "sha512-LHOMxmT8/tU1IiiiHOdHFF83Qsi+V8d0kLfscG4EvQE9cafiR8blOYr8SfkQKWB1wgEilQgXJX3MIA4vetDLZw==", "dev": true, "dependencies": { - "@microsoft/tsdoc": "0.14.2", - "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "4.0.2" + "@microsoft/tsdoc": "~0.15.0", + "@microsoft/tsdoc-config": "~0.17.0", + "@rushstack/node-core-library": "5.5.1" } }, "node_modules/@microsoft/api-extractor/node_modules/typescript": { @@ -952,34 +1033,21 @@ } }, "node_modules/@microsoft/tsdoc": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", - "integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.0.tgz", + "integrity": "sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==", "dev": true }, "node_modules/@microsoft/tsdoc-config": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz", - "integrity": "sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.17.0.tgz", + "integrity": "sha512-v/EYRXnCAIHxOHW+Plb6OWuUoMotxTN0GLatnpOb1xq0KuTNw/WI3pamJx/UbsoJP5k9MCw1QxvvhPcF9pH3Zg==", "dev": true, "dependencies": { - "@microsoft/tsdoc": "0.14.2", - "ajv": "~6.12.6", + "@microsoft/tsdoc": "0.15.0", + "ajv": "~8.12.0", "jju": "~1.4.0", - "resolve": "~1.19.0" - } - }, - "node_modules/@microsoft/tsdoc-config/node_modules/resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", - "dev": true, - "dependencies": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "resolve": "~1.22.2" } }, "node_modules/@nodelib/fs.scandir": { @@ -1761,9 +1829,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.2.tgz", - "integrity": "sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.0.tgz", + "integrity": "sha512-WTWD8PfoSAJ+qL87lE7votj3syLavxunWhzCnx3XFxFiI/BA/r3X7MUM8dVrH8rb2r4AiO8jJsr3ZjdaftmnfA==", "cpu": [ "arm" ], @@ -1774,9 +1842,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.2.tgz", - "integrity": "sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.0.tgz", + "integrity": "sha512-a1sR2zSK1B4eYkiZu17ZUZhmUQcKjk2/j9Me2IDjk1GHW7LB5Z35LEzj9iJch6gtUfsnvZs1ZNyDW2oZSThrkA==", "cpu": [ "arm64" ], @@ -1787,9 +1855,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.2.tgz", - "integrity": "sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.0.tgz", + "integrity": "sha512-zOnKWLgDld/svhKO5PD9ozmL6roy5OQ5T4ThvdYZLpiOhEGY+dp2NwUmxK0Ld91LrbjrvtNAE0ERBwjqhZTRAA==", "cpu": [ "arm64" ], @@ -1800,9 +1868,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.2.tgz", - "integrity": "sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.0.tgz", + "integrity": "sha512-7doS8br0xAkg48SKE2QNtMSFPFUlRdw9+votl27MvT46vo44ATBmdZdGysOevNELmZlfd+NEa0UYOA8f01WSrg==", "cpu": [ "x64" ], @@ -1813,9 +1881,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.2.tgz", - "integrity": "sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.0.tgz", + "integrity": "sha512-pWJsfQjNWNGsoCq53KjMtwdJDmh/6NubwQcz52aEwLEuvx08bzcy6tOUuawAOncPnxz/3siRtd8hiQ32G1y8VA==", "cpu": [ "arm" ], @@ -1826,9 +1894,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.2.tgz", - "integrity": "sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.0.tgz", + "integrity": "sha512-efRIANsz3UHZrnZXuEvxS9LoCOWMGD1rweciD6uJQIx2myN3a8Im1FafZBzh7zk1RJ6oKcR16dU3UPldaKd83w==", "cpu": [ "arm" ], @@ -1839,9 +1907,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz", - "integrity": "sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.0.tgz", + "integrity": "sha512-ZrPhydkTVhyeGTW94WJ8pnl1uroqVHM3j3hjdquwAcWnmivjAwOYjTEAuEDeJvGX7xv3Z9GAvrBkEzCgHq9U1w==", "cpu": [ "arm64" ], @@ -1852,9 +1920,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.2.tgz", - "integrity": "sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.0.tgz", + "integrity": "sha512-cfaupqd+UEFeURmqNP2eEvXqgbSox/LHOyN9/d2pSdV8xTrjdg3NgOFJCtc1vQ/jEke1qD0IejbBfxleBPHnPw==", "cpu": [ "arm64" ], @@ -1865,9 +1933,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.2.tgz", - "integrity": "sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.0.tgz", + "integrity": "sha512-ZKPan1/RvAhrUylwBXC9t7B2hXdpb/ufeu22pG2psV7RN8roOfGurEghw1ySmX/CmDDHNTDDjY3lo9hRlgtaHg==", "cpu": [ "ppc64" ], @@ -1878,9 +1946,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.2.tgz", - "integrity": "sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.0.tgz", + "integrity": "sha512-H1eRaCwd5E8eS8leiS+o/NqMdljkcb1d6r2h4fKSsCXQilLKArq6WS7XBLDu80Yz+nMqHVFDquwcVrQmGr28rg==", "cpu": [ "riscv64" ], @@ -1891,9 +1959,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.2.tgz", - "integrity": "sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.0.tgz", + "integrity": "sha512-zJ4hA+3b5tu8u7L58CCSI0A9N1vkfwPhWd/puGXwtZlsB5bTkwDNW/+JCU84+3QYmKpLi+XvHdmrlwUwDA6kqw==", "cpu": [ "s390x" ], @@ -1904,9 +1972,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz", - "integrity": "sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.0.tgz", + "integrity": "sha512-e2hrvElFIh6kW/UNBQK/kzqMNY5mO+67YtEh9OA65RM5IJXYTWiXjX6fjIiPaqOkBthYF1EqgiZ6OXKcQsM0hg==", "cpu": [ "x64" ], @@ -1917,9 +1985,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.2.tgz", - "integrity": "sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.0.tgz", + "integrity": "sha512-1vvmgDdUSebVGXWX2lIcgRebqfQSff0hMEkLJyakQ9JQUbLDkEaMsPTLOmyccyC6IJ/l3FZuJbmrBw/u0A0uCQ==", "cpu": [ "x64" ], @@ -1930,9 +1998,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.2.tgz", - "integrity": "sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.0.tgz", + "integrity": "sha512-s5oFkZ/hFcrlAyBTONFY1TWndfyre1wOMwU+6KCpm/iatybvrRgmZVM+vCFwxmC5ZhdlgfE0N4XorsDpi7/4XQ==", "cpu": [ "arm64" ], @@ -1943,9 +2011,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.2.tgz", - "integrity": "sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.0.tgz", + "integrity": "sha512-G9+TEqRnAA6nbpqyUqgTiopmnfgnMkR3kMukFBDsiyy23LZvUCpiUwjTRx6ezYCjJODXrh52rBR9oXvm+Fp5wg==", "cpu": [ "ia32" ], @@ -1956,9 +2024,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.2.tgz", - "integrity": "sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.0.tgz", + "integrity": "sha512-2jsCDZwtQvRhejHLfZ1JY6w6kEuEtfF9nzYsZxzSlNVKDX+DpsDJ+Rbjkm74nvg2rdx0gwBS+IMdvwJuq3S9pQ==", "cpu": [ "x64" ], @@ -1969,17 +2037,19 @@ ] }, "node_modules/@rushstack/node-core-library": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-4.0.2.tgz", - "integrity": "sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.5.1.tgz", + "integrity": "sha512-ZutW56qIzH8xIOlfyaLQJFx+8IBqdbVCZdnj+XT1MorQ1JqqxHse8vbCpEM+2MjsrqcbxcgDIbfggB1ZSQ2A3g==", "dev": true, "dependencies": { + "ajv": "~8.13.0", + "ajv-draft-04": "~1.0.0", + "ajv-formats": "~3.0.1", "fs-extra": "~7.0.1", "import-lazy": "~4.0.0", "jju": "~1.4.0", "resolve": "~1.22.1", - "semver": "~7.5.4", - "z-schema": "~5.0.2" + "semver": "~7.5.4" }, "peerDependencies": { "@types/node": "*" @@ -1990,6 +2060,22 @@ } } }, + "node_modules/@rushstack/node-core-library/node_modules/ajv": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/@rushstack/node-core-library/node_modules/fs-extra": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", @@ -2023,9 +2109,9 @@ } }, "node_modules/@rushstack/rig-package": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.2.tgz", - "integrity": "sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.3.tgz", + "integrity": "sha512-olzSSjYrvCNxUFZowevC3uz8gvKr3WTpHQ7BkpjtRpA3wK+T0ybep/SRUMfr195gBzJm5gaXw0ZMgjIyHqJUow==", "dev": true, "dependencies": { "resolve": "~1.22.1", @@ -2033,12 +2119,12 @@ } }, "node_modules/@rushstack/terminal": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.10.0.tgz", - "integrity": "sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==", + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.13.3.tgz", + "integrity": "sha512-fc3zjXOw8E0pXS5t9vTiIPx9gHA0fIdTXsu9mT4WbH+P3mYvnrX0iAQ5a6NvyK1+CqYWBTw/wVNx7SDJkI+WYQ==", "dev": true, "dependencies": { - "@rushstack/node-core-library": "4.0.2", + "@rushstack/node-core-library": "5.5.1", "supports-color": "~8.1.1" }, "peerDependencies": { @@ -2066,12 +2152,12 @@ } }, "node_modules/@rushstack/ts-command-line": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.19.1.tgz", - "integrity": "sha512-J7H768dgcpG60d7skZ5uSSwyCZs/S2HrWP1Ds8d1qYAyaaeJmpmmLr9BVw97RjFzmQPOYnoXcKA4GkqDCkduQg==", + "version": "4.22.3", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.22.3.tgz", + "integrity": "sha512-edMpWB3QhFFZ4KtSzS8WNjBgR4PXPPOVrOHMbb7kNpmQ1UFS9HdVtjCXg1H5fG+xYAbeE+TMPcVPUyX2p84STA==", "dev": true, "dependencies": { - "@rushstack/terminal": "0.10.0", + "@rushstack/terminal": "0.13.3", "@types/argparse": "1.0.38", "argparse": "~1.0.9", "string-argv": "~0.3.1" @@ -2086,6 +2172,24 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/@shikijs/core": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.14.1.tgz", + "integrity": "sha512-KyHIIpKNaT20FtFPFjCQB5WVSTpLR/n+jQXhWHWVUMm9MaOaG9BGOG0MSyt7yA4+Lm+4c9rTc03tt3nYzeYSfw==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/core/node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@sigstore/bundle": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz", @@ -2194,13 +2298,13 @@ } }, "node_modules/@ts-morph/common": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.23.0.tgz", - "integrity": "sha512-m7Lllj9n/S6sOkCkRftpM7L24uvmfXQFedlW/4hENcuJH1HHm9u5EgxZb9uVjQSCGrbBWBkOGgcTxNg36r6ywA==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.24.0.tgz", + "integrity": "sha512-c1xMmNHWpNselmpIqursHeOHHBTIsJLbB+NuovbTTRCNiTLEr/U9dbJ8qy0jd/O2x5pc3seWuOUN5R2IoOTp8A==", "dev": true, "dependencies": { "fast-glob": "^3.3.2", - "minimatch": "^9.0.3", + "minimatch": "^9.0.4", "mkdirp": "^3.0.1", "path-browserify": "^1.0.1" } @@ -2215,9 +2319,9 @@ } }, "node_modules/@ts-morph/common/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -2400,11 +2504,11 @@ "integrity": "sha512-xPSg0jm4mqgEkNhowKgZFBNtwoEwF6gJ4Dhww+GFpm3IgtNseHQZ5IqdNwnquZEoANxyDAKDRAdVo4Z72VvD/g==" }, "node_modules/@types/node": { - "version": "20.12.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", - "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", + "version": "20.16.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.1.tgz", + "integrity": "sha512-zJDo7wEadFtSyNz5QITDfRcrhqDvQI1xQNQ0VoizPjM/dVAODqqIUWbJPkvsxmTI0MYRGRikcdjMPhOssnPejQ==", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/@types/normalize-package-data": { @@ -2468,7 +2572,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/xast/-/xast-2.0.4.tgz", "integrity": "sha512-6Q6HWhHXR5EEKcxgF5YBW5XPAAtCi/GgyCWHx6wR7dZTXF5rv2B2fm0hgpSscJqaVDVm6n1DAVbsM8RSM5PlMw==", - "dev": true, "dependencies": { "@types/unist": "*" } @@ -2619,84 +2722,81 @@ "link": true }, "node_modules/@vitest/expect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", - "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.0.5.tgz", + "integrity": "sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==", "dev": true, "dependencies": { - "@vitest/spy": "1.6.0", - "@vitest/utils": "1.6.0", - "chai": "^4.3.10" + "@vitest/spy": "2.0.5", + "@vitest/utils": "2.0.5", + "chai": "^5.1.1", + "tinyrainbow": "^1.2.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/runner": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", - "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", + "node_modules/@vitest/pretty-format": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.0.5.tgz", + "integrity": "sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==", "dev": true, "dependencies": { - "@vitest/utils": "1.6.0", - "p-limit": "^5.0.0", - "pathe": "^1.1.1" + "tinyrainbow": "^1.2.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/runner/node_modules/p-limit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", - "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", + "node_modules/@vitest/runner": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.0.5.tgz", + "integrity": "sha512-TfRfZa6Bkk9ky4tW0z20WKXFEwwvWhRY+84CnSEtq4+3ZvDlJyY32oNTJtM7AW9ihW90tX/1Q78cb6FjoAs+ig==", "dev": true, "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": ">=18" + "@vitest/utils": "2.0.5", + "pathe": "^1.1.2" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/snapshot": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", - "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.0.5.tgz", + "integrity": "sha512-SgCPUeDFLaM0mIUHfaArq8fD2WbaXG/zVXjRupthYfYGzc8ztbFbu6dUNOblBG7XLMR1kEhS/DNnfCZ2IhdDew==", "dev": true, "dependencies": { - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "pretty-format": "^29.7.0" + "@vitest/pretty-format": "2.0.5", + "magic-string": "^0.30.10", + "pathe": "^1.1.2" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/spy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", - "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.0.5.tgz", + "integrity": "sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==", "dev": true, "dependencies": { - "tinyspy": "^2.2.0" + "tinyspy": "^3.0.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/utils": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", - "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.0.5.tgz", + "integrity": "sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==", "dev": true, "dependencies": { - "diff-sequences": "^29.6.3", + "@vitest/pretty-format": "2.0.5", "estree-walker": "^3.0.3", - "loupe": "^2.3.7", - "pretty-format": "^29.7.0" + "loupe": "^3.1.1", + "tinyrainbow": "^1.2.0" }, "funding": { "url": "https://opencollective.com/vitest" @@ -2712,71 +2812,78 @@ } }, "node_modules/@volar/language-core": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-1.11.1.tgz", - "integrity": "sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.0.tgz", + "integrity": "sha512-FTla+khE+sYK0qJP+6hwPAAUwiNHVMph4RUXpxf/FIPKUP61NFrVZorml4mjFShnueR2y9/j8/vnh09YwVdH7A==", "dev": true, "dependencies": { - "@volar/source-map": "1.11.1" + "@volar/source-map": "2.4.0" } }, "node_modules/@volar/source-map": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-1.11.1.tgz", - "integrity": "sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==", - "dev": true, - "dependencies": { - "muggle-string": "^0.3.1" - } + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.0.tgz", + "integrity": "sha512-2ceY8/NEZvN6F44TXw2qRP6AQsvCYhV2bxaBPWxV9HqIfkbRydSksTFObCF1DBDNBfKiZTS8G/4vqV6cvjdOIQ==", + "dev": true }, "node_modules/@volar/typescript": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-1.11.1.tgz", - "integrity": "sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.0.tgz", + "integrity": "sha512-9zx3lQWgHmVd+JRRAHUSRiEhe4TlzL7U7e6ulWXOxHH/WNYxzKwCvZD7WYWEZFdw4dHfTD9vUR0yPQO6GilCaQ==", "dev": true, "dependencies": { - "@volar/language-core": "1.11.1", - "path-browserify": "^1.0.1" + "@volar/language-core": "2.4.0", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" } }, "node_modules/@vue/compiler-core": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.19.tgz", - "integrity": "sha512-gj81785z0JNzRcU0Mq98E56e4ltO1yf8k5PQ+tV/7YHnbZkrM0fyFyuttnN8ngJZjbpofWE/m4qjKBiLl8Ju4w==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.38.tgz", + "integrity": "sha512-8IQOTCWnLFqfHzOGm9+P8OPSEDukgg3Huc92qSG49if/xI2SAwLHQO2qaPQbjCWPBcQoO1WYfXfTACUrWV3c5A==", "dev": true, "dependencies": { - "@babel/parser": "^7.23.9", - "@vue/shared": "3.4.19", + "@babel/parser": "^7.24.7", + "@vue/shared": "3.4.38", "entities": "^4.5.0", "estree-walker": "^2.0.2", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-dom": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.19.tgz", - "integrity": "sha512-vm6+cogWrshjqEHTzIDCp72DKtea8Ry/QVpQRYoyTIg9k7QZDX6D8+HGURjtmatfgM8xgCFtJJaOlCaRYRK3QA==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.38.tgz", + "integrity": "sha512-Osc/c7ABsHXTsETLgykcOwIxFktHfGSUDkb05V61rocEfsFDcjDLH/IHJSNJP+/Sv9KeN2Lx1V6McZzlSb9EhQ==", + "dev": true, + "dependencies": { + "@vue/compiler-core": "3.4.38", + "@vue/shared": "3.4.38" + } + }, + "node_modules/@vue/compiler-vue2": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", + "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", "dev": true, "dependencies": { - "@vue/compiler-core": "3.4.19", - "@vue/shared": "3.4.19" + "de-indent": "^1.0.2", + "he": "^1.2.0" } }, "node_modules/@vue/language-core": { - "version": "1.8.27", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.27.tgz", - "integrity": "sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==", + "version": "2.0.29", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.29.tgz", + "integrity": "sha512-o2qz9JPjhdoVj8D2+9bDXbaI4q2uZTHQA/dbyZT4Bj1FR9viZxDJnLcKVHfxdn6wsOzRgpqIzJEEmSSvgMvDTQ==", "dev": true, "dependencies": { - "@volar/language-core": "~1.11.1", - "@volar/source-map": "~1.11.1", - "@vue/compiler-dom": "^3.3.0", - "@vue/shared": "^3.3.0", + "@volar/language-core": "~2.4.0-alpha.18", + "@vue/compiler-dom": "^3.4.0", + "@vue/compiler-vue2": "^2.7.16", + "@vue/shared": "^3.4.0", "computeds": "^0.0.1", "minimatch": "^9.0.3", - "muggle-string": "^0.3.1", - "path-browserify": "^1.0.1", - "vue-template-compiler": "^2.7.14" + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1" }, "peerDependencies": { "typescript": "*" @@ -2797,9 +2904,9 @@ } }, "node_modules/@vue/language-core/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -2812,9 +2919,9 @@ } }, "node_modules/@vue/shared": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.19.tgz", - "integrity": "sha512-/KliRRHMF6LoiThEy+4c1Z4KB/gbPrGjWwJR+crg2otgrf/egKzRaCPvJ51S5oetgsgXLfc4Rm5ZgrKHZrtMSw==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.38.tgz", + "integrity": "sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw==", "dev": true }, "node_modules/@yarnpkg/lockfile": { @@ -2890,15 +2997,6 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/add-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", @@ -2943,14 +3041,14 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", "uri-js": "^4.2.2" }, "funding": { @@ -2958,6 +3056,37 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "dev": true, + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -2989,12 +3118,6 @@ "node": ">=8" } }, - "node_modules/ansi-sequence-parser": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz", - "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==", - "dev": true - }, "node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -3112,12 +3235,12 @@ } }, "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "engines": { - "node": "*" + "node": ">=12" } }, "node_modules/async": { @@ -3145,9 +3268,9 @@ } }, "node_modules/axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", "dev": true, "dependencies": { "follow-redirects": "^1.15.6", @@ -3225,11 +3348,11 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -3460,21 +3583,19 @@ } }, "node_modules/chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz", + "integrity": "sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==", "dev": true, "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=12" } }, "node_modules/chalk": { @@ -3522,15 +3643,12 @@ "dev": true }, "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, "engines": { - "node": "*" + "node": ">= 16" } }, "node_modules/chokidar": { @@ -3815,6 +3933,12 @@ "dot-prop": "^5.1.0" } }, + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "dev": true + }, "node_modules/computeds": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz", @@ -4064,9 +4188,9 @@ "dev": true }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dependencies": { "ms": "2.1.2" }, @@ -4132,13 +4256,10 @@ "dev": true }, "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, "engines": { "node": ">=6" } @@ -4514,9 +4635,9 @@ } }, "node_modules/esbuild": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.2.tgz", - "integrity": "sha512-LmHPAa5h4tSxz+g/D8IHY6wCjtIiFx8I7/Q0Aq+NmvtoYvyMnJU0KQJcqB6QH30X9x/W4CemgUtPgQDZFca5SA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "bin": { @@ -4526,29 +4647,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.2", - "@esbuild/android-arm": "0.21.2", - "@esbuild/android-arm64": "0.21.2", - "@esbuild/android-x64": "0.21.2", - "@esbuild/darwin-arm64": "0.21.2", - "@esbuild/darwin-x64": "0.21.2", - "@esbuild/freebsd-arm64": "0.21.2", - "@esbuild/freebsd-x64": "0.21.2", - "@esbuild/linux-arm": "0.21.2", - "@esbuild/linux-arm64": "0.21.2", - "@esbuild/linux-ia32": "0.21.2", - "@esbuild/linux-loong64": "0.21.2", - "@esbuild/linux-mips64el": "0.21.2", - "@esbuild/linux-ppc64": "0.21.2", - "@esbuild/linux-riscv64": "0.21.2", - "@esbuild/linux-s390x": "0.21.2", - "@esbuild/linux-x64": "0.21.2", - "@esbuild/netbsd-x64": "0.21.2", - "@esbuild/openbsd-x64": "0.21.2", - "@esbuild/sunos-x64": "0.21.2", - "@esbuild/win32-arm64": "0.21.2", - "@esbuild/win32-ia32": "0.21.2", - "@esbuild/win32-x64": "0.21.2" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/esbuild-runner": { @@ -4766,12 +4887,6 @@ "node": ">=8.6.0" } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -4838,9 +4953,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -7271,9 +7386,9 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, "node_modules/json-stringify-safe": { @@ -7914,6 +8029,15 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/load-json-file": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz", @@ -7985,18 +8109,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "dev": true - }, "node_modules/lodash.ismatch": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", @@ -8068,9 +8180,9 @@ } }, "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.1.tgz", + "integrity": "sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==", "dev": true, "dependencies": { "get-func-name": "^2.0.1" @@ -8094,12 +8206,12 @@ "dev": true }, "node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", "dev": true, "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" + "@jridgewell/sourcemap-codec": "^1.5.0" } }, "node_modules/make-dir": { @@ -8185,6 +8297,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, "node_modules/markdown-table": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", @@ -8195,18 +8324,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "dev": true, - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 12" - } - }, "node_modules/mdast-builder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/mdast-builder/-/mdast-builder-1.1.1.tgz", @@ -8706,6 +8823,12 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true + }, "node_modules/memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -10673,9 +10796,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/muggle-string": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.3.1.tgz", - "integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", "dev": true }, "node_modules/multimatch": { @@ -11864,6 +11987,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true + }, "node_modules/pacote": { "version": "17.0.7", "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.7.tgz", @@ -12397,12 +12526,12 @@ "dev": true }, "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true, "engines": { - "node": "*" + "node": ">= 14.16" } }, "node_modules/peggy": { @@ -12421,9 +12550,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", "dev": true }, "node_modules/picomatch": { @@ -12499,9 +12628,9 @@ } }, "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.4.41", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", + "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", "dev": true, "funding": [ { @@ -12519,7 +12648,7 @@ ], "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.0", + "picocolors": "^1.0.1", "source-map-js": "^1.2.0" }, "engines": { @@ -12682,6 +12811,15 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -13402,6 +13540,15 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "1.22.6", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", @@ -13473,18 +13620,19 @@ } }, "node_modules/rimraf": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", - "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", "dev": true, "dependencies": { - "glob": "^10.3.7" + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" }, "bin": { "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=14.18" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -13500,46 +13648,99 @@ } }, "node_modules/rimraf/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", + "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "node_modules/rimraf/node_modules/jackspeak": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.1.tgz", + "integrity": "sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==", "dev": true, "dependencies": { - "brace-expansion": "^2.0.1" + "@isaacs/cliui": "^8.0.2" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/rimraf/node_modules/lru-cache": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.0.tgz", + "integrity": "sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==", + "dev": true, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/rimraf/node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "dev": true, + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/rollup": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.17.2.tgz", - "integrity": "sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.0.tgz", + "integrity": "sha512-vo+S/lfA2lMS7rZ2Qoubi6I5hwZwzXeUIctILZLbHI+laNtvhhOIon2S1JksA5UEDQ7l3vberd0fxK44lTYjbQ==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -13552,22 +13753,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.17.2", - "@rollup/rollup-android-arm64": "4.17.2", - "@rollup/rollup-darwin-arm64": "4.17.2", - "@rollup/rollup-darwin-x64": "4.17.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.17.2", - "@rollup/rollup-linux-arm-musleabihf": "4.17.2", - "@rollup/rollup-linux-arm64-gnu": "4.17.2", - "@rollup/rollup-linux-arm64-musl": "4.17.2", - "@rollup/rollup-linux-powerpc64le-gnu": "4.17.2", - "@rollup/rollup-linux-riscv64-gnu": "4.17.2", - "@rollup/rollup-linux-s390x-gnu": "4.17.2", - "@rollup/rollup-linux-x64-gnu": "4.17.2", - "@rollup/rollup-linux-x64-musl": "4.17.2", - "@rollup/rollup-win32-arm64-msvc": "4.17.2", - "@rollup/rollup-win32-ia32-msvc": "4.17.2", - "@rollup/rollup-win32-x64-msvc": "4.17.2", + "@rollup/rollup-android-arm-eabi": "4.21.0", + "@rollup/rollup-android-arm64": "4.21.0", + "@rollup/rollup-darwin-arm64": "4.21.0", + "@rollup/rollup-darwin-x64": "4.21.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.21.0", + "@rollup/rollup-linux-arm-musleabihf": "4.21.0", + "@rollup/rollup-linux-arm64-gnu": "4.21.0", + "@rollup/rollup-linux-arm64-musl": "4.21.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.21.0", + "@rollup/rollup-linux-riscv64-gnu": "4.21.0", + "@rollup/rollup-linux-s390x-gnu": "4.21.0", + "@rollup/rollup-linux-x64-gnu": "4.21.0", + "@rollup/rollup-linux-x64-musl": "4.21.0", + "@rollup/rollup-win32-arm64-msvc": "4.21.0", + "@rollup/rollup-win32-ia32-msvc": "4.21.0", + "@rollup/rollup-win32-x64-msvc": "4.21.0", "fsevents": "~2.3.2" } }, @@ -13804,15 +14005,22 @@ } }, "node_modules/shiki": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.7.tgz", - "integrity": "sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.14.1.tgz", + "integrity": "sha512-FujAN40NEejeXdzPt+3sZ3F2dx1U24BY2XTY01+MG8mbxCiA2XukXdcbyMyLAHJ/1AUUnQd1tZlvIjefWWEJeA==", "dev": true, "dependencies": { - "ansi-sequence-parser": "^1.1.0", - "jsonc-parser": "^3.2.0", - "vscode-oniguruma": "^1.7.0", - "vscode-textmate": "^8.0.0" + "@shikijs/core": "1.14.1", + "@types/hast": "^3.0.4" + } + }, + "node_modules/shiki/node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "dependencies": { + "@types/unist": "*" } }, "node_modules/shx": { @@ -14272,24 +14480,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strip-literal": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.0.tgz", - "integrity": "sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==", - "dev": true, - "dependencies": { - "js-tokens": "^9.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/strip-literal/node_modules/js-tokens": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz", - "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==", - "dev": true - }, "node_modules/strong-log-transformer": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", @@ -14492,24 +14682,33 @@ } }, "node_modules/tinybench": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.1.tgz", - "integrity": "sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", "dev": true }, "node_modules/tinypool": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", - "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.1.tgz", + "integrity": "sha512-URZYihUbRPcGv95En+sz6MfghfIc2OJ1sv/RmhWZLouPY0/8Vo80viwPvg3dlaS9fuq7fQMEfgRRK7BBZThBEA==", + "dev": true, + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", "dev": true, "engines": { "node": ">=14.0.0" } }, "node_modules/tinyspy": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", - "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.0.tgz", + "integrity": "sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA==", "dev": true, "engines": { "node": ">=14.0.0" @@ -14524,6 +14723,15 @@ "node": ">=14.14" } }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -14596,12 +14804,12 @@ } }, "node_modules/ts-morph": { - "version": "22.0.0", - "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-22.0.0.tgz", - "integrity": "sha512-M9MqFGZREyeb5fTl6gNHKZLqBQA0TjA1lea+CR48R8EBTDuWrNqW6ccC5QvjNR4s6wDumD3LTCjOFSp9iwlzaw==", + "version": "23.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-23.0.0.tgz", + "integrity": "sha512-FcvFx7a9E8TUe6T3ShihXJLiJOiqyafzFKUO4aqIHDUCIvADdGNShcbc2W5PMr3LerXRv7mafvFZ9lRENxJmug==", "dev": true, "dependencies": { - "@ts-morph/common": "~0.23.0", + "@ts-morph/common": "~0.24.0", "code-block-writer": "^13.0.1" } }, @@ -14648,15 +14856,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/type-fest": { "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", @@ -14739,24 +14938,25 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, "node_modules/typedoc": { - "version": "0.25.13", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.13.tgz", - "integrity": "sha512-pQqiwiJ+Z4pigfOnnysObszLiU3mVLWAExSPf+Mu06G/qsc3wzbuM56SZQvONhHLncLUhYzOVkjFFpFfL5AzhQ==", + "version": "0.26.6", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.26.6.tgz", + "integrity": "sha512-SfEU3SH3wHNaxhFPjaZE2kNl/NFtLNW5c1oHsg7mti7GjmUj1Roq6osBQeMd+F4kL0BoRBBr8gQAuqBlfFu8LA==", "dev": true, "dependencies": { "lunr": "^2.3.9", - "marked": "^4.3.0", - "minimatch": "^9.0.3", - "shiki": "^0.14.7" + "markdown-it": "^14.1.0", + "minimatch": "^9.0.5", + "shiki": "^1.9.1", + "yaml": "^2.4.5" }, "bin": { "typedoc": "bin/typedoc" }, "engines": { - "node": ">= 16" + "node": ">= 18" }, "peerDependencies": { - "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x" + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x" } }, "node_modules/typedoc/node_modules/brace-expansion": { @@ -14769,9 +14969,9 @@ } }, "node_modules/typedoc/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -14784,9 +14984,9 @@ } }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -14796,6 +14996,12 @@ "node": ">=14.17" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true + }, "node_modules/ufo": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz", @@ -14831,9 +15037,9 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" }, "node_modules/unified": { "version": "10.1.2", @@ -15203,15 +15409,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/validator": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", - "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/vfile": { "version": "5.3.7", "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", @@ -15487,14 +15684,14 @@ } }, "node_modules/vite": { - "version": "5.2.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz", - "integrity": "sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.2.tgz", + "integrity": "sha512-dDrQTRHp5C1fTFzcSaMxjk6vdpKvT+2/mIdE07Gw2ykehT49O0z/VHS3zZ8iV/Gh8BJJKHWOe5RjaNrW5xf/GA==", "dev": true, "dependencies": { - "esbuild": "^0.20.1", - "postcss": "^8.4.38", - "rollup": "^4.13.0" + "esbuild": "^0.21.3", + "postcss": "^8.4.41", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" @@ -15513,6 +15710,7 @@ "less": "*", "lightningcss": "^1.21.0", "sass": "*", + "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" @@ -15530,6 +15728,9 @@ "sass": { "optional": true }, + "sass-embedded": { + "optional": true + }, "stylus": { "optional": true }, @@ -15542,15 +15743,15 @@ } }, "node_modules/vite-node": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", - "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.0.5.tgz", + "integrity": "sha512-LdsW4pxj0Ot69FAoXZ1yTnA9bjGohr2yNBU7QKRxpz8ITSkhuDl6h3zS/tvgz4qrNjeRnvrWeXQ8ZF7Um4W00Q==", "dev": true, "dependencies": { "cac": "^6.7.14", - "debug": "^4.3.4", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", + "debug": "^4.3.5", + "pathe": "^1.1.2", + "tinyrainbow": "^1.2.0", "vite": "^5.0.0" }, "bin": { @@ -15564,18 +15765,21 @@ } }, "node_modules/vite-plugin-dts": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-3.9.1.tgz", - "integrity": "sha512-rVp2KM9Ue22NGWB8dNtWEr+KekN3rIgz1tWD050QnRGlriUCmaDwa7qA5zDEjbXg5lAXhYMSBJtx3q3hQIJZSg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-4.0.3.tgz", + "integrity": "sha512-+xnTsaONwU2kV6zhRjtbRJSGN41uFR/whqmcb4k4fftLFDJElxthp0PP5Fq8gMeM9ytWMt1yk5gGgekLREWYQQ==", "dev": true, "dependencies": { - "@microsoft/api-extractor": "7.43.0", + "@microsoft/api-extractor": "7.47.4", "@rollup/pluginutils": "^5.1.0", - "@vue/language-core": "^1.8.27", - "debug": "^4.3.4", + "@volar/typescript": "^2.3.4", + "@vue/language-core": "2.0.29", + "compare-versions": "^6.1.1", + "debug": "^4.3.6", "kolorist": "^1.8.0", - "magic-string": "^0.30.8", - "vue-tsc": "^1.8.27" + "local-pkg": "^0.5.0", + "magic-string": "^0.30.11", + "vue-tsc": "2.0.29" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -15591,9 +15795,9 @@ } }, "node_modules/vite-plugin-static-copy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-1.0.4.tgz", - "integrity": "sha512-UtyOttgoeotSCwmBugsEZCZJZcIpjE9NGO7jlZ9OeedYpBueBdspD8waRZrjE+yQLH6qGNU2CvYB2FILviCQjg==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-1.0.6.tgz", + "integrity": "sha512-3uSvsMwDVFZRitqoWHj0t4137Kz7UynnJeq1EZlRW7e25h2068fyIZX4ORCCOAkfp1FklGxJNVJBkBOD+PZIew==", "dev": true, "dependencies": { "chokidar": "^3.5.3", @@ -15608,438 +15812,31 @@ "vite": "^5.0.0" } }, - "node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" - } - }, "node_modules/vitest": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", - "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", - "dev": true, - "dependencies": { - "@vitest/expect": "1.6.0", - "@vitest/runner": "1.6.0", - "@vitest/snapshot": "1.6.0", - "@vitest/spy": "1.6.0", - "@vitest/utils": "1.6.0", - "acorn-walk": "^8.3.2", - "chai": "^4.3.10", - "debug": "^4.3.4", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.0.5.tgz", + "integrity": "sha512-8GUxONfauuIdeSl5f9GTgVEpg5BTOlplET4WEDaeY2QBiN8wSm68vxN/tb5z405OwppfoCavnwXafiaYBC/xOA==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@vitest/expect": "2.0.5", + "@vitest/pretty-format": "^2.0.5", + "@vitest/runner": "2.0.5", + "@vitest/snapshot": "2.0.5", + "@vitest/spy": "2.0.5", + "@vitest/utils": "2.0.5", + "chai": "^5.1.1", + "debug": "^4.3.5", "execa": "^8.0.1", - "local-pkg": "^0.5.0", - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "std-env": "^3.5.0", - "strip-literal": "^2.0.0", - "tinybench": "^2.5.1", - "tinypool": "^0.8.3", + "magic-string": "^0.30.10", + "pathe": "^1.1.2", + "std-env": "^3.7.0", + "tinybench": "^2.8.0", + "tinypool": "^1.0.0", + "tinyrainbow": "^1.2.0", "vite": "^5.0.0", - "vite-node": "1.6.0", - "why-is-node-running": "^2.2.2" + "vite-node": "2.0.5", + "why-is-node-running": "^2.3.0" }, "bin": { "vitest": "vitest.mjs" @@ -16053,8 +15850,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.6.0", - "@vitest/ui": "1.6.0", + "@vitest/browser": "2.0.5", + "@vitest/ui": "2.0.5", "happy-dom": "*", "jsdom": "*" }, @@ -16213,43 +16010,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/vscode-oniguruma": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", - "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", - "dev": true - }, - "node_modules/vscode-textmate": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", - "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", "dev": true }, - "node_modules/vue-template-compiler": { - "version": "2.7.16", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", - "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==", - "dev": true, - "dependencies": { - "de-indent": "^1.0.2", - "he": "^1.2.0" - } - }, "node_modules/vue-tsc": { - "version": "1.8.27", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.27.tgz", - "integrity": "sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==", + "version": "2.0.29", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.0.29.tgz", + "integrity": "sha512-MHhsfyxO3mYShZCGYNziSbc63x7cQ5g9kvijV7dRe1TTXBRLxXyL0FnXWpUF1xII2mJ86mwYpYsUmMwkmerq7Q==", "dev": true, "dependencies": { - "@volar/typescript": "~1.11.1", - "@vue/language-core": "1.8.27", + "@volar/typescript": "~2.4.0-alpha.18", + "@vue/language-core": "2.0.29", "semver": "^7.5.4" }, "bin": { "vue-tsc": "bin/vue-tsc.js" }, "peerDependencies": { - "typescript": "*" + "typescript": ">=5.0.0" } }, "node_modules/walk-up-path": { @@ -16351,9 +16132,9 @@ } }, "node_modules/why-is-node-running": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", - "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, "dependencies": { "siginfo": "^2.0.0", @@ -16376,12 +16157,12 @@ } }, "node_modules/wireit": { - "version": "0.14.4", - "resolved": "https://registry.npmjs.org/wireit/-/wireit-0.14.4.tgz", - "integrity": "sha512-WNAXEw2cJs1nSRNJNRcPypARZNumgtsRTJFTNpd6turCA6JZ6cEwl4ZU3C1IHc/3IaXoPu9LdxcI5TBTdD6/pg==", + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/wireit/-/wireit-0.14.7.tgz", + "integrity": "sha512-bMyyaKtH8fTYD3cmI8ZULIwifDcgNRHyHfYF54QFISvKiDtDJ4yHJZRlW/q2j0DaRjuFbMkIhpE++/GtI5iipQ==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "brace-expansion": "^4.0.0", "chokidar": "^3.5.3", "fast-glob": "^3.2.11", "jsonc-parser": "^3.0.0", @@ -16391,7 +16172,28 @@ "wireit": "bin/wireit.js" }, "engines": { - "node": ">=14.14.0" + "node": ">=18.0.0" + } + }, + "node_modules/wireit/node_modules/balanced-match": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-3.0.1.tgz", + "integrity": "sha512-vjtV3hiLqYDNRoiAv0zC4QaGAMPomEoq83PRmYIofPswwZurCeWR5LByXm7SyoL0Zh5+2z0+HC7jG8gSZJUh0w==", + "dev": true, + "engines": { + "node": ">= 16" + } + }, + "node_modules/wireit/node_modules/brace-expansion": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-4.0.0.tgz", + "integrity": "sha512-l/mOwLWs7BQIgOKrL46dIAbyCKvPV7YJPDspkuc88rHsZRlg3hptUGdU7Trv0VFP4d3xnSGBQrKu5ZvGB7UeIw==", + "dev": true, + "dependencies": { + "balanced-match": "^3.0.0" + }, + "engines": { + "node": ">= 18" } }, "node_modules/wordwrap": { @@ -16604,7 +16406,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/xastscript/-/xastscript-4.0.0.tgz", "integrity": "sha512-r7a0kObEyivkML0dLrp/nOH5l51y9v5DL1MT/Xc6qUgGGNP1mZZUmT6NXtWAmx2FLfjonop++PtpVMwp1Hw/Gw==", - "dev": true, "dependencies": { "@types/xast": "^2.0.0" }, @@ -16637,9 +16438,12 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.2.tgz", - "integrity": "sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", + "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", + "bin": { + "yaml": "bin.mjs" + }, "engines": { "node": ">= 14" } @@ -16680,48 +16484,6 @@ "node": ">=12" } }, - "node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", - "dev": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/z-schema": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz", - "integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==", - "dev": true, - "dependencies": { - "lodash.get": "^4.4.2", - "lodash.isequal": "^4.5.0", - "validator": "^13.7.0" - }, - "bin": { - "z-schema": "bin/z-schema" - }, - "engines": { - "node": ">=8.0.0" - }, - "optionalDependencies": { - "commander": "^9.4.1" - } - }, - "node_modules/z-schema/node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", - "dev": true, - "optional": true, - "engines": { - "node": "^12.20.0 || >=14" - } - }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", @@ -16957,11 +16719,8 @@ "@unified-latex/unified-latex-util-trim": "^1.7.1", "@unified-latex/unified-latex-util-visit": "^1.7.1", "cssesc": "^3.0.0", - "hast": "^1.0.0", - "hastscript": "^7.2.0", - "rehype-raw": "^6.1.1", - "rehype-stringify": "^9.0.4", - "unified": "^10.1.2" + "unified": "^10.1.2", + "xastscript": "^4.0.0" }, "devDependencies": { "@types/xast": "^2.0.4", @@ -16969,8 +16728,7 @@ "hast-util-to-string": "^3.0.0", "prettier": "^2.8.8", "xast-util-to-string": "^3.0.0", - "xast-util-to-xml": "^4.0.0", - "xastscript": "^4.0.0" + "xast-util-to-xml": "^4.0.0" } }, "packages/unified-latex-types": { diff --git a/package.json b/package.json index 16fcad37..06ec86ee 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "trailingComma": "es5" }, "devDependencies": { - "@types/node": "^20.12.12", + "@types/node": "^20.16.1", "@types/prettier": "^2.7.3", "@types/shelljs": "^0.8.15", "esbuild": "^0.21.2", @@ -44,16 +44,16 @@ "remark-gfm": "^3.0.1", "remark-parse": "^10.0.2", "remark-stringify": "^10.0.3", - "rimraf": "^5.0.7", + "rimraf": "^6.0.1", "shx": "^0.3.4", - "ts-morph": "^22.0.0", - "typedoc": "^0.25.13", - "typescript": "^5.4.5", - "vite": "^5.2.11", - "vite-plugin-dts": "^3.9.1", - "vite-plugin-static-copy": "^1.0.4", - "vitest": "^1.6.0", - "wireit": "^0.14.4" + "ts-morph": "^23.0.0", + "typedoc": "^0.26.6", + "typescript": "^5.5.4", + "vite": "^5.4.2", + "vite-plugin-dts": "^4.0.3", + "vite-plugin-static-copy": "^1.0.6", + "vitest": "^2.0.5", + "wireit": "^0.14.7" }, "dependencies": { "@types/color": "^3.0.6", @@ -75,7 +75,7 @@ "unified-engine": "^10.1.0", "unified-lint-rule": "^2.1.1", "unist-util-position": "^4.0.4", - "vfile-reporter-json": "^3.2.0", + "vfile-reporter-json": "^3.3.0", "vfile-reporter-position": "^0.1.7", "vfile-reporter-pretty": "^6.1.1" }, From 0aabe43eb776974cd9368ce2c5f432983c7cd092 Mon Sep 17 00:00:00 2001 From: Jason Siefken Date: Tue, 20 Aug 2024 11:51:43 -0400 Subject: [PATCH 8/8] Rebuild documentation --- packages/unified-latex-ctan/README.md | 8 ++-- packages/unified-latex-lint/README.md | 2 +- packages/unified-latex-to-pretext/README.md | 48 ++++--------------- packages/unified-latex-util-align/README.md | 2 +- .../unified-latex-util-arguments/README.md | 6 +-- .../unified-latex-util-environments/README.md | 6 +-- packages/unified-latex-util-macros/README.md | 2 +- packages/unified-latex-util-match/README.md | 6 +-- packages/unified-latex-util-parse/README.md | 16 +++---- packages/unified-latex-util-pgfkeys/README.md | 10 +--- packages/unified-latex-util-scan/README.md | 2 +- 11 files changed, 36 insertions(+), 72 deletions(-) diff --git a/packages/unified-latex-ctan/README.md b/packages/unified-latex-ctan/README.md index fe317bc2..52734d5c 100644 --- a/packages/unified-latex-ctan/README.md +++ b/packages/unified-latex-ctan/README.md @@ -40,7 +40,7 @@ import the `.js` file. To explicitly access the commonjs export, import the `.cj # Constants -| Name | Type | Description | -| :---------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------- | -| `environmentInfo` | `{ cleveref: EnvInfoRecord; exam: EnvInfoRecord; geometry: EnvInfoRecord; hyperref: EnvInfoRecord; latex2e: EnvInfoRecord; ... 10 more ...; multicol: EnvInfoRecord; }` | Info about the environments for available ctan packages. `latex2e` contains the standard environments for LaTeX. | -| `macroInfo` | `{ cleveref: MacroInfoRecord; exam: MacroInfoRecord; geometry: MacroInfoRecord; hyperref: MacroInfoRecord; latex2e: MacroInfoRecord; ... 10 more ...; multicol: MacroInfoRecord; }` | Info about the macros for available ctan packages. `latex2e` contains the standard macros for LaTeX. | +| Name | Type | Description | +| :---------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------- | +| `environmentInfo` | `{ amsart: EnvInfoRecord; cleveref: EnvInfoRecord; exam: EnvInfoRecord; geometry: EnvInfoRecord; hyperref: EnvInfoRecord; ... 11 more ...; multicol: EnvInfoRecord; }` | Info about the environments for available ctan packages. `latex2e` contains the standard environments for LaTeX. | +| `macroInfo` | `{ amsart: MacroInfoRecord; cleveref: MacroInfoRecord; exam: MacroInfoRecord; geometry: MacroInfoRecord; hyperref: MacroInfoRecord; ... 11 more ...; multicol: MacroInfoRecord; }` | Info about the macros for available ctan packages. `latex2e` contains the standard macros for LaTeX. | diff --git a/packages/unified-latex-lint/README.md b/packages/unified-latex-lint/README.md index 8020bc74..68cec17a 100644 --- a/packages/unified-latex-lint/README.md +++ b/packages/unified-latex-lint/README.md @@ -26,4 +26,4 @@ import the `.js` file. To explicitly access the commonjs export, import the `.cj | Name | Type | Description | | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------ | -| `lints` | `{ unifiedLatexLintArgumentColorCommands: Plugin; ... 7 more ...; unifiedLatexLintPreferSetlength: Plugin<...>; }` | Object exporting all available lints. | +| `lints` | `{ unifiedLatexLintArgumentColorCommands: Plugin; ... 7 more ...; unifiedLatexLintPreferSetlength: Plugin<...>; }` | Object exporting all available lints. | diff --git a/packages/unified-latex-to-pretext/README.md b/packages/unified-latex-to-pretext/README.md index 9df0ef19..387e91e0 100644 --- a/packages/unified-latex-to-pretext/README.md +++ b/packages/unified-latex-to-pretext/README.md @@ -81,36 +81,19 @@ Unified plugin to convert a `unified-latex` AST into a `xast` AST representation #### options ```typescript -HtmlLikePluginOptions +PluginOptions ``` ### Type -`Plugin` +`Plugin` ```typescript function unifiedLatexToPretext( - options: HtmlLikePluginOptions + options: PluginOptions ): (tree: Ast.Root, file: VFile) => Xast.Root; ``` -where - -```typescript -type HtmlLikePluginOptions = { - /** - * Functions called to replace environments during processing. Key values should match environment names. - * You probably want to use the function `htmlLike(...)` to return a node that gets converted to specific HTML. - */ - environmentReplacements?: EnvironmentReplacements; - /** - * Functions called to replace macros during processing. Key values should match macro names. - * You probably want to use the function `htmlLike(...)` to return a node that gets converted to specific HTML. - */ - macroReplacements?: MacroReplacements; -}; -``` - ## `unifiedLatexWrapPars` Unified plugin to wrap paragraphs in `\html-tag:p{...}` macros. @@ -196,23 +179,6 @@ function convertToPretext( | tree | `Ast.Node \| Ast.Node[]` | | options | `PluginOptions` | -where - -```typescript -type PluginOptions = { - /** - * Functions called to replace environments during processing. Key values should match environment names. - * You probably want to use the function `htmlLike(...)` to return a node that gets converted to specific HTML. - */ - environmentReplacements?: EnvironmentReplacements; - /** - * Functions called to replace macros during processing. Key values should match macro names. - * You probably want to use the function `htmlLike(...)` to return a node that gets converted to specific HTML. - */ - macroReplacements?: MacroReplacements; -}; -``` - ## `wrapPars(nodes, options)` Wrap paragraphs in `

    ...

    ` tags. @@ -253,5 +219,11 @@ function wrapPars( ## `PluginOptions` ```typescript -export type PluginOptions = HtmlLikePluginOptions & {}; +export type PluginOptions = HtmlLikePluginOptions & { + /** + * A boolean where if it's true then the output won't be wrapped in the
    ... etc. tags. + * If it's false (default), a valid and complete PreTeXt document is returned. + */ + producePretextFragment?: boolean; +}; ``` diff --git a/packages/unified-latex-util-align/README.md b/packages/unified-latex-util-align/README.md index 9c737893..989844ba 100644 --- a/packages/unified-latex-util-align/README.md +++ b/packages/unified-latex-util-align/README.md @@ -35,7 +35,7 @@ function createMatchers( ): { isRowSep: Ast.TypeGuard; isColSep: (node: Ast.Node) => boolean; - isWhitespace: (node: Ast.Node) => boolean; + isWhitespace: (node: Ast.Node) => node is Ast.Whitespace; isSameLineComment: (node: Ast.Node) => boolean; isOwnLineComment: (node: Ast.Node) => boolean; }; diff --git a/packages/unified-latex-util-arguments/README.md b/packages/unified-latex-util-arguments/README.md index 11764d9f..30a9757d 100644 --- a/packages/unified-latex-util-arguments/README.md +++ b/packages/unified-latex-util-arguments/README.md @@ -43,16 +43,16 @@ option. #### options ```typescript -{ macros: Ast.MacroInfoRecord; } +{ macros: MacroInfoRecord; } ``` ### Type -`Plugin<{ macros: Ast.MacroInfoRecord; }[], Ast.Root, Ast.Root>` +`Plugin<{ macros: MacroInfoRecord; }[], Ast.Root, Ast.Root>` ```typescript function unifiedLatexAttachMacroArguments(options: { - macros: Ast.MacroInfoRecord; + macros: MacroInfoRecord; }): (tree: Ast.Root) => void; ``` diff --git a/packages/unified-latex-util-environments/README.md b/packages/unified-latex-util-environments/README.md index 1fbbbfcc..1fc6eadc 100644 --- a/packages/unified-latex-util-environments/README.md +++ b/packages/unified-latex-util-environments/README.md @@ -35,16 +35,16 @@ Unified plugin to process environment content and attach arguments. #### options ```typescript -{ environments: Ast.EnvInfoRecord; } +{ environments: EnvInfoRecord; } ``` ### Type -`Plugin<{ environments: Ast.EnvInfoRecord; }[], Ast.Root, Ast.Root>` +`Plugin<{ environments: EnvInfoRecord; }[], Ast.Root, Ast.Root>` ```typescript function unifiedLatexProcessEnvironments(options: { - environments: Ast.EnvInfoRecord; + environments: EnvInfoRecord; }): (tree: Ast.Root) => void; ``` diff --git a/packages/unified-latex-util-macros/README.md b/packages/unified-latex-util-macros/README.md index b397bf78..e95df135 100644 --- a/packages/unified-latex-util-macros/README.md +++ b/packages/unified-latex-util-macros/README.md @@ -47,7 +47,7 @@ function createMacroExpander( ```typescript function createMatchers(): { - isHash: (node: Ast.Node) => boolean; + isHash: (node: Ast.Node) => node is Ast.String; isNumber: (node: Ast.Node) => boolean; splitNumber: ( node: Ast.String diff --git a/packages/unified-latex-util-match/README.md b/packages/unified-latex-util-match/README.md index 4e88f214..df4a4260 100644 --- a/packages/unified-latex-util-match/README.md +++ b/packages/unified-latex-util-match/README.md @@ -23,6 +23,6 @@ import the `.js` file. To explicitly access the commonjs export, import the `.cj # Constants -| Name | Type | Description | -| :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------- | -| `match` | `{ macro(node: any, macroName?: string): node is Ast.Macro; anyMacro(node: any): node is Ast.Macro; environment(node: any, envName?: string): node is Ast.Environment; anyEnvironment(node: any): node is Ast.Environment; ... 11 more ...; createEnvironmentMatcher: (macros: string[] \| Record<...>) => Ast.TypeGuard<...>; }` | Functions to match different types of nodes. | +| Name | Type | Description | +| :------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------- | +| `match` | `{ macro(node: any, macroName?: string): node is Ast.Macro; anyMacro(node: any): node is Ast.Macro; environment(node: any, envName?: string): node is Ast.Environment; ... 12 more ...; createEnvironmentMatcher: (macros: string[] \| Record) => Ast.TypeGuard; }` | Functions to match different types of nodes. | diff --git a/packages/unified-latex-util-parse/README.md b/packages/unified-latex-util-parse/README.md index 73d5c03f..5fadbb8c 100644 --- a/packages/unified-latex-util-parse/README.md +++ b/packages/unified-latex-util-parse/README.md @@ -51,18 +51,18 @@ Parse a string to a LaTeX AST. #### options ```typescript -{ mode?: "math" | "regular"; macros?: Ast.MacroInfoRecord; environments?: Ast.EnvInfoRecord; flags?: { atLetter?: boolean; expl3?: boolean; autodetectExpl3AndAtLetter?: boolean; }; } +{ mode?: "math" | "regular"; macros?: MacroInfoRecord; environments?: EnvInfoRecord; flags?: { atLetter?: boolean; expl3?: boolean; autodetectExpl3AndAtLetter?: boolean; }; } ``` ### Type -`Plugin<{ mode?: "math" | "regular"; macros?: Ast.MacroInfoRecord; environments?: Ast.EnvInfoRecord; flags?: { atLetter?: boolean; expl3?: boolean; autodetectExpl3AndAtLetter?: boolean; }; }[], string, Ast.Root>` +`Plugin<{ mode?: "math" | "regular"; macros?: MacroInfoRecord; environments?: EnvInfoRecord; flags?: { atLetter?: boolean; expl3?: boolean; autodetectExpl3AndAtLetter?: boolean; }; }[], string, Ast.Root>` ```typescript function unifiedLatexFromString(options: { mode?: "math" | "regular"; - macros?: Ast.MacroInfoRecord; - environments?: Ast.EnvInfoRecord; + macros?: MacroInfoRecord; + environments?: EnvInfoRecord; flags?: { atLetter?: boolean; expl3?: boolean; @@ -134,17 +134,17 @@ are reparsed (if needed) in math mode. #### options ```typescript -{ environments: Ast.EnvInfoRecord; macros: Ast.MacroInfoRecord; } +{ environments: EnvInfoRecord; macros: MacroInfoRecord; } ``` ### Type -`Plugin<{ environments: Ast.EnvInfoRecord; macros: Ast.MacroInfoRecord; }[], Ast.Root, Ast.Root>` +`Plugin<{ environments: EnvInfoRecord; macros: MacroInfoRecord; }[], Ast.Root, Ast.Root>` ```typescript function unifiedLatexProcessMacrosAndEnvironmentsWithMathReparse(options: { - environments: Ast.EnvInfoRecord; - macros: Ast.MacroInfoRecord; + environments: EnvInfoRecord; + macros: MacroInfoRecord; }): (tree: Ast.Root) => void; ``` diff --git a/packages/unified-latex-util-pgfkeys/README.md b/packages/unified-latex-util-pgfkeys/README.md index 9db9ca45..6b90de27 100644 --- a/packages/unified-latex-util-pgfkeys/README.md +++ b/packages/unified-latex-util-pgfkeys/README.md @@ -30,15 +30,7 @@ import the `.js` file. To explicitly access the commonjs export, import the `.cj ```typescript -function createMatchers(): { - isChar: (node: Ast.Node, char: string) => boolean; - isComma: (node: Ast.Node) => boolean; - isEquals: (node: Ast.Node) => boolean; - isWhitespace: (node: Ast.Node) => boolean; - isParbreak: (node: Ast.Node) => boolean; - isSameLineComment: (node: Ast.Node) => boolean; - isOwnLineComment: (node: Ast.Node) => boolean; -}; +function createMatchers(): { isChar: (node: Ast.Node, char: string) => node is Ast.String; isComma: (node: Ast.Node) => node is Ast.String; isEquals: (node: Ast.Node) => node is Ast.String; isWhitespace: (node: Ast.Node) => node is Ast.Whitespace; isParbreak: (node: Ast.Node) => node is Ast.Parbreak; isSameLineComment: (node: Ast.Node) => boo... ``` ## `parsePgfkeys(ast, options)` diff --git a/packages/unified-latex-util-scan/README.md b/packages/unified-latex-util-scan/README.md index 8e0000bb..6d5f18e8 100644 --- a/packages/unified-latex-util-scan/README.md +++ b/packages/unified-latex-util-scan/README.md @@ -29,7 +29,7 @@ Efficiently search for a large number of strings using a prefix-tree. The longest match is returned. ```typescript -function prefixMatch(nodes: Ast.Node[], prefixes: string | string[] | { dump(spacer?: number): string; tree(): any; addWord(word: string): ...; removeWord(word: string): ...; isPrefix(word: string): boolean; countPrefix(word: string): number; ... 5 more ...; getSubAnagrams(word: string): string[]; }, options: { startIndex?: number; matchSubstrings?: boolean; assumeOneCharStrings?: boolean; }): { match: string; endNodeIndex: number; endNodePartialMatch: string | null; } +function prefixMatch(nodes: Ast.Node[], prefixes: string | string[] | { dump(spacer?: number): string; tree(): any; addWord(word: string): ReturnType; removeWord(word: string): ReturnType; ... 7 more ...; getSubAnagrams(word: string): string[]; }, options: { startIndex?: number; matchSubstrings?: boolean; assumeOneCharStrings?: boolean; }): { match: string; endNodeIndex: number; endNodePartialMatch: string | null; } ``` **Parameters**