@codenhub/styles 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.es.md +9 -9
- package/README.md +8 -8
- package/README.pt-BR.md +9 -9
- package/dist/aesthetics/chunky-tile.css +1 -1
- package/dist/aesthetics/cyber.css +1 -1
- package/dist/aesthetics/glass.css +1 -1
- package/dist/aesthetics/index.css +1 -1
- package/dist/aesthetics/neobrutalism.css +1 -1
- package/dist/aesthetics/pixel.css +1 -1
- package/dist/aesthetics/sketch.css +1 -1
- package/dist/cli.js +231 -62
- package/dist/components.css +49 -1
- package/dist/index.css +49 -1
- package/dist/native.css +49 -1
- package/dist/purge/classes.json +1 -0
- package/dist/purge/index.css +50 -0
- package/dist/theme.css +1 -1
- package/docs/changelog/0.8.0.md +1 -1
- package/docs/changelog/0.9.0.md +40 -0
- package/docs/changelog/index.md +1 -0
- package/docs/es/index.md +2 -2
- package/docs/es/integrating/tailwind.md +2 -1
- package/docs/es/integrating/without-a-bundler.md +60 -31
- package/docs/es/setup.md +4 -3
- package/docs/es/usage/aesthetics.md +2 -2
- package/docs/es/usage/content-and-layout.md +3 -1
- package/docs/es/usage/customizing.md +30 -16
- package/docs/es/usage/forms.md +2 -2
- package/docs/es/usage/index.md +2 -2
- package/docs/es/usage/solo.md +2 -2
- package/docs/es/usage/theming.md +2 -2
- package/docs/es/usage/tooltips.md +2 -2
- package/docs/index.md +1 -1
- package/docs/integrating/tailwind.md +1 -0
- package/docs/integrating/without-a-bundler.md +59 -30
- package/docs/pt-BR/index.md +2 -2
- package/docs/pt-BR/integrating/tailwind.md +2 -1
- package/docs/pt-BR/integrating/without-a-bundler.md +60 -31
- package/docs/pt-BR/setup.md +4 -3
- package/docs/pt-BR/usage/aesthetics.md +2 -2
- package/docs/pt-BR/usage/content-and-layout.md +3 -1
- package/docs/pt-BR/usage/customizing.md +30 -16
- package/docs/pt-BR/usage/forms.md +2 -2
- package/docs/pt-BR/usage/index.md +2 -2
- package/docs/pt-BR/usage/solo.md +2 -2
- package/docs/pt-BR/usage/theming.md +2 -2
- package/docs/pt-BR/usage/tooltips.md +2 -2
- package/docs/setup.md +3 -2
- package/docs/usage/aesthetics.md +1 -1
- package/docs/usage/content-and-layout.md +2 -0
- package/docs/usage/customizing.md +29 -15
- package/docs/usage/forms.md +1 -1
- package/docs/usage/index.md +1 -1
- package/docs/usage/solo.md +1 -1
- package/docs/usage/theming.md +1 -1
- package/docs/usage/tooltips.md +1 -1
- package/llms-full.txt +145 -61
- package/llms.txt +3 -2
- package/package.json +12 -10
- package/tw/aesthetics/chunky-tile.css +4 -1
- package/tw/aesthetics/cyber.css +4 -1
- package/tw/aesthetics/glass.css +5 -0
- package/tw/aesthetics/neobrutalism.css +4 -1
- package/tw/aesthetics/pixel.css +3 -0
- package/tw/aesthetics/sketch.css +18 -0
- package/tw/box.css +21 -15
- package/tw/components/button.rules.css +1 -1
- package/tw/components/feedback.rules.css +22 -3
- package/tw/components/form.rules.css +65 -35
- package/tw/components/surface.rules.css +8 -5
- package/tw/components/tooltip.rules.css +39 -34
- package/tw/elevation.css +8 -8
- package/tw/native.css +4 -1
- package/tw/theme.css +1 -1
- package/tw/utilities/content.css +74 -54
- package/tw/utilities/layout.css +7 -5
package/dist/cli.js
CHANGED
|
@@ -1,15 +1,213 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { createRequire } from "node:module";
|
|
3
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
4
3
|
import * as fs from "node:fs/promises";
|
|
5
4
|
import path from "node:path";
|
|
6
|
-
import { fileURLToPath
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
7
6
|
import { parseArgs } from "node:util";
|
|
7
|
+
// src/cli/purge.ts
|
|
8
|
+
const GROUPS = /* @__PURE__ */ new Set([
|
|
9
|
+
"@media",
|
|
10
|
+
"@supports",
|
|
11
|
+
"@layer",
|
|
12
|
+
"@container",
|
|
13
|
+
"@scope",
|
|
14
|
+
"@starting-style"
|
|
15
|
+
]);
|
|
16
|
+
const IDENT = /^(?:\\[0-9a-fA-F]{1,6}\s?|\\.|[\w-]|\P{ASCII})+/u;
|
|
17
|
+
const ANY_OF = /* @__PURE__ */ new Set([
|
|
18
|
+
"is",
|
|
19
|
+
"where",
|
|
20
|
+
"has"
|
|
21
|
+
]);
|
|
22
|
+
/** Returns the index just past the string or comment that starts at `index`, or `index` when none does. */
|
|
23
|
+
function skipInert(css, index) {
|
|
24
|
+
const char = css[index];
|
|
25
|
+
if (char === "\"" || char === "'") {
|
|
26
|
+
for (let i = index + 1; i < css.length; i++) if (css[i] === "\\") i++;
|
|
27
|
+
else if (css[i] === char) return i + 1;
|
|
28
|
+
return css.length;
|
|
29
|
+
}
|
|
30
|
+
if (char === "/" && css[index + 1] === "*") {
|
|
31
|
+
const end = css.indexOf("*/", index + 2);
|
|
32
|
+
return end === -1 ? css.length : end + 2;
|
|
33
|
+
}
|
|
34
|
+
return index;
|
|
35
|
+
}
|
|
36
|
+
/** Returns the index of the first `stop` character at bracket depth zero from `from`, or `end` when there is none. */
|
|
37
|
+
function findTop(css, from, end, stop) {
|
|
38
|
+
let depth = 0;
|
|
39
|
+
for (let i = from; i < end; i++) {
|
|
40
|
+
const next = skipInert(css, i);
|
|
41
|
+
if (next !== i) {
|
|
42
|
+
i = next - 1;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const char = css[i];
|
|
46
|
+
if (char === "\\") i++;
|
|
47
|
+
else if (depth === 0 && stop.includes(char)) return i;
|
|
48
|
+
else if (char === "(" || char === "[" || char === "{") depth++;
|
|
49
|
+
else if (char === ")" || char === "]" || char === "}") depth--;
|
|
50
|
+
}
|
|
51
|
+
return end;
|
|
52
|
+
}
|
|
53
|
+
function splitTop(text, separator) {
|
|
54
|
+
const parts = [];
|
|
55
|
+
let from = 0;
|
|
56
|
+
while (from <= text.length) {
|
|
57
|
+
const at = findTop(text, from, text.length, separator);
|
|
58
|
+
parts.push(text.slice(from, at));
|
|
59
|
+
from = at + 1;
|
|
60
|
+
}
|
|
61
|
+
return parts;
|
|
62
|
+
}
|
|
63
|
+
function parse(css, start = 0, end = css.length) {
|
|
64
|
+
const nodes = [];
|
|
65
|
+
let index = start;
|
|
66
|
+
while (index < end) {
|
|
67
|
+
let comment = index;
|
|
68
|
+
while (comment < end && /\s/.test(css[comment])) comment++;
|
|
69
|
+
if (css.startsWith("/*", comment)) {
|
|
70
|
+
const after = skipInert(css, comment);
|
|
71
|
+
nodes.push({
|
|
72
|
+
kind: "statement",
|
|
73
|
+
text: css.slice(index, after)
|
|
74
|
+
});
|
|
75
|
+
index = after;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const open = findTop(css, index, end, "{;");
|
|
79
|
+
if (open >= end || css[open] === ";") {
|
|
80
|
+
nodes.push({
|
|
81
|
+
kind: "statement",
|
|
82
|
+
text: css.slice(index, Math.min(open + 1, end))
|
|
83
|
+
});
|
|
84
|
+
index = open + 1;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const close = findTop(css, open + 1, end, "}");
|
|
88
|
+
const prelude = css.slice(index, open);
|
|
89
|
+
const atRule = /^\s*(@[\w-]+)/.exec(prelude)?.[1];
|
|
90
|
+
if (atRule !== void 0 && GROUPS.has(atRule)) nodes.push({
|
|
91
|
+
kind: "group",
|
|
92
|
+
prelude,
|
|
93
|
+
children: parse(css, open + 1, close)
|
|
94
|
+
});
|
|
95
|
+
else nodes.push({
|
|
96
|
+
kind: "block",
|
|
97
|
+
prelude,
|
|
98
|
+
body: css.slice(open + 1, close),
|
|
99
|
+
isRule: atRule === void 0
|
|
100
|
+
});
|
|
101
|
+
index = close + 1;
|
|
102
|
+
}
|
|
103
|
+
return nodes;
|
|
104
|
+
}
|
|
105
|
+
function serialize(nodes) {
|
|
106
|
+
let css = "";
|
|
107
|
+
for (const node of nodes) if (node.kind === "statement") css += node.text;
|
|
108
|
+
else if (node.kind === "group") css += `${node.prelude}{${serialize(node.children)}}`;
|
|
109
|
+
else css += `${node.prelude}{${node.body}}`;
|
|
110
|
+
return css;
|
|
111
|
+
}
|
|
112
|
+
/** Writes the tree one declaration to a line, for `--no-minify`. */
|
|
113
|
+
function format(nodes, indent = "") {
|
|
114
|
+
let css = "";
|
|
115
|
+
for (const node of nodes) if (node.kind === "statement") css += `${indent}${node.text.trim()}\n`;
|
|
116
|
+
else if (node.kind === "group") css += `${indent}${node.prelude.trim()} {\n${format(node.children, `${indent} `)}${indent}}\n`;
|
|
117
|
+
else if (node.isRule) {
|
|
118
|
+
const selectors = splitTop(node.prelude, ",").map((selector) => selector.trim());
|
|
119
|
+
const declarations = splitTop(node.body, ";").filter((declaration) => declaration.trim() !== "");
|
|
120
|
+
css += `${indent}${selectors.join(`,\n${indent}`)} {\n`;
|
|
121
|
+
css += declarations.map((declaration) => `${indent} ${declaration.trim()};\n`).join("");
|
|
122
|
+
css += `${indent}}\n`;
|
|
123
|
+
} else css += `${indent}${node.prelude.trim()} { ${node.body} }\n`;
|
|
124
|
+
return css;
|
|
125
|
+
}
|
|
126
|
+
function unescapeIdent(raw) {
|
|
127
|
+
return raw.replace(/\\([0-9a-fA-F]{1,6})\s?|\\(.)/g, (_, hex, char) => {
|
|
128
|
+
if (hex === void 0) return char;
|
|
129
|
+
const code = Number.parseInt(hex, 16);
|
|
130
|
+
return code === 0 || code >= 55296 && code <= 57343 || code > 1114111 ? "�" : String.fromCodePoint(code);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Says whether a selector can match in markup whose classes are all in `used`.
|
|
135
|
+
* Every class the selector requires has to be there. A class inside `:not()` is
|
|
136
|
+
* never required, and of the selectors inside `:is()`, `:where()`, and `:has()`
|
|
137
|
+
* one is enough. `onClass`, when given, is told every class name it reads.
|
|
138
|
+
*/
|
|
139
|
+
function canMatch(selector, used, onClass) {
|
|
140
|
+
let isMatch = true;
|
|
141
|
+
for (let i = 0; i < selector.length; i++) {
|
|
142
|
+
const next = skipInert(selector, i);
|
|
143
|
+
if (next !== i) {
|
|
144
|
+
i = next - 1;
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const char = selector[i];
|
|
148
|
+
if (char === "\\") i++;
|
|
149
|
+
else if (char === "[") i = findTop(selector, i + 1, selector.length, "]");
|
|
150
|
+
else if (char === ".") {
|
|
151
|
+
const raw = IDENT.exec(selector.slice(i + 1))?.[0];
|
|
152
|
+
if (raw !== void 0) {
|
|
153
|
+
const name = unescapeIdent(raw);
|
|
154
|
+
onClass?.(name);
|
|
155
|
+
isMatch &&= used.has(name);
|
|
156
|
+
i += raw.length;
|
|
157
|
+
}
|
|
158
|
+
} else if (char === ":") {
|
|
159
|
+
const pseudo = /^::?([\w-]+)\(/.exec(selector.slice(i));
|
|
160
|
+
if (pseudo !== null) {
|
|
161
|
+
const open = i + pseudo[0].length;
|
|
162
|
+
const close = findTop(selector, open, selector.length, ")");
|
|
163
|
+
const branches = splitTop(selector.slice(open, close), ",");
|
|
164
|
+
if (ANY_OF.has(pseudo[1])) {
|
|
165
|
+
const results = branches.map((branch) => canMatch(branch, used, onClass));
|
|
166
|
+
isMatch &&= results.includes(true);
|
|
167
|
+
} else if (onClass !== void 0) for (const branch of branches) canMatch(branch, used, onClass);
|
|
168
|
+
i = close;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (!isMatch && onClass === void 0) return false;
|
|
172
|
+
}
|
|
173
|
+
return isMatch;
|
|
174
|
+
}
|
|
175
|
+
function isLayer(node) {
|
|
176
|
+
return node.kind === "group" && /^\s*@layer\b/.test(node.prelude);
|
|
177
|
+
}
|
|
178
|
+
function isEmptyLayer(node) {
|
|
179
|
+
return node.kind === "group" && isLayer(node) && node.children.every(isEmptyLayer);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Returns the tree without the rules that cannot match `used`. A selector list
|
|
183
|
+
* keeps only its selectors that can. A `@layer` block emptied this way stays,
|
|
184
|
+
* because where it first stands fixes the layer's place in the cascade, unless
|
|
185
|
+
* it is all that is left of a `@media` or `@supports` block: those hold a
|
|
186
|
+
* variant's rules, which come after the layer's first block.
|
|
187
|
+
*/
|
|
188
|
+
function purge(nodes, used) {
|
|
189
|
+
const kept = [];
|
|
190
|
+
for (const node of nodes) if (node.kind === "group") {
|
|
191
|
+
const children = purge(node.children, used);
|
|
192
|
+
if (isLayer(node) ? true : children.some((child) => !isEmptyLayer(child))) kept.push({
|
|
193
|
+
...node,
|
|
194
|
+
children
|
|
195
|
+
});
|
|
196
|
+
} else if (node.kind === "block" && node.isRule) {
|
|
197
|
+
const selectors = splitTop(node.prelude, ",").filter((selector) => canMatch(selector, used));
|
|
198
|
+
if (selectors.length > 0) kept.push({
|
|
199
|
+
...node,
|
|
200
|
+
prelude: selectors.join(",")
|
|
201
|
+
});
|
|
202
|
+
} else kept.push(node);
|
|
203
|
+
return kept;
|
|
204
|
+
}
|
|
8
205
|
// src/cli/run.ts
|
|
9
|
-
const BIN = "
|
|
206
|
+
const BIN = "chs";
|
|
10
207
|
const MIN_NODE_MAJOR = 24;
|
|
11
|
-
const
|
|
12
|
-
const
|
|
208
|
+
const AESTHETIC_EXPORT = /^\.\/aesthetics\/([^/]+)$/;
|
|
209
|
+
const PURGE_SOURCE = "dist/purge/index.css";
|
|
210
|
+
const PURGE_CLASSES = "dist/purge/classes.json";
|
|
13
211
|
const USAGE = `Usage: ${BIN} build --content <glob> [--content <glob> ...] --output <file> [options]
|
|
14
212
|
|
|
15
213
|
Builds a StyleKit stylesheet holding only the classes your templates use.
|
|
@@ -22,7 +220,6 @@ Options:
|
|
|
22
220
|
--no-minify Write readable CSS instead of minified CSS.
|
|
23
221
|
--help Show this help.
|
|
24
222
|
--version Show the version.`;
|
|
25
|
-
const POLYFILLS_NONE = 0;
|
|
26
223
|
async function run(argv, io) {
|
|
27
224
|
try {
|
|
28
225
|
const parsed = parseCommandLine(argv);
|
|
@@ -90,47 +287,46 @@ function parseFlags(argv) {
|
|
|
90
287
|
}
|
|
91
288
|
async function build(options, io) {
|
|
92
289
|
assertNodeVersion(io.nodeVersion);
|
|
93
|
-
const tailwind = loadTailwind(io);
|
|
94
290
|
const validAesthetics = readAestheticNames();
|
|
95
291
|
const unknown = options.aesthetics.find((name) => !validAesthetics.includes(name));
|
|
96
292
|
if (unknown !== void 0) throw new Error(`unknown aesthetic "${unknown}"; choose from ${validAesthetics.join(", ")}.`);
|
|
97
|
-
await Promise.all(options.contentGlobs.map((pattern) =>
|
|
293
|
+
const files = new Set((await Promise.all(options.contentGlobs.map((pattern) => findFiles(pattern, io.cwd)))).flat());
|
|
294
|
+
const contents = [];
|
|
295
|
+
for (const file of files) contents.push(await fs.readFile(file, "utf8"));
|
|
296
|
+
const droppable = new Set(JSON.parse(await readPackageFile(PURGE_CLASSES)));
|
|
297
|
+
const found = new Set(contents.flatMap((content) => findClasses(content, droppable)));
|
|
298
|
+
const used = { has: (name) => found.has(name) || !droppable.has(name) };
|
|
299
|
+
const stylesheets = await Promise.all([PURGE_SOURCE, ...options.aesthetics.map((name) => resolveExport(`./aesthetics/${name}`))].map(readPackageFile));
|
|
300
|
+
const write = options.shouldMinify ? serialize : format;
|
|
301
|
+
const css = stylesheets.map((stylesheet) => write(purge(parse(stylesheet), used))).join("");
|
|
98
302
|
const output = path.resolve(io.cwd, options.output);
|
|
99
|
-
const
|
|
100
|
-
`@import ${cssString(resolveExport("./tw"))};`,
|
|
101
|
-
...options.aesthetics.map((name) => `@import ${cssString(resolveExport(`./tw/aesthetics/${name}`))};`),
|
|
102
|
-
...options.contentGlobs.map((pattern) => `@source ${cssString(toCssPath(path.resolve(io.cwd, pattern)))};`)
|
|
103
|
-
].join("\n");
|
|
303
|
+
const temporary = `${output}.${process.pid}.tmp`;
|
|
104
304
|
try {
|
|
105
|
-
const css = await compileStylesheet(tailwind, input, io.cwd, options.shouldMinify);
|
|
106
305
|
await fs.mkdir(path.dirname(output), { recursive: true });
|
|
107
|
-
await fs.writeFile(
|
|
306
|
+
await fs.writeFile(temporary, css);
|
|
307
|
+
await fs.rename(temporary, output);
|
|
108
308
|
} catch (error) {
|
|
109
|
-
|
|
309
|
+
await fs.rm(temporary, { force: true }).catch(() => void 0);
|
|
310
|
+
throw new Error(`cannot write the stylesheet: ${error instanceof Error ? error.message : String(error)}`);
|
|
110
311
|
}
|
|
111
312
|
return output;
|
|
112
313
|
}
|
|
113
|
-
|
|
314
|
+
/** Returns the files a `--content` glob matches, as absolute paths, and fails when there are none. */
|
|
315
|
+
async function findFiles(pattern, cwd) {
|
|
316
|
+
const files = [];
|
|
114
317
|
for await (const entry of fs.glob(pattern, {
|
|
115
318
|
cwd,
|
|
116
319
|
withFileTypes: true
|
|
117
|
-
})) if (entry.isFile())
|
|
118
|
-
throw new Error(`--content "${pattern}" matches no file in ${cwd}; check the path, or run from the project root.`);
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
from: path.join(cwd, "codenhub-styles.css"),
|
|
124
|
-
polyfills: POLYFILLS_NONE,
|
|
125
|
-
onDependency() {}
|
|
126
|
-
});
|
|
127
|
-
const scanner = new tailwind.Scanner({ sources: compiler.sources });
|
|
128
|
-
const css = compiler.build(scanner.scan());
|
|
129
|
-
return shouldMinify ? tailwind.optimize(css, { minify: true }).code : css;
|
|
320
|
+
})) if (entry.isFile()) files.push(path.resolve(entry.parentPath, entry.name));
|
|
321
|
+
if (files.length === 0) throw new Error(`--content "${pattern}" matches no file in ${cwd}; check the path, or run from the project root.`);
|
|
322
|
+
return files;
|
|
323
|
+
}
|
|
324
|
+
function findClasses(content, known) {
|
|
325
|
+
return content.split(/[^\w:-]+/).flatMap((word) => known.has(word) ? [word] : word.split(":")).filter((word) => known.has(word));
|
|
130
326
|
}
|
|
131
327
|
function readAestheticNames() {
|
|
132
328
|
const { exports } = readManifest();
|
|
133
|
-
return Object.keys(exports).map((subpath) =>
|
|
329
|
+
return Object.keys(exports).map((subpath) => AESTHETIC_EXPORT.exec(subpath)?.[1]).filter((name) => name !== void 0).sort();
|
|
134
330
|
}
|
|
135
331
|
/** Returns the nearest folder at or above `from` that holds a `package.json`. */
|
|
136
332
|
function findPackageRoot(from) {
|
|
@@ -144,45 +340,18 @@ function readManifest() {
|
|
|
144
340
|
return JSON.parse(readFileSync(path.join(packageRoot, "package.json"), "utf8"));
|
|
145
341
|
}
|
|
146
342
|
function resolveExport(subpath) {
|
|
147
|
-
|
|
148
|
-
|
|
343
|
+
return readManifest().exports[subpath].import;
|
|
344
|
+
}
|
|
345
|
+
function readPackageFile(relativePath) {
|
|
346
|
+
return fs.readFile(path.resolve(packageRoot, relativePath), "utf8");
|
|
149
347
|
}
|
|
150
348
|
function assertNodeVersion(nodeVersion) {
|
|
151
349
|
if (Number.parseInt(nodeVersion, 10) < MIN_NODE_MAJOR) throw new Error(`this command needs Node.js ${MIN_NODE_MAJOR} or newer; this is Node.js ${nodeVersion}.`);
|
|
152
350
|
}
|
|
153
|
-
/** Loads Tailwind's compiler from where `@tailwindcss/cli` is installed, after checking both Tailwind packages are. */
|
|
154
|
-
function loadTailwind(io) {
|
|
155
|
-
const manifests = TAILWIND_PACKAGES.map((name) => resolveManifest(name, io));
|
|
156
|
-
const missing = TAILWIND_PACKAGES.filter((_, index) => manifests[index] === void 0);
|
|
157
|
-
if (missing.length > 0) throw new Error(`this command needs ${missing.join(" and ")}, which ${missing.length > 1 ? "are" : "is"} not installed. Run: npm install --save-dev ${missing.join(" ")}`);
|
|
158
|
-
const requireFromCli = createRequire(manifests[0]);
|
|
159
|
-
const { compile, optimize } = requireFromCli("@tailwindcss/node");
|
|
160
|
-
const { Scanner } = requireFromCli("@tailwindcss/oxide");
|
|
161
|
-
return {
|
|
162
|
-
compile,
|
|
163
|
-
optimize,
|
|
164
|
-
Scanner
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
function resolveManifest(name, io) {
|
|
168
|
-
try {
|
|
169
|
-
return io.resolvePackage(`${name}/package.json`);
|
|
170
|
-
} catch (error) {
|
|
171
|
-
if (error.code === "MODULE_NOT_FOUND") return;
|
|
172
|
-
throw error;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
function toCssPath(filePath) {
|
|
176
|
-
return filePath.split(path.sep).join("/");
|
|
177
|
-
}
|
|
178
|
-
function cssString(value) {
|
|
179
|
-
return `"${value.replace(/["\\]/g, "\\$&")}"`;
|
|
180
|
-
}
|
|
181
351
|
// src/cli/cli.ts
|
|
182
352
|
process.exitCode = await run(process.argv.slice(2), {
|
|
183
353
|
cwd: process.cwd(),
|
|
184
354
|
nodeVersion: process.versions.node,
|
|
185
|
-
resolvePackage: createRequire(import.meta.url).resolve,
|
|
186
355
|
stdout: (line) => process.stdout.write(`${line}\n`),
|
|
187
356
|
stderr: (line) => process.stderr.write(`${line}\n`)
|
|
188
357
|
});
|