Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/src/core/dart-sass.ts
6428 views
1
/*
2
* dart-sass.ts
3
*
4
* Copyright (C) 2020-2022 Posit Software, PBC
5
*/
6
import { join } from "../deno_ral/path.ts";
7
8
import { architectureToolsPath } from "./resources.ts";
9
import { execProcess } from "./process.ts";
10
import { ProcessResult } from "./process-types.ts";
11
import { TempContext } from "./temp.ts";
12
import { lines } from "./text.ts";
13
import { debug, info } from "../deno_ral/log.ts";
14
import { existsSync } from "../deno_ral/fs.ts";
15
import { warnOnce } from "./log.ts";
16
import { isWindows } from "../deno_ral/platform.ts";
17
import { requireQuoting, safeWindowsExec } from "./windows.ts";
18
19
export function dartSassInstallDir() {
20
return architectureToolsPath("dart-sass");
21
}
22
23
export async function dartSassVersion() {
24
return await dartCommand(["--version"]);
25
}
26
27
export async function dartCompile(
28
input: string,
29
outputFilePath: string,
30
temp: TempContext,
31
loadPaths?: string[],
32
compressed?: boolean,
33
): Promise<string | undefined> {
34
// Write the scss to a file
35
// We were previously passing it via stdin, but that can be overflowed
36
const inputFilePath = temp.createFile({ suffix: ".scss" });
37
38
// Write the css itself to a file
39
Deno.writeTextFileSync(inputFilePath, input);
40
const args = [
41
inputFilePath,
42
outputFilePath,
43
"--style",
44
compressed ? "compressed" : "expanded",
45
"--quiet", // Remove this flag to get depedency warnings from SASS
46
];
47
48
if (loadPaths) {
49
loadPaths.forEach((loadPath) => {
50
args.push(`--load-path=${loadPath}`);
51
});
52
}
53
54
await dartCommand(args);
55
return outputFilePath;
56
}
57
58
/**
59
* Options for dartCommand
60
*/
61
export interface DartCommandOptions {
62
/**
63
* Override the sass executable path.
64
* Primarily used for testing with spaced paths.
65
*/
66
sassPath?: string;
67
}
68
69
export async function dartCommand(
70
args: string[],
71
options?: DartCommandOptions,
72
) {
73
const resolvePath = () => {
74
const dartOverrideCmd = Deno.env.get("QUARTO_DART_SASS");
75
if (dartOverrideCmd) {
76
if (!existsSync(dartOverrideCmd)) {
77
warnOnce(
78
`Specified QUARTO_DART_SASS does not exist, using built in dart sass.`,
79
);
80
} else {
81
return dartOverrideCmd;
82
}
83
}
84
85
const command = isWindows ? "sass.bat" : "sass";
86
return architectureToolsPath(join("dart-sass", command));
87
};
88
const sass = options?.sassPath ?? resolvePath();
89
90
// Process result helper (shared by Windows and non-Windows paths)
91
const processResult = (result: ProcessResult): string | undefined => {
92
if (result.success) {
93
if (result.stderr) {
94
info(result.stderr);
95
}
96
return result.stdout;
97
} else {
98
debug(`[DART path] : ${sass}`);
99
debug(`[DART args] : ${args.join(" ")}`);
100
debug(`[DART stdout] : ${result.stdout}`);
101
debug(`[DART stderr] : ${result.stderr}`);
102
103
const errLines = lines(result.stderr || "");
104
// truncate the last 2 lines (they include a pointer to the temp file containing
105
// all of the concatenated sass, which is more or less incomprehensible for users.
106
const errMsg = errLines.slice(0, errLines.length - 2).join("\n");
107
throw new Error("Theme file compilation failed:\n\n" + errMsg);
108
}
109
};
110
111
// On Windows, use safeWindowsExec to handle paths with spaces
112
// (e.g., when Quarto is installed in C:\Program Files\)
113
// See https://github.com/quarto-dev/quarto-cli/issues/13997
114
if (isWindows) {
115
const quoted = requireQuoting([sass, ...args]);
116
const result = await safeWindowsExec(
117
quoted.args[0],
118
quoted.args.slice(1),
119
(cmd: string[]) => {
120
return execProcess({
121
cmd: cmd[0],
122
args: cmd.slice(1),
123
stdout: "piped",
124
stderr: "piped",
125
});
126
},
127
);
128
return processResult(result);
129
}
130
131
// Non-Windows: direct execution
132
const result = await execProcess({
133
cmd: sass,
134
args,
135
stdout: "piped",
136
stderr: "piped",
137
});
138
return processResult(result);
139
}
140
141