File tree Expand file tree Collapse file tree 9 files changed +74
-7
lines changed Expand file tree Collapse file tree 9 files changed +74
-7
lines changed Original file line number Diff line number Diff line change @@ -19,14 +19,15 @@ import {
1919 type ImmediateBufferCacheEntry ,
2020 type ImmediateStringCacheEntry ,
2121} from "./cache-types.ts" ;
22+ import { Cloneable } from "../safe-clone-deep.ts" ;
2223export { type ProjectCache } from "./cache-types.ts" ;
2324
2425const currentCacheVersion = "1" ;
2526const requiredQuartoVersions : Record < string , string > = {
2627 "1" : ">1.7.0" ,
2728} ;
2829
29- class ProjectCacheImpl {
30+ class ProjectCacheImpl implements Cloneable < ProjectCacheImpl > {
3031 projectScratchDir : string ;
3132 index : Deno . Kv | null ;
3233
@@ -35,6 +36,10 @@ class ProjectCacheImpl {
3536 this . index = null ;
3637 }
3738
39+ clone ( ) {
40+ return this ;
41+ }
42+
3843 close ( ) {
3944 if ( this . index ) {
4045 this . index . close ( ) ;
Original file line number Diff line number Diff line change 1+ /*
2+ * safe-clone-deep.ts
3+ *
4+ * CloneDeep that uses object's own cloning methods when available
5+ *
6+ * Copyright (C) 2025 Posit Software, PBC
7+ */
8+
9+ export interface Cloneable < T > {
10+ clone ( ) : T ;
11+ }
12+
13+ export function safeCloneDeep < T > ( obj : T ) : T {
14+ if ( obj === null || typeof obj !== "object" ) {
15+ return obj ;
16+ }
17+
18+ // Handle arrays
19+ if ( Array . isArray ( obj ) ) {
20+ return obj . map ( ( item ) => safeCloneDeep ( item ) ) as T ;
21+ }
22+
23+ if ( obj && ( "clone" in obj ) && typeof obj . clone === "function" ) {
24+ return obj . clone ( ) ;
25+ }
26+
27+ // Handle regular objects
28+ const result = { } as T ;
29+ for ( const key in obj ) {
30+ if ( Object . prototype . hasOwnProperty . call ( obj , key ) ) {
31+ result [ key ] = safeCloneDeep ( obj [ key ] ) ;
32+ }
33+ }
34+
35+ return result ;
36+ }
Original file line number Diff line number Diff line change @@ -384,6 +384,9 @@ export async function compileWithCache(
384384 const result = await memoizedGetVarsBlock ( project , input ) ;
385385 return input + "\n" + result ;
386386 } catch ( e ) {
387+ if ( e . name !== "SCSSParsingError" ) {
388+ throw e ;
389+ }
387390 console . warn ( "Error adding css vars block" , e ) ;
388391 console . warn (
389392 "The resulting CSS file will not have SCSS color variables exported as CSS." ,
Original file line number Diff line number Diff line change @@ -15,8 +15,22 @@ import { propagateDeclarationTypes } from "./analyzer/declaration-types.ts";
1515import { getVariableDependencies } from "./analyzer/get-dependencies.ts" ;
1616
1717const { getSassAst } = makeParserModule ( parse ) ;
18+
19+ export class SCSSParsingError extends Error {
20+ constructor ( message : string ) {
21+ super ( `SCSS Parsing Error: ${ message } ` ) ;
22+ this . name = "SCSSParsingError" ;
23+ }
24+ }
25+
1826export const cssVarsBlock = ( scssSource : string ) => {
19- const ast = propagateDeclarationTypes ( cleanSassAst ( getSassAst ( scssSource ) ) ) ;
27+ let astOriginal ;
28+ try {
29+ astOriginal = getSassAst ( scssSource ) ;
30+ } catch ( e ) {
31+ throw new SCSSParsingError ( e . message ) ;
32+ }
33+ const ast = propagateDeclarationTypes ( cleanSassAst ( astOriginal ) ) ;
2034 const deps = getVariableDependencies ( ast ) ;
2135
2236 const output : string [ ] = [ ":root {" ] ;
Original file line number Diff line number Diff line change @@ -14,11 +14,16 @@ import { TempContext } from "../temp.ts";
1414import { safeRemoveIfExists } from "../path.ts" ;
1515import * as log from "../../deno_ral/log.ts" ;
1616import { onCleanup } from "../cleanup.ts" ;
17+ import { Cloneable } from "../safe-clone-deep.ts" ;
1718
18- class SassCache {
19+ class SassCache implements Cloneable < SassCache > {
1920 kv : Deno . Kv ;
2021 path : string ;
2122
23+ clone ( ) {
24+ return this ;
25+ }
26+
2227 constructor ( kv : Deno . Kv , path : string ) {
2328 this . kv = kv ;
2429 this . path = path ;
Original file line number Diff line number Diff line change @@ -51,6 +51,7 @@ import { isQmdFile } from "../../execute/qmd.ts";
5151import { dirAndStem } from "../../core/path.ts" ;
5252import { projectOutputDir } from "../../project/project-shared.ts" ;
5353import { existsSync } from "../../deno_ral/fs.ts" ;
54+ import { safeCloneDeep } from "../../core/safe-clone-deep.ts" ;
5455
5556export const htmlNotebookContributor : NotebookContributor = {
5657 resolve : resolveHtmlNotebook ,
@@ -85,7 +86,7 @@ function resolveHtmlNotebook(
8586 executedFile : ExecutedFile ,
8687 notebookMetadata ?: NotebookMetadata ,
8788) {
88- const resolved = ld . cloneDeep ( executedFile ) as ExecutedFile ;
89+ const resolved = safeCloneDeep ( executedFile ) as ExecutedFile ;
8990
9091 // Set the output file
9192 resolved . recipe . format . pandoc [ kOutputFile ] = `${ outputFile ( nbAbsPath ) } ` ;
Original file line number Diff line number Diff line change @@ -34,6 +34,7 @@ import { ipynbTitleTemplatePath } from "../../format/ipynb/format-ipynb.ts";
3434import { projectOutputDir } from "../../project/project-shared.ts" ;
3535import { existsSync } from "../../deno_ral/fs.ts" ;
3636import { dirname , join , relative } from "../../deno_ral/path.ts" ;
37+ import { safeCloneDeep } from "../../core/safe-clone-deep.ts" ;
3738
3839export const outputNotebookContributor : NotebookContributor = {
3940 resolve : resolveOutputNotebook ,
@@ -67,7 +68,7 @@ function resolveOutputNotebook(
6768 executedFile : ExecutedFile ,
6869 _notebookMetadata ?: NotebookMetadata ,
6970) {
70- const resolved = ld . cloneDeep ( executedFile ) ;
71+ const resolved = safeCloneDeep ( executedFile ) ;
7172 resolved . recipe . format . pandoc [ kOutputFile ] = outputFile ( nbAbsPath ) ;
7273 resolved . recipe . output = resolved . recipe . format . pandoc [ kOutputFile ] ;
7374
Original file line number Diff line number Diff line change @@ -37,6 +37,7 @@ import * as ld from "../../core/lodash.ts";
3737
3838import { error } from "../../deno_ral/log.ts" ;
3939import { Format } from "../../config/types.ts" ;
40+ import { safeCloneDeep } from "../../core/safe-clone-deep.ts" ;
4041
4142export const jatsContributor : NotebookContributor = {
4243 resolve : resolveJats ,
@@ -56,7 +57,7 @@ function resolveJats(
5657 executedFile : ExecutedFile ,
5758 _notebookMetadata ?: NotebookMetadata ,
5859) {
59- const resolved = ld . cloneDeep ( executedFile ) ;
60+ const resolved = safeCloneDeep ( executedFile ) ;
6061 const to =
6162 resolved . recipe . format . render [ kVariant ] ?. includes ( "+element_citations" )
6263 ? "jats+element_citations"
Original file line number Diff line number Diff line change @@ -38,6 +38,7 @@ import { ipynbTitleTemplatePath } from "../../format/ipynb/format-ipynb.ts";
3838import { projectScratchPath } from "../../project/project-scratch.ts" ;
3939import { ensureDirSync , existsSync } from "../../deno_ral/fs.ts" ;
4040import { dirname , join , relative } from "../../deno_ral/path.ts" ;
41+ import { safeCloneDeep } from "../../core/safe-clone-deep.ts" ;
4142
4243export const qmdNotebookContributor : NotebookContributor = {
4344 resolve : resolveOutputNotebook ,
@@ -86,7 +87,7 @@ function resolveOutputNotebook(
8687 executedFile : ExecutedFile ,
8788 _notebookMetadata ?: NotebookMetadata ,
8889) {
89- const resolved = ld . cloneDeep ( executedFile ) ;
90+ const resolved = safeCloneDeep ( executedFile ) ;
9091 resolved . recipe . format . pandoc [ kOutputFile ] = ipynbOutputFile ( nbAbsPath ) ;
9192 resolved . recipe . output = resolved . recipe . format . pandoc [ kOutputFile ] ;
9293
You can’t perform that action at this time.
0 commit comments