Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/src/core/css.ts
3557 views
1
/*
2
* css.ts
3
*
4
* Copyright (C) 2020-2022 Posit Software, PBC
5
*/
6
7
import { existsSync } from "../deno_ral/fs.ts";
8
import { dirname, extname, join } from "../deno_ral/path.ts";
9
import { isFileRef } from "./http.ts";
10
import { normalizePath } from "./path.ts";
11
12
export const kCssUrlRegex =
13
/url\((?!['"]?(?:data|https?):)(['"])?([^'"]*?)\1\)/g;
14
export const kCssImportRegex =
15
/@import\s(?!['"](?:data|https?):)(['"])([^'"]*?)\1/g;
16
17
export function cssFileResourceReferences(files: string[]) {
18
return files.reduce((allRefs: string[], file: string) => {
19
if (extname(file).toLowerCase() === ".css") {
20
if (existsSync(file)) {
21
file = normalizePath(file);
22
const css = Deno.readTextFileSync(file);
23
const cssRefs = cssFileRefs(css).map((ref) => join(dirname(file), ref));
24
allRefs.push(...cssRefs);
25
allRefs.push(...cssFileResourceReferences(cssRefs));
26
}
27
}
28
return allRefs;
29
}, []);
30
}
31
32
export function isCssFile(path: string) {
33
return extname(path).toLowerCase() === ".css";
34
}
35
36
export function fixupCssReferences(
37
css: string,
38
resolveRef: (ref: string) => string,
39
) {
40
// fixup / copy refs from url()
41
let destCss = css.replaceAll(
42
kCssUrlRegex,
43
(_match, p1: string, p2: string) => {
44
const path = resolveRef(p2);
45
return `url(${p1 || ""}${path}${p1 || ""})`;
46
},
47
);
48
49
// fixup / copy refs from @import
50
destCss = destCss.replaceAll(
51
kCssImportRegex,
52
(_match, p1: string, p2: string) => {
53
const path = resolveRef(p2);
54
return `@import ${p1 || ""}${path}${p1 || ""}`;
55
},
56
);
57
58
return destCss;
59
}
60
61
export function cssFileRefs(css: string) {
62
return cssImports(css).concat(cssResources(css)).filter(isFileRef);
63
}
64
65
export function cssResources(css: string) {
66
return matchCss(css, kCssUrlRegex);
67
}
68
69
export function cssImports(css: string) {
70
return matchCss(css, kCssImportRegex);
71
}
72
73
function matchCss(css: string, regex: RegExp): string[] {
74
const matches = [];
75
regex.lastIndex = 0;
76
let match = regex.exec(css);
77
while (match != null) {
78
matches.push(match[2]);
79
match = regex.exec(css);
80
}
81
regex.lastIndex = 0;
82
return matches;
83
}
84
85
export function asCssFont(value: unknown): string | undefined {
86
if (!value) {
87
return undefined;
88
} else {
89
const fontFamily = String(value)
90
.split(",")
91
.map((font) => {
92
font = font.trim();
93
if (
94
font.includes(" ") && !font.startsWith('"') && !font.startsWith("'")
95
) {
96
font = `"${font}"`;
97
}
98
return font;
99
})
100
.filter((font) => font.length > 0)
101
.join(", ");
102
return `${fontFamily}`;
103
}
104
}
105
106
export function asCssNumber(value: unknown): string | undefined {
107
if (typeof value === "number") {
108
return String(value);
109
} else if (!value) {
110
return undefined;
111
} else {
112
const str = String(value);
113
const match = str.match(/(^[0-9]*)/);
114
if (match) {
115
return match[1];
116
} else {
117
return undefined;
118
}
119
}
120
}
121
122
export function asCssSize(value: unknown): string | undefined {
123
if (typeof value === "number") {
124
if (value === 0) {
125
return "0";
126
} else {
127
return value + "px";
128
}
129
} else if (!value) {
130
return undefined;
131
} else {
132
const str = String(value);
133
if (str !== "0" && !str.match(/[^0-9]$/)) {
134
return str + "px";
135
} else {
136
return str;
137
}
138
}
139
}
140
141
export function asCssColor(value: unknown): string | undefined {
142
if (typeof value === "string") {
143
if (value === "none") {
144
return "transparent";
145
} else {
146
return value;
147
}
148
}
149
}
150
151
// The named colors
152
const kBootstrapColors = [
153
"primary",
154
"secondary",
155
"success",
156
"info",
157
"warning",
158
"danger",
159
"light",
160
"dark",
161
];
162
163
const kBootstrapPaletteRegex = RegExp(
164
`gray\-[1-9]00`,
165
);
166
167
export function asBootstrapColor(value: unknown): string | undefined {
168
if (typeof value === "string") {
169
if (
170
kBootstrapColors.includes(value) || value.match(kBootstrapPaletteRegex)
171
) {
172
return `$${value}`;
173
} else {
174
return asCssColor(value);
175
}
176
}
177
}
178
179