@projectwallace/format-css 2.0.0 → 2.1.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 CHANGED
@@ -79,6 +79,18 @@ let minified = minify("a {}");
79
79
  let formatted_mini = format("a {}", { minify: true });
80
80
  ```
81
81
 
82
+ ## Tab size
83
+
84
+ 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
+
86
+ ```js
87
+ import { format } from "@projectwallace/format-css";
88
+
89
+ let formatted = format("a { color: red; }", {
90
+ tab_size: 2
91
+ });
92
+ ```
93
+
82
94
  ## Acknowledgements
83
95
 
84
96
  - Thanks to [CSSTree](https://github.com/csstree/csstree) for providing the necessary parser and the interfaces for our CSS Types (the **bold** elements in the list above)
@@ -1,83 +1,88 @@
1
- import h from "css-tree/parser";
2
- const o = " ", i = "", N = ":", x = ";", L = '"', I = "(", g = ")", d = "[", ee = "]", H = "{", V = "}", te = "{}", W = ",", Z = "Atrule", z = "Rule", F = "Block", G = "SelectorList", Y = "Selector", B = "Declaration", $ = "Operator";
3
- function b(_) {
4
- return /[A-Z]/.test(_) ? _.toLowerCase() : _;
1
+ import d from "css-tree/parser";
2
+ const a = " ", c = "", $ = ":", x = ";", g = '"', I = "(", v = ")", ee = "[", te = "]", V = "{", W = "}", re = "{}", Z = ",", j = "Atrule", F = "Rule", G = "Block", Q = "SelectorList", Y = "Selector", w = "Declaration", B = "Operator";
3
+ function C(y) {
4
+ return /[A-Z]/.test(y) ? y.toLowerCase() : y;
5
5
  }
6
- function re(_, { minify: P = !1 } = {}) {
7
- let O = [], v = h(_, {
6
+ function ne(y, {
7
+ minify: O = !1,
8
+ tab_size: T = void 0
9
+ } = /* @__PURE__ */ Object.create(null)) {
10
+ if (T !== void 0 && Number(T) < 1)
11
+ throw new TypeError("tab_size must be a number greater than 0");
12
+ let A = [], R = d(y, {
8
13
  positions: !0,
9
14
  parseAtrulePrelude: !1,
10
15
  parseCustomProperty: !0,
11
16
  parseValue: !0,
12
17
  onComment: (n, e) => {
13
- O.push(e.start.offset, e.end.offset);
18
+ A.push(e.start.offset, e.end.offset);
14
19
  }
15
20
  });
16
- const u = P ? i : `
17
- `, C = P ? i : o, Q = P ? i : x;
18
- let a = 0;
19
- function s(n) {
20
- return P ? i : " ".repeat(n);
21
+ const u = O ? c : `
22
+ `, p = O ? c : a, h = O ? c : x;
23
+ let s = 0;
24
+ function i(n) {
25
+ return O ? c : T ? a.repeat(T * n) : " ".repeat(n);
21
26
  }
22
- function A(n) {
27
+ function P(n) {
23
28
  let e = n.loc;
24
- return e ? _.slice(e.start.offset, e.end.offset) : i;
29
+ return e ? y.slice(e.start.offset, e.end.offset) : c;
25
30
  }
26
- function y(n) {
31
+ function b(n) {
27
32
  return /** @type {import('css-tree').CssLocation} */ n.loc.start.offset;
28
33
  }
29
- function c(n) {
34
+ function E(n) {
30
35
  return /** @type {import('css-tree').CssLocation} */ n.loc.end.offset;
31
36
  }
32
- function E(n, e) {
33
- if (P || n === void 0 || e === void 0)
34
- return i;
37
+ function m(n, e) {
38
+ if (O || n === void 0 || e === void 0)
39
+ return c;
35
40
  let t = "";
36
- for (let r = 0; r < O.length; r += 2) {
37
- let l = O[r];
41
+ for (let r = 0; r < A.length; r += 2) {
42
+ let l = A[r];
38
43
  if (l === void 0 || l < n) continue;
39
- let f = O[r + 1];
44
+ let f = A[r + 1];
40
45
  if (f === void 0 || f > e) break;
41
- t.length > 0 && (t += u + s(a)), t += _.slice(l, f);
46
+ t.length > 0 && (t += u + i(s)), t += y.slice(l, f);
42
47
  }
43
48
  return t;
44
49
  }
45
- function w(n) {
50
+ function M(n) {
46
51
  let e, t = n.prelude, r = n.block;
47
- t.type === G && (e = j(t));
48
- let l = E(c(t), y(r));
49
- return l && (e += u + s(a) + l), r.type === F && (e += M(r)), e;
52
+ t.type === Q && (e = q(t));
53
+ let l = m(E(t), b(r));
54
+ return l && (e += u + i(s) + l), r.type === G && (e += K(r)), e;
50
55
  }
51
- function j(n) {
52
- let e = i;
56
+ function q(n) {
57
+ let e = c;
53
58
  return n.children.forEach((t, r) => {
54
- t.type === Y && (e += s(a) + S(t)), r.next !== null && (e += W + u);
55
- let l = r.next !== null ? y(r.next.data) : c(n), f = E(c(t), l);
56
- f && (e += s(a) + f + u);
59
+ t.type === Y && (e += i(s) + S(t)), r.next !== null && (e += Z + u);
60
+ let l = r.next !== null ? b(r.next.data) : E(n), f = m(E(t), l);
61
+ f && (e += i(s) + f + u);
57
62
  }), e;
58
63
  }
59
64
  function S(n) {
60
- let e = i;
65
+ let e = c;
61
66
  return (n.children || []).forEach((r) => {
62
67
  switch (r.type) {
63
68
  case "TypeSelector": {
64
- e += b(r.name);
69
+ e += C(r.name);
65
70
  break;
66
71
  }
67
72
  case "Combinator": {
68
- e += o, r.name !== " " && (e += r.name + o);
73
+ e += a, r.name !== " " && (e += r.name + a);
69
74
  break;
70
75
  }
71
76
  case "PseudoClassSelector":
72
77
  case "PseudoElementSelector": {
73
- e += N;
74
- let l = b(r.name);
75
- (l === "before" || l === "after" || r.type === "PseudoElementSelector") && (e += N), e += l, r.children && (e += I + S(r) + g);
78
+ e += $;
79
+ let l = C(r.name);
80
+ (l === "before" || l === "after" || r.type === "PseudoElementSelector") && (e += $), e += l, r.children && (e += I + S(r) + v);
76
81
  break;
77
82
  }
78
- case G: {
83
+ case Q: {
79
84
  r.children.forEach((l, f) => {
80
- l.type === Y && (e += S(l)), f.next && f.next.data.type === Y && (e += W + C);
85
+ l.type === Y && (e += S(l)), f.next && f.next.data.type === Y && (e += Z + p);
81
86
  });
82
87
  break;
83
88
  }
@@ -85,101 +90,104 @@ function re(_, { minify: P = !1 } = {}) {
85
90
  let l = r.nth;
86
91
  if (l)
87
92
  if (l.type === "AnPlusB") {
88
- let f = l.a, p = l.b;
89
- f !== null && (e += f + "n"), f !== null && p !== null && (e += o), p !== null && (f !== null && !p.startsWith("-") && (e += "+" + o), e += p);
93
+ let f = l.a, o = l.b;
94
+ f !== null && (e += f + "n"), f !== null && o !== null && (e += a), o !== null && (f !== null && !o.startsWith("-") && (e += "+" + a), e += o);
90
95
  } else
91
- e += A(l);
92
- r.selector !== null && (e += o + "of" + o + S(r.selector));
96
+ e += P(l);
97
+ r.selector !== null && (e += a + "of" + a + S(r.selector));
93
98
  break;
94
99
  }
95
100
  case "AttributeSelector": {
96
- e += d, e += r.name.name, r.matcher && r.value && (e += r.matcher, e += L, r.value.type === "String" ? e += r.value.value : r.value.type === "Identifier" && (e += r.value.name), e += L), r.flags && (e += o + r.flags), e += ee;
101
+ e += ee, e += r.name.name, r.matcher && r.value && (e += r.matcher, e += g, r.value.type === "String" ? e += r.value.value : r.value.type === "Identifier" && (e += r.value.name), e += g), r.flags && (e += a + r.flags), e += te;
97
102
  break;
98
103
  }
99
104
  default: {
100
- e += A(r);
105
+ e += P(r);
101
106
  break;
102
107
  }
103
108
  }
104
109
  }), e;
105
110
  }
106
- function M(n) {
107
- let e = n.children, t = C;
111
+ function K(n) {
112
+ let e = n.children, t = p;
108
113
  if (e.isEmpty) {
109
- let f = E(y(n), c(n));
110
- return f ? (t += H + u, t += s(a + 1) + f, t += u + s(a) + V, t) : t + te;
114
+ let f = m(b(n), E(n));
115
+ return f ? (t += V + u, t += i(s + 1) + f, t += u + i(s) + W, t) : t + re;
111
116
  }
112
- t += H + u, a++;
113
- let r = E(y(n), y(
117
+ t += V + u, s++;
118
+ let r = m(b(n), b(
114
119
  /** @type {import('css-tree').CssNode} */
115
120
  e.first
116
121
  ));
117
- r && (t += s(a) + r + u), e.forEach((f, p) => {
118
- if (p.prev !== null) {
119
- let D = E(c(p.prev.data), y(f));
120
- D && (t += s(a) + D + u);
122
+ r && (t += i(s) + r + u), e.forEach((f, o) => {
123
+ if (o.prev !== null) {
124
+ let H = m(E(o.prev.data), b(f));
125
+ H && (t += i(s) + H + u);
121
126
  }
122
- f.type === B ? (t += J(f), p.next === null ? t += Q : t += x) : (p.prev !== null && p.prev.data.type === B && (t += u), f.type === z ? t += w(f) : f.type === Z ? t += K(f) : t += k(f, a)), p.next !== null && (t += u, f.type !== B && (t += u));
127
+ f.type === w ? (t += X(f), o.next === null ? t += h : t += x) : (o.prev !== null && o.prev.data.type === w && (t += u), f.type === F ? t += M(f) : f.type === j ? t += U(f) : t += N(f, s)), o.next !== null && (t += u, f.type !== w && (t += u));
123
128
  });
124
- let l = E(c(
129
+ let l = m(E(
125
130
  /** @type {import('css-tree').CssNode} */
126
131
  e.last
127
- ), c(n));
128
- return l && (t += u + s(a) + l), a--, t += u + s(a) + V, t;
132
+ ), E(n));
133
+ return l && (t += u + i(s) + l), s--, t += u + i(s) + W, t;
129
134
  }
130
- function K(n) {
131
- let e = s(a) + "@", t = n.prelude, r = n.block;
132
- return e += b(n.name), t !== null && (e += o + q(t)), r === null ? e += x : r.type === F && (e += M(r)), e;
133
- }
134
- function q(n) {
135
- let e = A(n);
136
- return e.replace(/\s*([:,])/g, e.toLowerCase().includes("selector(") ? "$1" : "$1 ").replace(/\s*(=>|<=)\s*/g, " $1 ").replace(/\)([a-zA-Z])/g, ") $1").replace(new RegExp("(?<!<=)(?<!=>)(?<!<= )([<>])(?![<= ])(?![=> ])(?![ =>])", "g"), " $1 ").replace(/calc\(([^*]*)\*([^*])/g, "calc($1 * $2").replace(/\s+/g, o).replace(/selector|url|supports|layer\(/ig, (t) => b(t));
135
+ function U(n) {
136
+ let e = i(s) + "@", t = n.prelude, r = n.block;
137
+ return e += C(n.name), t !== null && (e += a + J(t)), r === null ? e += x : r.type === G && (e += K(r)), e;
137
138
  }
138
139
  function J(n) {
140
+ let e = P(n);
141
+ return e.replace(/\s*([:,])/g, e.toLowerCase().includes("selector(") ? "$1" : "$1 ").replace(/\)([a-zA-Z])/g, ") $1").replace(/\s*(=>|<=)\s*/g, " $1 ").replace(/([^<>=\s])([<>])([^<>=\s])/g, `$1${p}$2${p}$3`).replace(/\s+/g, p).replace(/calc\(\s*([^()+\-*/]+)\s*([*/+-])\s*([^()+\-*/]+)\s*\)/g, (t, r, l, f) => {
142
+ let o = l === "+" || l === "-" ? a : p;
143
+ return `calc(${r.trim()}${o}${l}${o}${f.trim()})`;
144
+ }).replace(/selector|url|supports|layer\(/ig, (t) => C(t));
145
+ }
146
+ function X(n) {
139
147
  let e = n.property;
140
- e.charCodeAt(0) === 45 && e.charCodeAt(1) === 45 || (e = b(e));
141
- let t = U(n.value);
142
- return e === "font" && (t = t.replace(/\s*\/\s*/, "/")), t === i && P && (t += o), n.important === !0 ? t += C + "!important" : typeof n.important == "string" && (t += C + "!" + b(n.important)), s(a) + e + N + C + t;
148
+ e.charCodeAt(0) === 45 && e.charCodeAt(1) === 45 || (e = C(e));
149
+ let t = D(n.value);
150
+ return e === "font" && (t = t.replace(/\s*\/\s*/, "/")), t === c && O && (t += a), n.important === !0 ? t += p + "!important" : typeof n.important == "string" && (t += p + "!" + C(n.important)), i(s) + e + $ + p + t;
143
151
  }
144
- function R(n) {
145
- let e = i;
152
+ function k(n) {
153
+ let e = c;
146
154
  return n.forEach((t, r) => {
147
- t.type === "Identifier" ? e += t.name : t.type === "Function" ? e += b(t.name) + I + R(t.children) + g : t.type === "Dimension" ? e += t.value + b(t.unit) : t.type === "Value" ? e += U(t) : t.type === $ ? e += X(t) : t.type === "Parentheses" ? e += I + R(t.children) + g : t.type === "Url" ? e += "url(" + L + t.value + L + g : e += A(t), t.type !== $ && r.next !== null && r.next.data.type !== $ && (e += o);
155
+ t.type === "Identifier" ? e += t.name : t.type === "Function" ? e += C(t.name) + I + k(t.children) + v : t.type === "Dimension" ? e += t.value + C(t.unit) : t.type === "Value" ? e += D(t) : t.type === B ? e += z(t) : t.type === "Parentheses" ? e += I + k(t.children) + v : t.type === "Url" ? e += "url(" + g + t.value + g + v : e += P(t), t.type !== B && r.next !== null && r.next.data.type !== B && (e += a);
148
156
  }), e;
149
157
  }
150
- function X(n) {
151
- let e = i, t = n.value.trim(), r = t.charCodeAt(0);
152
- return r === 43 || r === 45 ? e += o : r !== 44 && (e += C), e += t, r === 43 || r === 45 ? e += o : e += C, e;
158
+ function z(n) {
159
+ let e = c, t = n.value.trim(), r = t.charCodeAt(0);
160
+ return r === 43 || r === 45 ? e += a : r !== 44 && (e += p), e += t, r === 43 || r === 45 ? e += a : e += p, e;
153
161
  }
154
- function U(n) {
155
- return n.type === "Raw" ? k(n, 0) : R(n.children);
156
- }
157
- function k(n, e) {
158
- return s(e) + A(n).trim();
159
- }
160
- let T = v.children, m = i;
161
- if (T.first) {
162
- let n = E(0, y(T.first));
163
- n && (m += n + u), T.forEach((t, r) => {
164
- if (t.type === z ? m += w(t) : t.type === Z ? m += K(t) : m += k(t, a), r.next !== null) {
165
- m += u;
166
- let l = E(c(t), y(r.next.data));
167
- l && (m += s(a) + l), m += u;
162
+ function D(n) {
163
+ return n.type === "Raw" ? N(n, 0) : k(n.children);
164
+ }
165
+ function N(n, e) {
166
+ return i(e) + P(n).trim();
167
+ }
168
+ let L = R.children, _ = c;
169
+ if (L.first) {
170
+ let n = m(0, b(L.first));
171
+ n && (_ += n + u), L.forEach((t, r) => {
172
+ if (t.type === F ? _ += M(t) : t.type === j ? _ += U(t) : _ += N(t, s), r.next !== null) {
173
+ _ += u;
174
+ let l = m(E(t), b(r.next.data));
175
+ l && (_ += i(s) + l), _ += u;
168
176
  }
169
177
  });
170
- let e = E(c(
178
+ let e = m(E(
171
179
  /** @type {import('css-tree').CssNode} */
172
- T.last
173
- ), c(v));
174
- e && (m += u + e);
180
+ L.last
181
+ ), E(R));
182
+ e && (_ += u + e);
175
183
  } else
176
- m += E(0, c(v));
177
- return m;
184
+ _ += m(0, E(R));
185
+ return _;
178
186
  }
179
- function le(_) {
180
- return re(_, { minify: !0 });
187
+ function fe(y) {
188
+ return ne(y, { minify: !0 });
181
189
  }
182
190
  export {
183
- re as format,
184
- le as minify
191
+ ne as format,
192
+ fe as minify
185
193
  };
package/dist/index.d.ts CHANGED
@@ -1,13 +1,14 @@
1
1
  /**
2
2
  * @typedef {Object} Options
3
3
  * @property {boolean} [minify] Whether to minify the CSS or keep it formatted
4
+ * @property {number} [tab_size] Tell the formatter to use N spaces instead of tabs
4
5
  *
5
6
  * Format a string of CSS using some simple rules
6
7
  * @param {string} css The original CSS
7
8
  * @param {Options} options
8
9
  * @returns {string} The formatted CSS
9
10
  */
10
- export function format(css: string, { minify }?: Options): string;
11
+ export function format(css: string, { minify, tab_size, }?: Options): string;
11
12
  /**
12
13
  * Minify a string of CSS
13
14
  * @param {string} css The original CSS
@@ -17,8 +18,12 @@ export function minify(css: string): string;
17
18
  export type Options = {
18
19
  /**
19
20
  * Whether to minify the CSS or keep it formatted
21
+ */
22
+ minify?: boolean | undefined;
23
+ /**
24
+ * Tell the formatter to use N spaces instead of tabs
20
25
  *
21
26
  * Format a string of CSS using some simple rules
22
27
  */
23
- minify?: boolean | undefined;
28
+ tab_size?: number | undefined;
24
29
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@projectwallace/format-css",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Fast, small, zero-config library to format or minify CSS with basic rules.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,16 +26,14 @@
26
26
  "prettier": "prettier --check index.js test/**/*.js"
27
27
  },
28
28
  "devDependencies": {
29
- "@codecov/vite-plugin": "^1.4.0",
30
- "@codspeed/tinybench-plugin": "^3.1.1",
31
- "@types/css-tree": "^2.3.9",
32
- "c8": "^10.1.2",
33
- "prettier": "^3.3.3",
34
- "tinybench": "^2.8.0",
35
- "typescript": "^5.6.3",
29
+ "@codecov/vite-plugin": "^1.9.0",
30
+ "@types/css-tree": "^2.3.10",
31
+ "c8": "^10.1.3",
32
+ "prettier": "^3.5.3",
33
+ "typescript": "^5.8.3",
36
34
  "uvu": "^0.5.6",
37
- "vite": "^5.4.11",
38
- "vite-plugin-dts": "^4.3.0"
35
+ "vite": "^6.2.6",
36
+ "vite-plugin-dts": "^4.5.3"
39
37
  },
40
38
  "dependencies": {
41
39
  "css-tree": "^3.0.1"