@projectwallace/format-css 2.2.5 → 3.0.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.md +45 -15
- package/dist/cli.mjs +96 -0
- package/dist/index.d.ts +11 -7
- package/dist/index.js +335 -0
- package/package.json +35 -39
- package/dist/format-css.js +0 -216
package/README.md
CHANGED
|
@@ -41,10 +41,10 @@ npm install @projectwallace/format-css
|
|
|
41
41
|
## Usage
|
|
42
42
|
|
|
43
43
|
```js
|
|
44
|
-
import { format } from
|
|
44
|
+
import { format } from '@projectwallace/format-css'
|
|
45
45
|
|
|
46
|
-
let old_css =
|
|
47
|
-
let new_css = format(old_css)
|
|
46
|
+
let old_css = '/* Your old CSS here */'
|
|
47
|
+
let new_css = format(old_css)
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
Need more examples?
|
|
@@ -65,34 +65,64 @@ Need more examples?
|
|
|
65
65
|
1. Multiline tokens like **Selectors, Values, etc.** are rendered on a single line
|
|
66
66
|
1. Unknown syntax is rendered as-is, with multi-line formatting kept intact
|
|
67
67
|
|
|
68
|
-
##
|
|
68
|
+
## Options
|
|
69
|
+
|
|
70
|
+
### Minify CSS
|
|
69
71
|
|
|
70
72
|
This package also exposes a minifier function since minifying CSS follows many of the same rules as formatting.
|
|
71
73
|
|
|
72
74
|
```js
|
|
73
|
-
import { format, minify } from
|
|
75
|
+
import { format, minify } from '@projectwallace/format-css'
|
|
74
76
|
|
|
75
|
-
let minified = minify(
|
|
77
|
+
let minified = minify('a {}')
|
|
76
78
|
|
|
77
79
|
// which is an alias for
|
|
78
80
|
|
|
79
|
-
let formatted_mini = format(
|
|
81
|
+
let formatted_mini = format('a {}', { minify: true })
|
|
80
82
|
```
|
|
81
83
|
|
|
82
|
-
|
|
84
|
+
### Tab size
|
|
83
85
|
|
|
84
86
|
For cases where you cannot control the tab size with CSS there is an option to override the default tabbed indentation with N spaces.
|
|
85
87
|
|
|
86
88
|
```js
|
|
87
|
-
import { format } from
|
|
89
|
+
import { format } from '@projectwallace/format-css'
|
|
90
|
+
|
|
91
|
+
let formatted = format('a { color: red; }', {
|
|
92
|
+
tab_size: 2,
|
|
93
|
+
})
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## CLI
|
|
97
|
+
|
|
98
|
+
This library also ships a CLI tools that's a small wrapper around the library.
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
USAGE
|
|
102
|
+
format-css [options] [file...]
|
|
103
|
+
cat styles.css | format-css [options]
|
|
104
|
+
|
|
105
|
+
OPTIONS
|
|
106
|
+
--minify Minify the CSS output
|
|
107
|
+
--tab-size=<n> Use N spaces for indentation instead of tabs
|
|
108
|
+
--help, -h Show this help
|
|
109
|
+
|
|
110
|
+
EXAMPLES
|
|
111
|
+
# Format a file
|
|
112
|
+
format-css styles.css
|
|
113
|
+
|
|
114
|
+
# Format with 2-space indentation
|
|
115
|
+
format-css styles.css --tab-size=2
|
|
116
|
+
|
|
117
|
+
# Minify
|
|
118
|
+
format-css styles.css --minify
|
|
88
119
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
});
|
|
120
|
+
# Via pipe
|
|
121
|
+
cat styles.css | format-css
|
|
92
122
|
```
|
|
93
123
|
|
|
94
124
|
## Related projects
|
|
95
125
|
|
|
96
|
-
- [Format CSS online](https://www.projectwallace.com/prettify-css
|
|
97
|
-
- [Minify CSS online](https://www.projectwallace.com/minify-css
|
|
98
|
-
- [CSS Analyzer](https://github.com/projectwallace/css-analyzer) - The best CSS analyzer that powers all analysis on [projectwallace.com](https://www.projectwallace.com
|
|
126
|
+
- [Format CSS online](https://www.projectwallace.com/prettify-css) - See this formatter in action online!
|
|
127
|
+
- [Minify CSS online](https://www.projectwallace.com/minify-css) - See this minifier in action online!
|
|
128
|
+
- [CSS Analyzer](https://github.com/projectwallace/css-analyzer) - The best CSS analyzer that powers all analysis on [projectwallace.com](https://www.projectwallace.com)
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs, styleText } from "node:util";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { resolve, sep } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { format } from "@projectwallace/format-css";
|
|
7
|
+
//#region src/cli/cli.ts
|
|
8
|
+
function help() {
|
|
9
|
+
return `
|
|
10
|
+
${styleText("bold", "USAGE")}
|
|
11
|
+
format-css [options] [file...]
|
|
12
|
+
cat styles.css | format-css [options]
|
|
13
|
+
|
|
14
|
+
${styleText("bold", "OPTIONS")}
|
|
15
|
+
--minify Minify the CSS output
|
|
16
|
+
--tab-size=<n> Use N spaces for indentation instead of tabs
|
|
17
|
+
--help, -h Show this help
|
|
18
|
+
|
|
19
|
+
${styleText("bold", "EXAMPLES")}
|
|
20
|
+
${styleText("dim", "# Format a file")}
|
|
21
|
+
format-css styles.css
|
|
22
|
+
|
|
23
|
+
${styleText("dim", "# Format with 2-space indentation")}
|
|
24
|
+
format-css styles.css --tab-size=2
|
|
25
|
+
|
|
26
|
+
${styleText("dim", "# Minify")}
|
|
27
|
+
format-css styles.css --minify
|
|
28
|
+
|
|
29
|
+
${styleText("dim", "# Via pipe")}
|
|
30
|
+
cat styles.css | format-css
|
|
31
|
+
`.trim();
|
|
32
|
+
}
|
|
33
|
+
function parse_arguments(args) {
|
|
34
|
+
const { values, positionals } = parseArgs({
|
|
35
|
+
args,
|
|
36
|
+
allowPositionals: true,
|
|
37
|
+
options: {
|
|
38
|
+
minify: {
|
|
39
|
+
type: "boolean",
|
|
40
|
+
default: false
|
|
41
|
+
},
|
|
42
|
+
"tab-size": { type: "string" }
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
const issues = [];
|
|
46
|
+
let tab_size;
|
|
47
|
+
if (values["tab-size"] !== void 0) {
|
|
48
|
+
tab_size = Number(values["tab-size"]);
|
|
49
|
+
if (isNaN(tab_size) || tab_size < 1) issues.push("--tab-size must be a positive integer");
|
|
50
|
+
}
|
|
51
|
+
const cwd = process.cwd();
|
|
52
|
+
const files = [];
|
|
53
|
+
for (const file of positionals) {
|
|
54
|
+
const resolved = resolve(file);
|
|
55
|
+
if (resolved !== cwd && !resolved.startsWith(cwd + sep)) issues.push(`Invalid path: ${file}`);
|
|
56
|
+
else files.push(resolved);
|
|
57
|
+
}
|
|
58
|
+
if (issues.length > 0) throw new Error(issues.join("\n"));
|
|
59
|
+
return {
|
|
60
|
+
files,
|
|
61
|
+
minify: values.minify ?? false,
|
|
62
|
+
tab_size
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
async function run(args, io) {
|
|
66
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
67
|
+
io.write(help() + "\n");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const { files, minify, tab_size } = parse_arguments(args);
|
|
71
|
+
const options = {
|
|
72
|
+
minify,
|
|
73
|
+
tab_size
|
|
74
|
+
};
|
|
75
|
+
if (files.length > 0) for (const file of files) io.write(format(io.readFile(file), options));
|
|
76
|
+
else if (!io.isTTY) io.write(format(await io.readStdin(), options));
|
|
77
|
+
else io.write(help() + "\n");
|
|
78
|
+
}
|
|
79
|
+
async function read_stdin() {
|
|
80
|
+
const chunks = [];
|
|
81
|
+
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
82
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
83
|
+
}
|
|
84
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) try {
|
|
85
|
+
await run(process.argv.slice(2), {
|
|
86
|
+
readFile: (path) => readFileSync(path, "utf-8"),
|
|
87
|
+
readStdin: read_stdin,
|
|
88
|
+
write: (output) => process.stdout.write(output),
|
|
89
|
+
isTTY: process.stdin.isTTY === true
|
|
90
|
+
});
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
96
|
+
export { parse_arguments, run };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
tab_size?: number;
|
|
1
|
+
//#region src/lib/index.d.ts
|
|
2
|
+
type FormatOptions = {
|
|
3
|
+
/** Whether to minify the CSS or keep it formatted */minify?: boolean; /** Tell the formatter to use N spaces instead of tabs */
|
|
4
|
+
tab_size?: number;
|
|
6
5
|
};
|
|
7
6
|
/**
|
|
8
7
|
* Format a string of CSS using some simple rules
|
|
9
8
|
*/
|
|
10
|
-
|
|
9
|
+
declare function format(css: string, {
|
|
10
|
+
minify,
|
|
11
|
+
tab_size
|
|
12
|
+
}?: FormatOptions): string;
|
|
11
13
|
/**
|
|
12
14
|
* Minify a string of CSS
|
|
13
15
|
* @param {string} css The original CSS
|
|
14
16
|
* @returns {string} The minified CSS
|
|
15
17
|
*/
|
|
16
|
-
|
|
18
|
+
declare function minify(css: string): string;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { FormatOptions, format, minify };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import { ATTR_FLAG_NAMES, ATTR_OPERATOR_NAMES, NODE_TYPES, parse } from "@projectwallace/css-parser";
|
|
2
|
+
//#region src/lib/index.ts
|
|
3
|
+
const SPACE = " ";
|
|
4
|
+
const EMPTY_STRING = "";
|
|
5
|
+
const COLON = ":";
|
|
6
|
+
const SEMICOLON = ";";
|
|
7
|
+
const QUOTE = "\"";
|
|
8
|
+
const OPEN_PARENTHESES = "(";
|
|
9
|
+
const CLOSE_PARENTHESES = ")";
|
|
10
|
+
const OPEN_BRACKET = "[";
|
|
11
|
+
const CLOSE_BRACKET = "]";
|
|
12
|
+
const OPEN_BRACE = "{";
|
|
13
|
+
const CLOSE_BRACE = "}";
|
|
14
|
+
const COMMA = ",";
|
|
15
|
+
/**
|
|
16
|
+
* Format a string of CSS using some simple rules
|
|
17
|
+
*/
|
|
18
|
+
function format(css, { minify = false, tab_size = void 0 } = Object.create(null)) {
|
|
19
|
+
if (tab_size !== void 0 && Number(tab_size) < 1) throw new TypeError("tab_size must be a number greater than 0");
|
|
20
|
+
const NEWLINE = minify ? EMPTY_STRING : "\n";
|
|
21
|
+
const OPTIONAL_SPACE = minify ? EMPTY_STRING : SPACE;
|
|
22
|
+
const LAST_SEMICOLON = minify ? EMPTY_STRING : SEMICOLON;
|
|
23
|
+
let comments = [];
|
|
24
|
+
let ast = parse(css, {
|
|
25
|
+
parse_atrule_preludes: false,
|
|
26
|
+
on_comment: minify ? void 0 : ({ start, end }) => {
|
|
27
|
+
comments.push(start, end);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
let depth = 0;
|
|
31
|
+
function indent(size) {
|
|
32
|
+
if (minify === true) return EMPTY_STRING;
|
|
33
|
+
if (tab_size !== void 0) return SPACE.repeat(tab_size * size);
|
|
34
|
+
return " ".repeat(size);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get and format comments from the CSS string within a range
|
|
38
|
+
* @param after After which offset to look for comments
|
|
39
|
+
* @param before Before which offset to look for comments
|
|
40
|
+
* @param level Indentation level (uses current depth if not specified)
|
|
41
|
+
* @returns The formatted comment string, or empty string if no comment found
|
|
42
|
+
*/
|
|
43
|
+
function get_comment(after, before, level = depth) {
|
|
44
|
+
if (minify || after === void 0 || before === void 0) return EMPTY_STRING;
|
|
45
|
+
let buffer = EMPTY_STRING;
|
|
46
|
+
for (let i = 0; i < comments.length; i += 2) {
|
|
47
|
+
let start = comments[i];
|
|
48
|
+
if (start === void 0 || start < after) continue;
|
|
49
|
+
let end = comments[i + 1];
|
|
50
|
+
if (end === void 0 || end > before) break;
|
|
51
|
+
if (buffer.length > 0) buffer += NEWLINE + indent(level);
|
|
52
|
+
buffer += css.slice(start, end);
|
|
53
|
+
}
|
|
54
|
+
return buffer;
|
|
55
|
+
}
|
|
56
|
+
function unquote(str) {
|
|
57
|
+
return str.replace(/(?:^['"])|(?:['"]$)/g, EMPTY_STRING);
|
|
58
|
+
}
|
|
59
|
+
function print_string(str) {
|
|
60
|
+
str = str?.toString() || "";
|
|
61
|
+
return QUOTE + unquote(str) + QUOTE;
|
|
62
|
+
}
|
|
63
|
+
function print_operator(node) {
|
|
64
|
+
let parts = [];
|
|
65
|
+
let operator = node.text;
|
|
66
|
+
let code = operator.charCodeAt(0);
|
|
67
|
+
if (code === 43 || code === 45) parts.push(SPACE);
|
|
68
|
+
else if (code !== 44) parts.push(OPTIONAL_SPACE);
|
|
69
|
+
parts.push(operator);
|
|
70
|
+
if (code === 43 || code === 45) parts.push(SPACE);
|
|
71
|
+
else parts.push(OPTIONAL_SPACE);
|
|
72
|
+
return parts.join(EMPTY_STRING);
|
|
73
|
+
}
|
|
74
|
+
function print_list(nodes) {
|
|
75
|
+
let parts = [];
|
|
76
|
+
for (let node of nodes) {
|
|
77
|
+
if (node.type === NODE_TYPES.FUNCTION) {
|
|
78
|
+
let fn = node.name?.toLowerCase();
|
|
79
|
+
parts.push(fn, OPEN_PARENTHESES);
|
|
80
|
+
parts.push(print_list(node.children));
|
|
81
|
+
parts.push(CLOSE_PARENTHESES);
|
|
82
|
+
} else if (node.type === NODE_TYPES.DIMENSION) parts.push(node.value, node.unit?.toLowerCase());
|
|
83
|
+
else if (node.type === NODE_TYPES.STRING) parts.push(print_string(node.text));
|
|
84
|
+
else if (node.type === NODE_TYPES.OPERATOR) parts.push(print_operator(node));
|
|
85
|
+
else if (node.type === NODE_TYPES.PARENTHESIS) parts.push(OPEN_PARENTHESES, print_list(node.children), CLOSE_PARENTHESES);
|
|
86
|
+
else if (node.type === NODE_TYPES.URL && typeof node.value === "string") {
|
|
87
|
+
parts.push("url(");
|
|
88
|
+
let { value } = node;
|
|
89
|
+
if (/^['"]?data:/i.test(value)) parts.push(unquote(value));
|
|
90
|
+
else parts.push(print_string(value));
|
|
91
|
+
parts.push(CLOSE_PARENTHESES);
|
|
92
|
+
} else parts.push(node.text);
|
|
93
|
+
if (node.type !== NODE_TYPES.OPERATOR) {
|
|
94
|
+
if (node.has_next) {
|
|
95
|
+
if (node.next_sibling?.type !== NODE_TYPES.OPERATOR) parts.push(SPACE);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return parts.join(EMPTY_STRING);
|
|
100
|
+
}
|
|
101
|
+
function print_value(nodes) {
|
|
102
|
+
if (nodes === null) return EMPTY_STRING;
|
|
103
|
+
return print_list(nodes);
|
|
104
|
+
}
|
|
105
|
+
function print_declaration(node) {
|
|
106
|
+
let important = [];
|
|
107
|
+
if (node.is_important) {
|
|
108
|
+
let text = node.text;
|
|
109
|
+
let has_semicolon = text.endsWith(SEMICOLON);
|
|
110
|
+
let start = text.lastIndexOf("!");
|
|
111
|
+
let end = has_semicolon ? -1 : void 0;
|
|
112
|
+
important.push(OPTIONAL_SPACE, text.slice(start, end).toLowerCase());
|
|
113
|
+
}
|
|
114
|
+
let value = print_value(node.value);
|
|
115
|
+
let property = node.property;
|
|
116
|
+
if (property === "font") value = value.replace(/\s*\/\s*/, "/");
|
|
117
|
+
if (value === EMPTY_STRING && minify === true) value += SPACE;
|
|
118
|
+
if (!property.startsWith("--")) property = property.toLowerCase();
|
|
119
|
+
return property + COLON + OPTIONAL_SPACE + value + important.join(EMPTY_STRING);
|
|
120
|
+
}
|
|
121
|
+
function print_nth(node) {
|
|
122
|
+
let parts = [];
|
|
123
|
+
let a = node.nth_a;
|
|
124
|
+
let b = node.nth_b;
|
|
125
|
+
if (a) parts.push(a);
|
|
126
|
+
if (a && b) parts.push(OPTIONAL_SPACE);
|
|
127
|
+
if (b) {
|
|
128
|
+
if (a && !b.startsWith("-")) parts.push("+", OPTIONAL_SPACE);
|
|
129
|
+
parts.push(parseFloat(b));
|
|
130
|
+
}
|
|
131
|
+
return parts.join(EMPTY_STRING);
|
|
132
|
+
}
|
|
133
|
+
function print_nth_of(node) {
|
|
134
|
+
let parts = [];
|
|
135
|
+
if (node.children[0]?.type === NODE_TYPES.NTH_SELECTOR) {
|
|
136
|
+
parts.push(print_nth(node.children[0]));
|
|
137
|
+
parts.push(SPACE, "of", SPACE);
|
|
138
|
+
}
|
|
139
|
+
if (node.children[1]?.type === NODE_TYPES.SELECTOR_LIST) parts.push(print_inline_selector_list(node.children[1]));
|
|
140
|
+
return parts.join(EMPTY_STRING);
|
|
141
|
+
}
|
|
142
|
+
function print_simple_selector(node, is_first = false) {
|
|
143
|
+
let name = node.name ?? "";
|
|
144
|
+
switch (node.type) {
|
|
145
|
+
case NODE_TYPES.TYPE_SELECTOR: return name.toLowerCase() ?? "";
|
|
146
|
+
case NODE_TYPES.COMBINATOR: {
|
|
147
|
+
let text = node.text;
|
|
148
|
+
if (/^\s+$/.test(text)) return SPACE;
|
|
149
|
+
return (is_first ? EMPTY_STRING : OPTIONAL_SPACE) + text + OPTIONAL_SPACE;
|
|
150
|
+
}
|
|
151
|
+
case NODE_TYPES.PSEUDO_ELEMENT_SELECTOR:
|
|
152
|
+
case NODE_TYPES.PSEUDO_CLASS_SELECTOR: {
|
|
153
|
+
let parts = [COLON];
|
|
154
|
+
name = name.toLowerCase();
|
|
155
|
+
if (name === "before" || name === "after" || node.type === NODE_TYPES.PSEUDO_ELEMENT_SELECTOR) parts.push(COLON);
|
|
156
|
+
parts.push(name);
|
|
157
|
+
if (node.has_children) {
|
|
158
|
+
parts.push(OPEN_PARENTHESES);
|
|
159
|
+
if (node.children.length > 0) if (name === "highlight") parts.push(print_list(node.children));
|
|
160
|
+
else parts.push(print_inline_selector_list(node));
|
|
161
|
+
parts.push(CLOSE_PARENTHESES);
|
|
162
|
+
}
|
|
163
|
+
return parts.join(EMPTY_STRING);
|
|
164
|
+
}
|
|
165
|
+
case NODE_TYPES.ATTRIBUTE_SELECTOR: {
|
|
166
|
+
let parts = [OPEN_BRACKET, name.toLowerCase()];
|
|
167
|
+
if (node.attr_operator) {
|
|
168
|
+
parts.push(ATTR_OPERATOR_NAMES[node.attr_operator] ?? "");
|
|
169
|
+
if (typeof node.value === "string") parts.push(print_string(node.value));
|
|
170
|
+
if (node.attr_flags) parts.push(SPACE, ATTR_FLAG_NAMES[node.attr_flags] ?? "");
|
|
171
|
+
}
|
|
172
|
+
parts.push(CLOSE_BRACKET);
|
|
173
|
+
return parts.join(EMPTY_STRING);
|
|
174
|
+
}
|
|
175
|
+
default: return node.text;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function print_selector(node) {
|
|
179
|
+
if (node.type === NODE_TYPES.NTH_SELECTOR) return print_nth(node);
|
|
180
|
+
if (node.type === NODE_TYPES.NTH_OF_SELECTOR) return print_nth_of(node);
|
|
181
|
+
if (node.type === NODE_TYPES.SELECTOR_LIST) return print_inline_selector_list(node);
|
|
182
|
+
if (node.type === NODE_TYPES.LANG_SELECTOR) return print_string(node.text);
|
|
183
|
+
let parts = [];
|
|
184
|
+
node.children.forEach((child, index) => {
|
|
185
|
+
const part = print_simple_selector(child, index === 0);
|
|
186
|
+
parts.push(part);
|
|
187
|
+
});
|
|
188
|
+
return parts.join(EMPTY_STRING);
|
|
189
|
+
}
|
|
190
|
+
function print_inline_selector_list(node) {
|
|
191
|
+
let parts = [];
|
|
192
|
+
for (let selector of node) {
|
|
193
|
+
parts.push(print_selector(selector));
|
|
194
|
+
if (selector.has_next) parts.push(COMMA, OPTIONAL_SPACE);
|
|
195
|
+
}
|
|
196
|
+
return parts.join(EMPTY_STRING);
|
|
197
|
+
}
|
|
198
|
+
function print_selector_list(node) {
|
|
199
|
+
let lines = [];
|
|
200
|
+
let prev_end;
|
|
201
|
+
for (let selector of node) {
|
|
202
|
+
if (prev_end !== void 0) {
|
|
203
|
+
let comment = get_comment(prev_end, selector.start);
|
|
204
|
+
if (comment) lines.push(indent(depth) + comment);
|
|
205
|
+
}
|
|
206
|
+
let printed = print_selector(selector);
|
|
207
|
+
if (selector.has_next) printed += COMMA;
|
|
208
|
+
lines.push(indent(depth) + printed);
|
|
209
|
+
prev_end = selector.end;
|
|
210
|
+
}
|
|
211
|
+
return lines.join(NEWLINE);
|
|
212
|
+
}
|
|
213
|
+
function print_block(node) {
|
|
214
|
+
let lines = [];
|
|
215
|
+
depth++;
|
|
216
|
+
let children = node.children;
|
|
217
|
+
if (children.length === 0) {
|
|
218
|
+
let comment = get_comment(node.start, node.end);
|
|
219
|
+
if (comment) {
|
|
220
|
+
lines.push(indent(depth) + comment);
|
|
221
|
+
depth--;
|
|
222
|
+
lines.push(indent(depth) + CLOSE_BRACE);
|
|
223
|
+
return lines.join(NEWLINE);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
let first_child = children[0];
|
|
227
|
+
let comment_before_first = get_comment(node.start, first_child?.start);
|
|
228
|
+
if (comment_before_first) lines.push(indent(depth) + comment_before_first);
|
|
229
|
+
let prev_end;
|
|
230
|
+
for (let child of children) {
|
|
231
|
+
if (prev_end !== void 0) {
|
|
232
|
+
let comment = get_comment(prev_end, child.start);
|
|
233
|
+
if (comment) lines.push(indent(depth) + comment);
|
|
234
|
+
}
|
|
235
|
+
let is_last = child.next_sibling?.type !== NODE_TYPES.DECLARATION;
|
|
236
|
+
if (child.type === NODE_TYPES.DECLARATION) {
|
|
237
|
+
let declaration = print_declaration(child);
|
|
238
|
+
let semi = is_last ? LAST_SEMICOLON : SEMICOLON;
|
|
239
|
+
lines.push(indent(depth) + declaration + semi);
|
|
240
|
+
} else if (child.type === NODE_TYPES.STYLE_RULE) {
|
|
241
|
+
if (prev_end !== void 0 && lines.length !== 0) lines.push(EMPTY_STRING);
|
|
242
|
+
lines.push(print_rule(child));
|
|
243
|
+
} else if (child.type === NODE_TYPES.AT_RULE) {
|
|
244
|
+
if (prev_end !== void 0 && lines.length !== 0) lines.push(EMPTY_STRING);
|
|
245
|
+
lines.push(indent(depth) + print_atrule(child));
|
|
246
|
+
}
|
|
247
|
+
prev_end = child.end;
|
|
248
|
+
}
|
|
249
|
+
let comment_after_last = get_comment(prev_end, node.end);
|
|
250
|
+
if (comment_after_last) lines.push(indent(depth) + comment_after_last);
|
|
251
|
+
depth--;
|
|
252
|
+
lines.push(indent(depth) + CLOSE_BRACE);
|
|
253
|
+
return lines.join(NEWLINE);
|
|
254
|
+
}
|
|
255
|
+
function print_rule(node) {
|
|
256
|
+
let lines = [];
|
|
257
|
+
if (node.first_child?.type === NODE_TYPES.SELECTOR_LIST) {
|
|
258
|
+
let list = print_selector_list(node.first_child);
|
|
259
|
+
let comment = get_comment(node.first_child.end, node.block?.start);
|
|
260
|
+
if (comment) list += NEWLINE + indent(depth) + comment;
|
|
261
|
+
list += OPTIONAL_SPACE + OPEN_BRACE;
|
|
262
|
+
if (!(node.block && (node.block.has_children || get_comment(node.block.start, node.block.end)))) list += CLOSE_BRACE;
|
|
263
|
+
lines.push(list);
|
|
264
|
+
}
|
|
265
|
+
if (node.block) {
|
|
266
|
+
if (node.block.has_children || get_comment(node.block.start, node.block.end)) lines.push(print_block(node.block));
|
|
267
|
+
}
|
|
268
|
+
return lines.join(NEWLINE);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Pretty-printing atrule preludes takes an insane amount of rules,
|
|
272
|
+
* so we're opting for a couple of 'good-enough' string replacements
|
|
273
|
+
* here to force some nice formatting.
|
|
274
|
+
* Should be OK perf-wise, since the amount of atrules in most
|
|
275
|
+
* stylesheets are limited, so this won't be called too often.
|
|
276
|
+
*/
|
|
277
|
+
function print_atrule_prelude(prelude) {
|
|
278
|
+
return prelude.replace(/\s*([:,])/g, prelude.toLowerCase().includes("selector(") ? "$1" : "$1 ").replace(/\)([a-zA-Z])/g, ") $1").replace(/\s*(=>|<=)\s*/g, " $1 ").replace(/([^<>=\s])([<>])([^<>=\s])/g, `$1${OPTIONAL_SPACE}$2${OPTIONAL_SPACE}$3`).replace(/\s+/g, OPTIONAL_SPACE).replace(/calc\(\s*([^()+\-*/]+)\s*([*/+-])\s*([^()+\-*/]+)\s*\)/g, (_, left, operator, right) => {
|
|
279
|
+
let space = operator === "+" || operator === "-" ? SPACE : OPTIONAL_SPACE;
|
|
280
|
+
return `calc(${left.trim()}${space}${operator}${space}${right.trim()})`;
|
|
281
|
+
}).replace(/selector|url|supports|layer\(/gi, (match) => match.toLowerCase());
|
|
282
|
+
}
|
|
283
|
+
function print_atrule(node) {
|
|
284
|
+
let lines = [];
|
|
285
|
+
let name = [`@`, node.name.toLowerCase()];
|
|
286
|
+
if (node.prelude) name.push(SPACE, print_atrule_prelude(node.prelude.text));
|
|
287
|
+
if (node.block === null) name.push(SEMICOLON);
|
|
288
|
+
else {
|
|
289
|
+
name.push(OPTIONAL_SPACE, OPEN_BRACE);
|
|
290
|
+
if (!(!node.block.is_empty || get_comment(node.block.start, node.block.end))) name.push(CLOSE_BRACE);
|
|
291
|
+
}
|
|
292
|
+
lines.push(name.join(EMPTY_STRING));
|
|
293
|
+
if (node.block !== null) {
|
|
294
|
+
if (!node.block.is_empty || get_comment(node.block.start, node.block.end)) lines.push(print_block(node.block));
|
|
295
|
+
}
|
|
296
|
+
return lines.join(NEWLINE);
|
|
297
|
+
}
|
|
298
|
+
function print_stylesheet(node) {
|
|
299
|
+
let lines = [];
|
|
300
|
+
let children = node.children;
|
|
301
|
+
if (children.length === 0) return get_comment(0, node.end, 0);
|
|
302
|
+
let first_child = children[0];
|
|
303
|
+
if (first_child) {
|
|
304
|
+
let comment_before_first = get_comment(0, first_child.start, 0);
|
|
305
|
+
if (comment_before_first) lines.push(comment_before_first);
|
|
306
|
+
}
|
|
307
|
+
let prev_end;
|
|
308
|
+
for (let child of node) {
|
|
309
|
+
if (prev_end !== void 0) {
|
|
310
|
+
let comment = get_comment(prev_end, child.start, 0);
|
|
311
|
+
if (comment) lines.push(comment);
|
|
312
|
+
}
|
|
313
|
+
if (child.type === NODE_TYPES.STYLE_RULE) lines.push(print_rule(child));
|
|
314
|
+
else if (child.type === NODE_TYPES.AT_RULE) lines.push(print_atrule(child));
|
|
315
|
+
prev_end = child.end;
|
|
316
|
+
if (child.has_next) {
|
|
317
|
+
if (!(child.next_sibling && get_comment(child.end, child.next_sibling.start, 0))) lines.push(EMPTY_STRING);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
let comment_after_last = get_comment(prev_end, node.end, 0);
|
|
321
|
+
if (comment_after_last) lines.push(comment_after_last);
|
|
322
|
+
return lines.join(NEWLINE);
|
|
323
|
+
}
|
|
324
|
+
return print_stylesheet(ast).trimEnd();
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Minify a string of CSS
|
|
328
|
+
* @param {string} css The original CSS
|
|
329
|
+
* @returns {string} The minified CSS
|
|
330
|
+
*/
|
|
331
|
+
function minify(css) {
|
|
332
|
+
return format(css, { minify: true });
|
|
333
|
+
}
|
|
334
|
+
//#endregion
|
|
335
|
+
export { format, minify };
|
package/package.json
CHANGED
|
@@ -1,65 +1,61 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@projectwallace/format-css",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Fast, small, zero-config library to format or minify CSS with basic rules.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"css",
|
|
7
|
+
"format",
|
|
8
|
+
"formatter",
|
|
9
|
+
"prettier",
|
|
10
|
+
"prettifier",
|
|
11
|
+
"pretty",
|
|
12
|
+
"print",
|
|
13
|
+
"style",
|
|
14
|
+
"stylesheet"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://github.com/projectwallace/format-css",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"author": "Bart Veneman <bart@projectwallace.com>",
|
|
5
19
|
"repository": {
|
|
6
20
|
"type": "git",
|
|
7
21
|
"url": "git+https://github.com/projectwallace/format-css.git"
|
|
8
22
|
},
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
"license": "MIT",
|
|
12
|
-
"author": "Bart Veneman <bart@projectwallace.com>",
|
|
13
|
-
"engines": {
|
|
14
|
-
"node": ">=18.0.0"
|
|
23
|
+
"bin": {
|
|
24
|
+
"format-css": "./dist/cli.mjs"
|
|
15
25
|
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
16
29
|
"type": "module",
|
|
17
|
-
"main": "./dist/
|
|
30
|
+
"main": "./dist/index.js",
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
18
32
|
"exports": {
|
|
19
33
|
"types": "./dist/index.d.ts",
|
|
20
|
-
"default": "./dist/
|
|
34
|
+
"default": "./dist/index.js"
|
|
21
35
|
},
|
|
22
|
-
"types": "./dist/index.d.ts",
|
|
23
36
|
"scripts": {
|
|
24
|
-
"build": "
|
|
37
|
+
"build": "tsdown",
|
|
25
38
|
"test": "vitest --coverage",
|
|
26
39
|
"check": "tsc",
|
|
27
40
|
"prettier": "prettier --check index.ts test/**/*.ts",
|
|
28
|
-
"lint": "oxlint"
|
|
29
|
-
|
|
41
|
+
"lint": "oxlint && oxfmt --check"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@projectwallace/css-parser": "^0.13.5"
|
|
30
45
|
},
|
|
31
46
|
"devDependencies": {
|
|
32
|
-
"@codecov/
|
|
47
|
+
"@codecov/rollup-plugin": "^1.9.1",
|
|
48
|
+
"@types/node": "^25.5.0",
|
|
33
49
|
"@vitest/coverage-v8": "^4.0.3",
|
|
34
|
-
"
|
|
50
|
+
"oxfmt": "^0.36.0",
|
|
35
51
|
"oxlint": "^1.24.0",
|
|
36
|
-
"prettier": "^3.6.2",
|
|
37
52
|
"publint": "^0.3.15",
|
|
53
|
+
"tsdown": "^0.21.0",
|
|
38
54
|
"typescript": "^5.9.3",
|
|
39
|
-
"vite": "^6.2.6",
|
|
40
|
-
"vite-plugin-dts": "^4.5.4",
|
|
41
55
|
"vitest": "^4.0.3"
|
|
42
56
|
},
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
],
|
|
46
|
-
"keywords": [
|
|
47
|
-
"css",
|
|
48
|
-
"stylesheet",
|
|
49
|
-
"formatter",
|
|
50
|
-
"format",
|
|
51
|
-
"print",
|
|
52
|
-
"prettifier",
|
|
53
|
-
"pretty",
|
|
54
|
-
"prettier"
|
|
55
|
-
],
|
|
56
|
-
"prettier": {
|
|
57
|
-
"semi": false,
|
|
58
|
-
"useTabs": true,
|
|
59
|
-
"printWidth": 140,
|
|
60
|
-
"singleQuote": true
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=20.12.0"
|
|
61
59
|
},
|
|
62
|
-
"
|
|
63
|
-
"@projectwallace/css-parser": "^0.13.5"
|
|
64
|
-
}
|
|
60
|
+
"issues": "https://github.com/projectwallace/format-css/issues"
|
|
65
61
|
}
|
package/dist/format-css.js
DELETED
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import { parse as V, NODE_TYPES as u, ATTR_OPERATOR_NAMES as X, ATTR_FLAG_NAMES as z } from "@projectwallace/css-parser";
|
|
2
|
-
const _ = " ", p = "", y = ":", A = ";", d = '"', v = "(", g = ")", tt = "[", et = "]", M = "{", N = "}", U = ",";
|
|
3
|
-
function rt(L, { minify: O = !1, tab_size: m = void 0 } = /* @__PURE__ */ Object.create(null)) {
|
|
4
|
-
if (m !== void 0 && Number(m) < 1)
|
|
5
|
-
throw new TypeError("tab_size must be a number greater than 0");
|
|
6
|
-
const E = O ? p : `
|
|
7
|
-
`, c = O ? p : _, D = O ? p : A;
|
|
8
|
-
let S = [], B = V(L, {
|
|
9
|
-
parse_atrule_preludes: !1,
|
|
10
|
-
on_comment: O ? void 0 : ({ start: t, end: e }) => {
|
|
11
|
-
S.push(t, e);
|
|
12
|
-
}
|
|
13
|
-
}), a = 0;
|
|
14
|
-
function o(t) {
|
|
15
|
-
return O === !0 ? p : m !== void 0 ? _.repeat(m * t) : " ".repeat(t);
|
|
16
|
-
}
|
|
17
|
-
function f(t, e, s = a) {
|
|
18
|
-
if (O || t === void 0 || e === void 0)
|
|
19
|
-
return p;
|
|
20
|
-
let r = p;
|
|
21
|
-
for (let i = 0; i < S.length; i += 2) {
|
|
22
|
-
let l = S[i];
|
|
23
|
-
if (l === void 0 || l < t) continue;
|
|
24
|
-
let n = S[i + 1];
|
|
25
|
-
if (n === void 0 || n > e) break;
|
|
26
|
-
r.length > 0 && (r += E + o(s)), r += L.slice(l, n);
|
|
27
|
-
}
|
|
28
|
-
return r;
|
|
29
|
-
}
|
|
30
|
-
function x(t) {
|
|
31
|
-
return t.replace(/(?:^['"])|(?:['"]$)/g, p);
|
|
32
|
-
}
|
|
33
|
-
function C(t) {
|
|
34
|
-
return t = (t == null ? void 0 : t.toString()) || "", d + x(t) + d;
|
|
35
|
-
}
|
|
36
|
-
function H(t) {
|
|
37
|
-
let e = [], s = t.text, r = s.charCodeAt(0);
|
|
38
|
-
return r === 43 || r === 45 ? e.push(_) : r !== 44 && e.push(c), e.push(s), r === 43 || r === 45 ? e.push(_) : e.push(c), e.join(p);
|
|
39
|
-
}
|
|
40
|
-
function b(t) {
|
|
41
|
-
var s, r, i;
|
|
42
|
-
let e = [];
|
|
43
|
-
for (let l of t) {
|
|
44
|
-
if (l.type === u.FUNCTION) {
|
|
45
|
-
let n = (s = l.name) == null ? void 0 : s.toLowerCase();
|
|
46
|
-
e.push(n, v), e.push(b(l.children)), e.push(g);
|
|
47
|
-
} else if (l.type === u.DIMENSION)
|
|
48
|
-
e.push(l.value, (r = l.unit) == null ? void 0 : r.toLowerCase());
|
|
49
|
-
else if (l.type === u.STRING)
|
|
50
|
-
e.push(C(l.text));
|
|
51
|
-
else if (l.type === u.OPERATOR)
|
|
52
|
-
e.push(H(l));
|
|
53
|
-
else if (l.type === u.PARENTHESIS)
|
|
54
|
-
e.push(v, b(l.children), g);
|
|
55
|
-
else if (l.type === u.URL && typeof l.value == "string") {
|
|
56
|
-
e.push("url(");
|
|
57
|
-
let { value: n } = l;
|
|
58
|
-
/^['"]?data:/i.test(n) ? e.push(x(n)) : e.push(C(n)), e.push(g);
|
|
59
|
-
} else
|
|
60
|
-
e.push(l.text);
|
|
61
|
-
l.type !== u.OPERATOR && l.has_next && ((i = l.next_sibling) == null ? void 0 : i.type) !== u.OPERATOR && e.push(_);
|
|
62
|
-
}
|
|
63
|
-
return e.join(p);
|
|
64
|
-
}
|
|
65
|
-
function Y(t) {
|
|
66
|
-
return t === null ? p : b(t);
|
|
67
|
-
}
|
|
68
|
-
function F(t) {
|
|
69
|
-
let e = [];
|
|
70
|
-
if (t.is_important) {
|
|
71
|
-
let i = t.text, l = i.endsWith(A), n = i.lastIndexOf("!"), T = l ? -1 : void 0;
|
|
72
|
-
e.push(c, i.slice(n, T).toLowerCase());
|
|
73
|
-
}
|
|
74
|
-
let s = Y(t.value), r = t.property;
|
|
75
|
-
return r === "font" && (s = s.replace(/\s*\/\s*/, "/")), s === p && O === !0 && (s += _), r.startsWith("--") || (r = r.toLowerCase()), r + y + c + s + e.join(p);
|
|
76
|
-
}
|
|
77
|
-
function P(t) {
|
|
78
|
-
let e = [], s = t.nth_a, r = t.nth_b;
|
|
79
|
-
return s && e.push(s), s && r && e.push(c), r && (s && !r.startsWith("-") && e.push("+", c), e.push(parseFloat(r))), e.join(p);
|
|
80
|
-
}
|
|
81
|
-
function G(t) {
|
|
82
|
-
var s, r;
|
|
83
|
-
let e = [];
|
|
84
|
-
return ((s = t.children[0]) == null ? void 0 : s.type) === u.NTH_SELECTOR && (e.push(P(t.children[0])), e.push(_, "of", _)), ((r = t.children[1]) == null ? void 0 : r.type) === u.SELECTOR_LIST && e.push(k(t.children[1])), e.join(p);
|
|
85
|
-
}
|
|
86
|
-
function W(t, e = !1) {
|
|
87
|
-
let s = t.name ?? "";
|
|
88
|
-
switch (t.type) {
|
|
89
|
-
case u.TYPE_SELECTOR:
|
|
90
|
-
return s.toLowerCase() ?? "";
|
|
91
|
-
case u.COMBINATOR: {
|
|
92
|
-
let r = t.text;
|
|
93
|
-
return /^\s+$/.test(r) ? _ : (e ? p : c) + r + c;
|
|
94
|
-
}
|
|
95
|
-
case u.PSEUDO_ELEMENT_SELECTOR:
|
|
96
|
-
case u.PSEUDO_CLASS_SELECTOR: {
|
|
97
|
-
let r = [y];
|
|
98
|
-
return s = s.toLowerCase(), (s === "before" || s === "after" || t.type === u.PSEUDO_ELEMENT_SELECTOR) && r.push(y), r.push(s), t.has_children && (r.push(v), t.children.length > 0 && (s === "highlight" ? r.push(b(t.children)) : r.push(k(t))), r.push(g)), r.join(p);
|
|
99
|
-
}
|
|
100
|
-
case u.ATTRIBUTE_SELECTOR: {
|
|
101
|
-
let r = [tt, s.toLowerCase()];
|
|
102
|
-
return t.attr_operator && (r.push(X[t.attr_operator] ?? ""), typeof t.value == "string" && r.push(C(t.value)), t.attr_flags && r.push(_, z[t.attr_flags] ?? "")), r.push(et), r.join(p);
|
|
103
|
-
}
|
|
104
|
-
default:
|
|
105
|
-
return t.text;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
function I(t) {
|
|
109
|
-
if (t.type === u.NTH_SELECTOR)
|
|
110
|
-
return P(t);
|
|
111
|
-
if (t.type === u.NTH_OF_SELECTOR)
|
|
112
|
-
return G(t);
|
|
113
|
-
if (t.type === u.SELECTOR_LIST)
|
|
114
|
-
return k(t);
|
|
115
|
-
if (t.type === u.LANG_SELECTOR)
|
|
116
|
-
return C(t.text);
|
|
117
|
-
let e = [];
|
|
118
|
-
return t.children.forEach((s, r) => {
|
|
119
|
-
const i = W(s, r === 0);
|
|
120
|
-
e.push(i);
|
|
121
|
-
}), e.join(p);
|
|
122
|
-
}
|
|
123
|
-
function k(t) {
|
|
124
|
-
let e = [];
|
|
125
|
-
for (let s of t)
|
|
126
|
-
e.push(I(s)), s.has_next && e.push(U, c);
|
|
127
|
-
return e.join(p);
|
|
128
|
-
}
|
|
129
|
-
function K(t) {
|
|
130
|
-
let e = [], s;
|
|
131
|
-
for (let r of t) {
|
|
132
|
-
if (s !== void 0) {
|
|
133
|
-
let l = f(s, r.start);
|
|
134
|
-
l && e.push(o(a) + l);
|
|
135
|
-
}
|
|
136
|
-
let i = I(r);
|
|
137
|
-
r.has_next && (i += U), e.push(o(a) + i), s = r.end;
|
|
138
|
-
}
|
|
139
|
-
return e.join(E);
|
|
140
|
-
}
|
|
141
|
-
function j(t) {
|
|
142
|
-
var T;
|
|
143
|
-
let e = [];
|
|
144
|
-
a++;
|
|
145
|
-
let s = t.children;
|
|
146
|
-
if (s.length === 0) {
|
|
147
|
-
let h = f(t.start, t.end);
|
|
148
|
-
if (h)
|
|
149
|
-
return e.push(o(a) + h), a--, e.push(o(a) + N), e.join(E);
|
|
150
|
-
}
|
|
151
|
-
let r = s[0], i = f(t.start, r == null ? void 0 : r.start);
|
|
152
|
-
i && e.push(o(a) + i);
|
|
153
|
-
let l;
|
|
154
|
-
for (let h of s) {
|
|
155
|
-
if (l !== void 0) {
|
|
156
|
-
let R = f(l, h.start);
|
|
157
|
-
R && e.push(o(a) + R);
|
|
158
|
-
}
|
|
159
|
-
let Z = ((T = h.next_sibling) == null ? void 0 : T.type) !== u.DECLARATION;
|
|
160
|
-
if (h.type === u.DECLARATION) {
|
|
161
|
-
let R = F(h), J = Z ? D : A;
|
|
162
|
-
e.push(o(a) + R + J);
|
|
163
|
-
} else h.type === u.STYLE_RULE ? (l !== void 0 && e.length !== 0 && e.push(p), e.push($(h))) : h.type === u.AT_RULE && (l !== void 0 && e.length !== 0 && e.push(p), e.push(o(a) + w(h)));
|
|
164
|
-
l = h.end;
|
|
165
|
-
}
|
|
166
|
-
let n = f(l, t.end);
|
|
167
|
-
return n && e.push(o(a) + n), a--, e.push(o(a) + N), e.join(E);
|
|
168
|
-
}
|
|
169
|
-
function $(t) {
|
|
170
|
-
var s, r;
|
|
171
|
-
let e = [];
|
|
172
|
-
if (((s = t.first_child) == null ? void 0 : s.type) === u.SELECTOR_LIST) {
|
|
173
|
-
let i = K(t.first_child), l = f(t.first_child.end, (r = t.block) == null ? void 0 : r.start);
|
|
174
|
-
l && (i += E + o(a) + l), i += c + M, t.block && (t.block.has_children || f(t.block.start, t.block.end)) || (i += N), e.push(i);
|
|
175
|
-
}
|
|
176
|
-
return t.block && (t.block.has_children || f(t.block.start, t.block.end)) && e.push(j(t.block)), e.join(E);
|
|
177
|
-
}
|
|
178
|
-
function q(t) {
|
|
179
|
-
return t.replace(/\s*([:,])/g, t.toLowerCase().includes("selector(") ? "$1" : "$1 ").replace(/\)([a-zA-Z])/g, ") $1").replace(/\s*(=>|<=)\s*/g, " $1 ").replace(/([^<>=\s])([<>])([^<>=\s])/g, `$1${c}$2${c}$3`).replace(/\s+/g, c).replace(/calc\(\s*([^()+\-*/]+)\s*([*/+-])\s*([^()+\-*/]+)\s*\)/g, (e, s, r, i) => {
|
|
180
|
-
let l = r === "+" || r === "-" ? _ : c;
|
|
181
|
-
return `calc(${s.trim()}${l}${r}${l}${i.trim()})`;
|
|
182
|
-
}).replace(/selector|url|supports|layer\(/gi, (e) => e.toLowerCase());
|
|
183
|
-
}
|
|
184
|
-
function w(t) {
|
|
185
|
-
let e = [], s = ["@", t.name.toLowerCase()];
|
|
186
|
-
return t.prelude && s.push(_, q(t.prelude.text)), t.block === null ? s.push(A) : (s.push(c, M), !t.block.is_empty || f(t.block.start, t.block.end) || s.push(N)), e.push(s.join(p)), t.block !== null && (!t.block.is_empty || f(t.block.start, t.block.end)) && e.push(j(t.block)), e.join(E);
|
|
187
|
-
}
|
|
188
|
-
function Q(t) {
|
|
189
|
-
let e = [], s = t.children;
|
|
190
|
-
if (s.length === 0)
|
|
191
|
-
return f(0, t.end, 0);
|
|
192
|
-
let r = s[0];
|
|
193
|
-
if (r) {
|
|
194
|
-
let n = f(0, r.start, 0);
|
|
195
|
-
n && e.push(n);
|
|
196
|
-
}
|
|
197
|
-
let i;
|
|
198
|
-
for (let n of t) {
|
|
199
|
-
if (i !== void 0) {
|
|
200
|
-
let T = f(i, n.start, 0);
|
|
201
|
-
T && e.push(T);
|
|
202
|
-
}
|
|
203
|
-
n.type === u.STYLE_RULE ? e.push($(n)) : n.type === u.AT_RULE && e.push(w(n)), i = n.end, n.has_next && (n.next_sibling && f(n.end, n.next_sibling.start, 0) || e.push(p));
|
|
204
|
-
}
|
|
205
|
-
let l = f(i, t.end, 0);
|
|
206
|
-
return l && e.push(l), e.join(E);
|
|
207
|
-
}
|
|
208
|
-
return Q(B).trimEnd();
|
|
209
|
-
}
|
|
210
|
-
function lt(L) {
|
|
211
|
-
return rt(L, { minify: !0 });
|
|
212
|
-
}
|
|
213
|
-
export {
|
|
214
|
-
rt as format,
|
|
215
|
-
lt as minify
|
|
216
|
-
};
|