diff --git a/src/command/render/defaults.ts b/src/command/render/defaults.ts index e6ef78d8d16..2cd97b7fcf5 100644 --- a/src/command/render/defaults.ts +++ b/src/command/render/defaults.ts @@ -39,9 +39,12 @@ export async function generateDefaults( let allDefaults: FormatPandoc | undefined; if (options.format.pandoc) { - allDefaults = (options.format.pandoc - ? ld.cloneDeep(options.format.pandoc) - : {}) as FormatPandoc; + allDefaults = { + ...(options.format.pandoc || {}), + variables: { + ...(options.format.pandoc?.variables || {}), + }, + } as FormatPandoc; // resolve filters const resolvedFilters = await resolveFilters( diff --git a/src/command/render/filters.ts b/src/command/render/filters.ts index 5e5eec61c9e..20fd5e97649 100644 --- a/src/command/render/filters.ts +++ b/src/command/render/filters.ts @@ -713,6 +713,7 @@ function initFilterParams(dependenciesFile: string) { const kQuartoFilterMarker = "quarto"; const kQuartoCiteProcMarker = "citeproc"; +// NB: this mutates `pandoc.citeproc` export async function resolveFilters( filters: QuartoFilter[], options: PandocOptions, diff --git a/src/command/render/flags.ts b/src/command/render/flags.ts index a2fa17bfcc7..10be31e5b33 100644 --- a/src/command/render/flags.ts +++ b/src/command/render/flags.ts @@ -27,8 +27,6 @@ import { import { isQuartoMetadata } from "../../config/metadata.ts"; import { RenderFlags, RenderOptions } from "./types.ts"; -import * as ld from "../../core/lodash.ts"; - import { isAbsolute, SEP_PATTERN } from "../../deno_ral/path.ts"; import { normalizePath } from "../../core/path.ts"; import { removeFlags } from "../../core/flags.ts"; @@ -471,7 +469,12 @@ export function removePandocToArg(args: string[]) { } export function removePandocTo(renderOptions: RenderOptions) { - renderOptions = ld.cloneDeep(renderOptions); + renderOptions = { + ...renderOptions, + flags: { + ...(renderOptions.flags || {}), + }, + } as RenderOptions; delete renderOptions.flags?.to; if (renderOptions.pandocArgs) { renderOptions.pandocArgs = removePandocToArg(renderOptions.pandocArgs); diff --git a/src/command/render/freeze.ts b/src/command/render/freeze.ts index 240de38cd30..2db57afedda 100644 --- a/src/command/render/freeze.ts +++ b/src/command/render/freeze.ts @@ -20,8 +20,6 @@ import { LF, } from "../../deno_ral/fs.ts"; -import { cloneDeep } from "../../core/lodash.ts"; - import { inputFilesDir } from "../../core/render.ts"; import { TempContext } from "../../core/temp.ts"; import { md5HashSync } from "../../core/hash.ts"; @@ -55,13 +53,15 @@ export function freezeExecuteResult( result: ExecuteResult, ) { // resolve includes within executeResult - result = cloneDeep(result) as ExecuteResult; + const innerResult = { + ...result, + } as ExecuteResult; const resolveIncludes = ( name: "include-in-header" | "include-before-body" | "include-after-body", ) => { - if (result.includes) { - if (result.includes[name]) { - result.includes[name] = result.includes[name]!.map((file) => + if (innerResult.includes) { + if (innerResult.includes[name]) { + innerResult.includes[name] = innerResult.includes[name]!.map((file) => // Storing file content using LF line ending format(Deno.readTextFileSync(file), LF) ); @@ -73,7 +73,7 @@ export function freezeExecuteResult( resolveIncludes(kIncludeAfterBody); // make the supporting dirs relative to the input file dir - result.supporting = result.supporting.map((file) => { + innerResult.supporting = innerResult.supporting.map((file) => { if (isAbsolute(file)) { return relative(normalizePath(dirname(input)), file); } else { @@ -88,7 +88,7 @@ export function freezeExecuteResult( const freezeJsonFile = freezeResultFile(input, output, true); Deno.writeTextFileSync( freezeJsonFile, - JSON.stringify({ hash, result }, undefined, 2), + JSON.stringify({ hash, result: innerResult }, undefined, 2), ); // return the file diff --git a/src/command/render/pandoc.ts b/src/command/render/pandoc.ts index 0a8973c0068..a6b6abd3e2a 100644 --- a/src/command/render/pandoc.ts +++ b/src/command/render/pandoc.ts @@ -391,9 +391,12 @@ export async function runPandoc( // save args and metadata so we can print them (we may subsequently edit them) const printArgs = [...args]; let printMetadata = { - ...ld.cloneDeep(options.format.metadata), + ...options.format.metadata, + crossref: { + ...(options.format.metadata.crossref || {}), + }, ...options.flags?.metadata, - }; + } as Metadata; // remove some metadata that are used as parameters to our lua filters const cleanMetadataForPrinting = (metadata: Metadata) => { @@ -691,7 +694,7 @@ export async function runPandoc( ), ...extras.metadataOverride || {}, }; - printMetadata = mergeConfigs(extras.metadata, printMetadata); + printMetadata = mergeConfigs(extras.metadata || {}, printMetadata); cleanMetadataForPrinting(printMetadata); } @@ -820,7 +823,9 @@ export async function runPandoc( } // more cleanup - options.format.metadata = cleanupPandocMetadata(options.format.metadata); + options.format.metadata = cleanupPandocMetadata({ + ...options.format.metadata, + }); printMetadata = cleanupPandocMetadata(printMetadata); if (extras[kIncludeInHeader]) { @@ -1370,13 +1375,12 @@ export async function runPandoc( } } +// this mutates metadata[kClassOption] function cleanupPandocMetadata(metadata: Metadata) { - const cleaned = ld.cloneDeep(metadata); - // pdf classoption can end up with duplicaed options - const classoption = cleaned[kClassOption]; + const classoption = metadata[kClassOption]; if (Array.isArray(classoption)) { - cleaned[kClassOption] = ld.uniqBy( + metadata[kClassOption] = ld.uniqBy( classoption.reverse(), (option: string) => { return option.replace(/=.+$/, ""); @@ -1384,7 +1388,7 @@ function cleanupPandocMetadata(metadata: Metadata) { ).reverse(); } - return cleaned; + return metadata; } async function resolveExtras( @@ -1687,7 +1691,10 @@ function resolveTextHighlightStyle( extras: FormatExtras, pandoc: FormatPandoc, ): FormatExtras { - extras = ld.cloneDeep(extras); + extras = { + ...extras, + pandoc: extras.pandoc ? { ...extras.pandoc } : {}, + } as FormatExtras; // Get the user selected theme or choose a default const highlightTheme = pandoc[kHighlightStyle] || kDefaultHighlightStyle; diff --git a/src/command/render/project.ts b/src/command/render/project.ts index 77050f6e2ea..5ce9f59b96e 100644 --- a/src/command/render/project.ts +++ b/src/command/render/project.ts @@ -144,7 +144,7 @@ const computeProjectRenderConfig = async ( // force execution for any incremental files (unless options.useFreezer is set) let alwaysExecuteFiles = incremental && !inputs.options.useFreezer - ? ld.cloneDeep(inputs.files) as string[] + ? [...(inputs.files!)] : undefined; // file normaliation diff --git a/src/core/jupyter/display-data.ts b/src/core/jupyter/display-data.ts index 97210e71eb3..53296ca3d19 100644 --- a/src/core/jupyter/display-data.ts +++ b/src/core/jupyter/display-data.ts @@ -123,8 +123,13 @@ export function displayDataWithMarkdownMath(output: JupyterOutputDisplayData) { if (Array.isArray(output.data[kTextLatex]) && !output.data[kTextMarkdown]) { const latex = output.data[kTextLatex] as string[]; if (displayDataLatexIsMath(latex)) { - output = ld.cloneDeep(output); - output.data[kTextMarkdown] = output.data[kTextLatex]; + output = { + ...output, + data: { + ...output.data, + [kTextMarkdown]: latex, + }, + }; return output; } } diff --git a/src/core/jupyter/jupyter.ts b/src/core/jupyter/jupyter.ts index 30b4316d014..eb34f0a6f39 100644 --- a/src/core/jupyter/jupyter.ts +++ b/src/core/jupyter/jupyter.ts @@ -963,7 +963,9 @@ export function mdFromContentCell( const contentCellEnvelope = createCellEnvelope(["cell", "markdown"], options); // clone source for manipulation - const source = ld.cloneDeep(cell.source) as string[]; + const source = typeof cell.source === "string" + ? [cell.source] + : [...cell.source]; // handle user expressions (if any) if (options && source) { @@ -1461,7 +1463,9 @@ async function mdFromCodeCell( } } md.push("}\n"); - let source = ld.cloneDeep(cell.source); + let source = typeof cell.source === "string" + ? [cell.source] + : [...cell.source]; if (fenced) { const optionsSource = cell.optionsSource.filter((line) => line.search(/\|\s+echo:\s+fenced\s*$/) === -1 diff --git a/src/execute/jupyter/jupyter.ts b/src/execute/jupyter/jupyter.ts index 5bc03c342e1..5bf2e81d15b 100644 --- a/src/execute/jupyter/jupyter.ts +++ b/src/execute/jupyter/jupyter.ts @@ -243,7 +243,15 @@ export const jupyterEngine: ExecutionEngine = { isServerShinyPython(format, kJupyterEngine) && format.render[kKeepHidden] !== true ) { - format = ld.cloneDeep(format); + format = { + ...format, + render: { + ...format.render, + }, + metadata: { + ...format.metadata, + }, + }; format.render[kKeepHidden] = true; format.metadata[kRemoveHidden] = "all"; } diff --git a/src/execute/ojs/compile.ts b/src/execute/ojs/compile.ts index 17303e7d9c3..cc33bc02b39 100644 --- a/src/execute/ojs/compile.ts +++ b/src/execute/ojs/compile.ts @@ -892,7 +892,9 @@ export async function ojsExecuteResult( executeResult: MappedExecuteResult, ojsBlockLineNumbers: number[], ) { - executeResult = ld.cloneDeep(executeResult); + executeResult = { + ...executeResult, + }; // evaluate ojs chunks const { markdown, includes, filters, resourceFiles } = await ojsCompile({ diff --git a/src/project/types/website/listing/website-listing-template.ts b/src/project/types/website/listing/website-listing-template.ts index 335deeaaa06..4d4136a618a 100644 --- a/src/project/types/website/listing/website-listing-template.ts +++ b/src/project/types/website/listing/website-listing-template.ts @@ -318,7 +318,9 @@ export function reshapeListing( listing: Listing, format: Format, ): ReshapedListing { - const reshaped = cloneDeep(listing) as Listing; + const reshaped = { + ...listing, + } as Listing; // Add template utilities const utilities = {} as Record; diff --git a/src/publish/config.ts b/src/publish/config.ts index 4033ae111a0..be1a3489052 100644 --- a/src/publish/config.ts +++ b/src/publish/config.ts @@ -8,8 +8,6 @@ import { warning } from "../deno_ral/log.ts"; import { stringify } from "../core/yaml.ts"; import { basename, dirname, join } from "../deno_ral/path.ts"; -import * as ld from "../core/lodash.ts"; - import { Metadata } from "../config/types.ts"; import { readYaml, readYamlFromString } from "../core/yaml.ts"; import { ProjectContext } from "../project/types.ts"; @@ -69,7 +67,9 @@ export function writePublishDeployment( publish: PublishRecord, ) { // don't write 'code' field if false - publish = ld.cloneDeep(publish) as PublishRecord; + publish = { + ...publish, + } as PublishRecord; if (publish.code === false) { delete (publish as Record).code; }