@projectwallace/css-design-tokens 0.10.0 → 0.11.1
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/dist/index.d.ts +101 -17
- package/dist/index.js +618 -0
- package/package.json +35 -27
- package/readme.md +223 -242
- package/dist/colors.d.ts +0 -2
- package/dist/css-design-tokens.js +0 -486
- package/dist/destructure-box-shadow.d.ts +0 -14
- package/dist/destructure-box-shadow.test.d.ts +0 -1
- package/dist/destructure-easing.d.ts +0 -2
- package/dist/destructure-easing.test.d.ts +0 -1
- package/dist/destructure-font-family.d.ts +0 -2
- package/dist/destructure-font-family.test.d.ts +0 -1
- package/dist/destructure-line-height.d.ts +0 -10
- package/dist/destructure-line-height.test.d.ts +0 -1
- package/dist/group-colors.d.ts +0 -4
- package/dist/hash.d.ts +0 -1
- package/dist/hash.test.d.ts +0 -1
- package/dist/index.test.d.ts +0 -1
- package/dist/parse-length.d.ts +0 -13
- package/dist/parse-length.test.d.ts +0 -1
- package/dist/types.d.ts +0 -70
- package/dist/unquote.d.ts +0 -1
- package/dist/unquote.test.d.ts +0 -1
package/dist/index.js
ADDED
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
import { analyze, colorFunctions, colorKeywords, cssKeywords, namedColors, systemColors } from "@projectwallace/css-analyzer";
|
|
2
|
+
import { convert } from "css-time-sort";
|
|
3
|
+
import { convert as convert$1 } from "color-sorter";
|
|
4
|
+
import { parse_value } from "@projectwallace/css-parser/parse-value";
|
|
5
|
+
import { A98RGB, A98RGB_Linear, ColorSpace, HSL, HSV, HWB, LCH, Lab, Lab_D65, OKLCH, OKLab, OKLrab, P3, P3_Linear, ProPhoto, ProPhoto_Linear, REC_2020, REC_2020_Linear, XYZ_ABS_D65, XYZ_D50, XYZ_D65, sRGB, sRGB_Linear, tryColor } from "colorjs.io/fn";
|
|
6
|
+
import { parse_value as parse_value$1 } from "@projectwallace/css-parser";
|
|
7
|
+
//#region src/group-colors.ts
|
|
8
|
+
const white = 0;
|
|
9
|
+
const black = 1;
|
|
10
|
+
const grey = 2;
|
|
11
|
+
const red = 3;
|
|
12
|
+
const orange = 4;
|
|
13
|
+
const yellow = 5;
|
|
14
|
+
const green = 6;
|
|
15
|
+
const cyan = 7;
|
|
16
|
+
const blue = 8;
|
|
17
|
+
const magenta = 9;
|
|
18
|
+
const pink = 10;
|
|
19
|
+
const unknown = 11;
|
|
20
|
+
const color_dict = new Map([
|
|
21
|
+
[white, "white"],
|
|
22
|
+
[black, "black"],
|
|
23
|
+
[grey, "grey"],
|
|
24
|
+
[red, "red"],
|
|
25
|
+
[orange, "orange"],
|
|
26
|
+
[yellow, "yellow"],
|
|
27
|
+
[green, "green"],
|
|
28
|
+
[cyan, "cyan"],
|
|
29
|
+
[blue, "blue"],
|
|
30
|
+
[magenta, "magenta"],
|
|
31
|
+
[pink, "pink"],
|
|
32
|
+
[unknown, "unknown"]
|
|
33
|
+
]);
|
|
34
|
+
function group_colors(colors) {
|
|
35
|
+
let color_groups = /* @__PURE__ */ new Map();
|
|
36
|
+
for (let color in colors) {
|
|
37
|
+
let group = unknown;
|
|
38
|
+
if (!color.includes("var(") && !color.includes("calc(")) {
|
|
39
|
+
let { hue, saturation, lightness } = convert$1(color);
|
|
40
|
+
if (saturation < 10 && lightness === 100) group = white;
|
|
41
|
+
else if (saturation < 10 && lightness === 0) group = black;
|
|
42
|
+
else if (saturation < 5) group = grey;
|
|
43
|
+
else if (hue < 22) group = red;
|
|
44
|
+
else if (hue < 50) group = orange;
|
|
45
|
+
else if (hue < 72) group = yellow;
|
|
46
|
+
else if (hue < 144) group = green;
|
|
47
|
+
else if (hue < 180) group = cyan;
|
|
48
|
+
else if (hue < 250) group = blue;
|
|
49
|
+
else if (hue < 300) group = magenta;
|
|
50
|
+
else if (hue < 350) group = pink;
|
|
51
|
+
else group = red;
|
|
52
|
+
}
|
|
53
|
+
if (color_groups.has(group)) color_groups.get(group).push(color);
|
|
54
|
+
else color_groups.set(group, [color]);
|
|
55
|
+
}
|
|
56
|
+
return Array.from(color_groups).sort((a, b) => a[0] === unknown || b[0] === unknown ? -1 : b[1].length - a[1].length);
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/types.ts
|
|
60
|
+
const EXTENSION_AUTHORED_AS = "com.projectwallace.css-authored-as";
|
|
61
|
+
const EXTENSION_USAGE_COUNT = "com.projectwallace.usage-count";
|
|
62
|
+
const EXTENSION_CSS_PROPERTIES = "com.projectwallace.css-properties";
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/colors.ts
|
|
65
|
+
ColorSpace.register(sRGB);
|
|
66
|
+
ColorSpace.register(XYZ_D65);
|
|
67
|
+
ColorSpace.register(XYZ_D50);
|
|
68
|
+
ColorSpace.register(XYZ_ABS_D65);
|
|
69
|
+
ColorSpace.register(Lab_D65);
|
|
70
|
+
ColorSpace.register(Lab);
|
|
71
|
+
ColorSpace.register(LCH);
|
|
72
|
+
ColorSpace.register(sRGB_Linear);
|
|
73
|
+
ColorSpace.register(HSL);
|
|
74
|
+
ColorSpace.register(HWB);
|
|
75
|
+
ColorSpace.register(HSV);
|
|
76
|
+
ColorSpace.register(P3_Linear);
|
|
77
|
+
ColorSpace.register(P3);
|
|
78
|
+
ColorSpace.register(A98RGB_Linear);
|
|
79
|
+
ColorSpace.register(A98RGB);
|
|
80
|
+
ColorSpace.register(ProPhoto_Linear);
|
|
81
|
+
ColorSpace.register(ProPhoto);
|
|
82
|
+
ColorSpace.register(REC_2020_Linear);
|
|
83
|
+
ColorSpace.register(REC_2020);
|
|
84
|
+
ColorSpace.register(OKLab);
|
|
85
|
+
ColorSpace.register(OKLCH);
|
|
86
|
+
ColorSpace.register(OKLrab);
|
|
87
|
+
function color_to_token(color) {
|
|
88
|
+
let lowercased = color.toLowerCase();
|
|
89
|
+
if (lowercased === "transparent") return {
|
|
90
|
+
colorSpace: "srgb",
|
|
91
|
+
components: [
|
|
92
|
+
0,
|
|
93
|
+
0,
|
|
94
|
+
0
|
|
95
|
+
],
|
|
96
|
+
alpha: 0
|
|
97
|
+
};
|
|
98
|
+
if (cssKeywords.has(lowercased) || colorKeywords.has(lowercased)) return null;
|
|
99
|
+
if (lowercased.includes("var(")) return null;
|
|
100
|
+
let parsed_color = tryColor(color);
|
|
101
|
+
if (parsed_color === null) return null;
|
|
102
|
+
let [component_a, component_b, component_c] = parsed_color.coords;
|
|
103
|
+
return {
|
|
104
|
+
colorSpace: parsed_color.space.id,
|
|
105
|
+
components: [
|
|
106
|
+
component_a ?? "none",
|
|
107
|
+
component_b ?? "none",
|
|
108
|
+
component_c ?? "none"
|
|
109
|
+
],
|
|
110
|
+
alpha: parsed_color.alpha ?? 1
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region src/destructure-box-shadow.ts
|
|
115
|
+
function create_destructured() {
|
|
116
|
+
return {
|
|
117
|
+
color: void 0,
|
|
118
|
+
offsetX: void 0,
|
|
119
|
+
offsetY: void 0,
|
|
120
|
+
blur: void 0,
|
|
121
|
+
spread: void 0,
|
|
122
|
+
inset: false
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function destructure_box_shadow(value) {
|
|
126
|
+
let ast = parse_value(value);
|
|
127
|
+
let current_shadow = create_destructured();
|
|
128
|
+
let destructured = [current_shadow];
|
|
129
|
+
if (ast.children.length < 2) return null;
|
|
130
|
+
for (let node of ast.children) if (node.type_name === "Identifier") {
|
|
131
|
+
if (node.name.toLowerCase() === "inset") current_shadow.inset = true;
|
|
132
|
+
else if (namedColors.has(node.name) || systemColors.has(node.name)) {
|
|
133
|
+
let color_token = color_to_token(node.name);
|
|
134
|
+
if (color_token === null) continue;
|
|
135
|
+
current_shadow.color = color_token;
|
|
136
|
+
}
|
|
137
|
+
} else if (node.type_name === "Dimension" || node.type_name === "Number" && node.value === 0) {
|
|
138
|
+
let length = node.type_name === "Dimension" ? {
|
|
139
|
+
value: Number(node.value),
|
|
140
|
+
unit: node.unit
|
|
141
|
+
} : {
|
|
142
|
+
value: 0,
|
|
143
|
+
unit: "px"
|
|
144
|
+
};
|
|
145
|
+
if (!current_shadow.offsetX) current_shadow.offsetX = length;
|
|
146
|
+
else if (!current_shadow.offsetY) current_shadow.offsetY = length;
|
|
147
|
+
else if (!current_shadow.blur) current_shadow.blur = length;
|
|
148
|
+
else if (!current_shadow.spread) current_shadow.spread = length;
|
|
149
|
+
} else if (node.type_name === "Function") {
|
|
150
|
+
if (colorFunctions.has(node.name)) {
|
|
151
|
+
let color_token = color_to_token(node.text);
|
|
152
|
+
if (color_token === null) continue;
|
|
153
|
+
current_shadow.color = color_token;
|
|
154
|
+
} else if (node.name?.toLowerCase() === "var" && !current_shadow.color) {
|
|
155
|
+
let color_token = color_to_token(node.text);
|
|
156
|
+
if (color_token === null) continue;
|
|
157
|
+
current_shadow.color = color_token;
|
|
158
|
+
}
|
|
159
|
+
} else if (node.type_name === "Hash") {
|
|
160
|
+
let color_token = color_to_token(node.text);
|
|
161
|
+
if (color_token === null) continue;
|
|
162
|
+
current_shadow.color = color_token;
|
|
163
|
+
} else if (node.type_name === "Operator" && node.value === ",") {
|
|
164
|
+
complete_shadow_token(current_shadow);
|
|
165
|
+
current_shadow = create_destructured();
|
|
166
|
+
destructured.push(current_shadow);
|
|
167
|
+
}
|
|
168
|
+
complete_shadow_token(current_shadow);
|
|
169
|
+
return destructured;
|
|
170
|
+
}
|
|
171
|
+
const DIMENSION_ZERO = {
|
|
172
|
+
value: 0,
|
|
173
|
+
unit: "px"
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* @description
|
|
177
|
+
* According to the spec every shadow MUST have an offsetX, offsetY, blur, spread and color,
|
|
178
|
+
* only the inset is optional and defaults to false.
|
|
179
|
+
*/
|
|
180
|
+
function complete_shadow_token(token) {
|
|
181
|
+
if (!token.offsetX) token.offsetX = DIMENSION_ZERO;
|
|
182
|
+
if (!token.offsetY) token.offsetY = DIMENSION_ZERO;
|
|
183
|
+
if (!token.blur) token.blur = DIMENSION_ZERO;
|
|
184
|
+
if (!token.spread) token.spread = DIMENSION_ZERO;
|
|
185
|
+
if (!token.color) token.color = color_to_token("#000");
|
|
186
|
+
return token;
|
|
187
|
+
}
|
|
188
|
+
//#endregion
|
|
189
|
+
//#region src/destructure-easing.ts
|
|
190
|
+
const EASING_KEYWORDS = new Map([
|
|
191
|
+
["linear", [
|
|
192
|
+
0,
|
|
193
|
+
0,
|
|
194
|
+
1,
|
|
195
|
+
1
|
|
196
|
+
]],
|
|
197
|
+
["ease", [
|
|
198
|
+
.25,
|
|
199
|
+
.1,
|
|
200
|
+
.25,
|
|
201
|
+
1
|
|
202
|
+
]],
|
|
203
|
+
["ease-in", [
|
|
204
|
+
.42,
|
|
205
|
+
0,
|
|
206
|
+
1,
|
|
207
|
+
1
|
|
208
|
+
]],
|
|
209
|
+
["ease-out", [
|
|
210
|
+
0,
|
|
211
|
+
0,
|
|
212
|
+
.58,
|
|
213
|
+
1
|
|
214
|
+
]],
|
|
215
|
+
["ease-in-out", [
|
|
216
|
+
.42,
|
|
217
|
+
0,
|
|
218
|
+
.58,
|
|
219
|
+
1
|
|
220
|
+
]]
|
|
221
|
+
]);
|
|
222
|
+
function destructure_easing(easing) {
|
|
223
|
+
easing = easing.trim().toLowerCase();
|
|
224
|
+
if (EASING_KEYWORDS.has(easing)) return EASING_KEYWORDS.get(easing);
|
|
225
|
+
if (easing.includes("var(")) return null;
|
|
226
|
+
if (easing.startsWith("cubic-bezier(")) {
|
|
227
|
+
let parts = easing.replace("cubic-bezier(", "").replace(")", "").split(",").map((v) => Number(v.trim()));
|
|
228
|
+
if (parts.length === 4 && parts.every((n) => Number.isFinite(n))) return parts;
|
|
229
|
+
}
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
//#endregion
|
|
233
|
+
//#region src/unquote.ts
|
|
234
|
+
function unquote(input) {
|
|
235
|
+
return input.replaceAll(/^['"]|['"]$/g, "");
|
|
236
|
+
}
|
|
237
|
+
//#endregion
|
|
238
|
+
//#region src/destructure-font-family.ts
|
|
239
|
+
function destructure_font_family(value) {
|
|
240
|
+
if (value.toLowerCase().includes("var(")) return;
|
|
241
|
+
let ast = parse_value(value);
|
|
242
|
+
let families = [];
|
|
243
|
+
let { children, has_children } = ast;
|
|
244
|
+
if (!has_children || children.length === 0) return families;
|
|
245
|
+
let family_buffer = "";
|
|
246
|
+
let prev_type;
|
|
247
|
+
for (let node of children) {
|
|
248
|
+
if (node.type_name === "Operator" && node.value === ",") {
|
|
249
|
+
families.push(unquote(family_buffer));
|
|
250
|
+
family_buffer = "";
|
|
251
|
+
prev_type = node.type_name;
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (prev_type === "Identifier" && node.type_name === "Identifier") family_buffer += " ";
|
|
255
|
+
family_buffer += node.text;
|
|
256
|
+
prev_type = node.type_name;
|
|
257
|
+
}
|
|
258
|
+
families.push(unquote(family_buffer));
|
|
259
|
+
return families;
|
|
260
|
+
}
|
|
261
|
+
//#endregion
|
|
262
|
+
//#region src/hash.ts
|
|
263
|
+
function hash(input) {
|
|
264
|
+
if (input === void 0) return "0";
|
|
265
|
+
if (typeof input === "number" && isNaN(input)) return "0";
|
|
266
|
+
if (typeof input !== "string") input = input.toString();
|
|
267
|
+
let hash = 0;
|
|
268
|
+
for (let char of input) {
|
|
269
|
+
hash = (hash << 5) - hash + char.charCodeAt(0);
|
|
270
|
+
hash |= 0;
|
|
271
|
+
}
|
|
272
|
+
return (hash >>> 0).toString(16);
|
|
273
|
+
}
|
|
274
|
+
//#endregion
|
|
275
|
+
//#region src/destructure-line-height.ts
|
|
276
|
+
const ALLOWED_UNITS = new Set(["px", "rem"]);
|
|
277
|
+
/**
|
|
278
|
+
* @description Destructure a line-height from a string
|
|
279
|
+
* The line-height property is specified as any one of the following:
|
|
280
|
+
* - a `<number>`
|
|
281
|
+
* - a `<length>`
|
|
282
|
+
* - a `<percentage>`
|
|
283
|
+
* - the keyword `normal`.
|
|
284
|
+
*/
|
|
285
|
+
function destructure_line_height(value) {
|
|
286
|
+
let ast = parse_value$1(value);
|
|
287
|
+
if (!ast.has_children) return null;
|
|
288
|
+
if (ast.children.length !== 1) return null;
|
|
289
|
+
let maybe_dimension = ast.first_child;
|
|
290
|
+
switch (maybe_dimension.type_name) {
|
|
291
|
+
case "Dimension": {
|
|
292
|
+
let { value, unit } = maybe_dimension;
|
|
293
|
+
if (value === 0) return 0;
|
|
294
|
+
if (unit === "%") return Number(value) / 100;
|
|
295
|
+
unit = unit.toLowerCase();
|
|
296
|
+
if (ALLOWED_UNITS.has(unit)) return {
|
|
297
|
+
value,
|
|
298
|
+
unit
|
|
299
|
+
};
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
case "Number": return Number(maybe_dimension.value);
|
|
303
|
+
case "Identifier": if (maybe_dimension.name?.toLowerCase() === "normal") return 1.2;
|
|
304
|
+
}
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
//#endregion
|
|
308
|
+
//#region src/parse-length.ts
|
|
309
|
+
let absolute_size_map = new Map([
|
|
310
|
+
["xx-small", .6],
|
|
311
|
+
["x-small", .75],
|
|
312
|
+
["small", .89],
|
|
313
|
+
["medium", 1],
|
|
314
|
+
["large", 1.2],
|
|
315
|
+
["x-large", 1.5],
|
|
316
|
+
["xx-large", 2],
|
|
317
|
+
["xxx-large", 3]
|
|
318
|
+
]);
|
|
319
|
+
/**
|
|
320
|
+
* @description Parse a length from a css value
|
|
321
|
+
* - a `<number>`
|
|
322
|
+
* - a `<length>`
|
|
323
|
+
* - a `<percentage>`
|
|
324
|
+
* - the keyword `normal`.
|
|
325
|
+
*/
|
|
326
|
+
function parse_length(value) {
|
|
327
|
+
let ast = parse_value$1(value);
|
|
328
|
+
if (!ast.has_children || ast.children.length !== 1) return null;
|
|
329
|
+
let maybe_length = ast.first_child;
|
|
330
|
+
switch (maybe_length.type_name) {
|
|
331
|
+
case "Dimension": {
|
|
332
|
+
let unit = maybe_length.unit.toLowerCase();
|
|
333
|
+
if (unit === "px" || unit === "rem") {
|
|
334
|
+
let value = Number(maybe_length.value);
|
|
335
|
+
if (value === 0) return {
|
|
336
|
+
value: 0,
|
|
337
|
+
unit: "px"
|
|
338
|
+
};
|
|
339
|
+
return {
|
|
340
|
+
value,
|
|
341
|
+
unit
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
case "Identifier": {
|
|
347
|
+
let name = maybe_length.name.toLowerCase();
|
|
348
|
+
if (absolute_size_map.has(name)) return {
|
|
349
|
+
value: absolute_size_map.get(name),
|
|
350
|
+
unit: "rem"
|
|
351
|
+
};
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
354
|
+
case "Number":
|
|
355
|
+
if (Number(maybe_length.value) === 0) return {
|
|
356
|
+
value: 0,
|
|
357
|
+
unit: "px"
|
|
358
|
+
};
|
|
359
|
+
break;
|
|
360
|
+
}
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
//#endregion
|
|
364
|
+
//#region src/index.ts
|
|
365
|
+
function css_to_tokens(css) {
|
|
366
|
+
return analysis_to_tokens(analyze(css));
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Function to get the unique values from a collection regardless of whether the analysis was run with
|
|
370
|
+
* locations enabled or not.
|
|
371
|
+
*/
|
|
372
|
+
function get_unique(collection) {
|
|
373
|
+
if ("uniqueWithLocations" in collection && collection.uniqueWithLocations != null) return collection.uniqueWithLocations;
|
|
374
|
+
return collection.unique;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Function to get the count of a specific value from a collection item regardless of whether the
|
|
378
|
+
* analysis was run with locations enabled or not.
|
|
379
|
+
*/
|
|
380
|
+
function get_count(collection_item) {
|
|
381
|
+
if (Array.isArray(collection_item)) return collection_item.length;
|
|
382
|
+
return collection_item;
|
|
383
|
+
}
|
|
384
|
+
function analysis_to_tokens(analysis) {
|
|
385
|
+
return {
|
|
386
|
+
color: (() => {
|
|
387
|
+
let colors = Object.create(null);
|
|
388
|
+
let unique = get_unique(analysis.values.colors);
|
|
389
|
+
let color_groups = group_colors(unique);
|
|
390
|
+
for (let [group, group_colors] of color_groups) for (let color of group_colors) {
|
|
391
|
+
let color_token = color_to_token(color);
|
|
392
|
+
let count = get_count(unique[color]);
|
|
393
|
+
if (color_token !== null) {
|
|
394
|
+
let { colorSpace, components, alpha } = color_token;
|
|
395
|
+
let name = `${color_dict.get(group)}-${hash([
|
|
396
|
+
colorSpace,
|
|
397
|
+
...components,
|
|
398
|
+
alpha
|
|
399
|
+
].join(""))}`;
|
|
400
|
+
let items_per_context = analysis.values.colors.itemsPerContext;
|
|
401
|
+
let new_properties = Object.entries(items_per_context).reduce((acc, [property, collection]) => {
|
|
402
|
+
if (color in collection.unique) return acc.add(property);
|
|
403
|
+
if (collection.uniqueWithLocations && color in collection.uniqueWithLocations) return acc.add(property);
|
|
404
|
+
return acc;
|
|
405
|
+
}, /* @__PURE__ */ new Set());
|
|
406
|
+
if (colors[name]) {
|
|
407
|
+
let old_properties = colors[name].$extensions[EXTENSION_CSS_PROPERTIES];
|
|
408
|
+
colors[name].$extensions[EXTENSION_CSS_PROPERTIES] = Array.from(new Set(old_properties).union(new_properties));
|
|
409
|
+
colors[name].$extensions[EXTENSION_USAGE_COUNT] += count;
|
|
410
|
+
} else colors[name] = {
|
|
411
|
+
$type: "color",
|
|
412
|
+
$value: color_token,
|
|
413
|
+
$extensions: {
|
|
414
|
+
[EXTENSION_AUTHORED_AS]: color,
|
|
415
|
+
[EXTENSION_USAGE_COUNT]: count,
|
|
416
|
+
[EXTENSION_CSS_PROPERTIES]: Array.from(new_properties)
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return colors;
|
|
422
|
+
})(),
|
|
423
|
+
font_size: (() => {
|
|
424
|
+
let font_sizes = Object.create(null);
|
|
425
|
+
let unique = get_unique(analysis.values.fontSizes);
|
|
426
|
+
for (let font_size in unique) {
|
|
427
|
+
let parsed = parse_length(font_size);
|
|
428
|
+
let extensions = {
|
|
429
|
+
[EXTENSION_AUTHORED_AS]: font_size,
|
|
430
|
+
[EXTENSION_USAGE_COUNT]: get_count(unique[font_size])
|
|
431
|
+
};
|
|
432
|
+
if (parsed === null) {
|
|
433
|
+
let name = `fontSize-${hash(font_size)}`;
|
|
434
|
+
font_sizes[name] = {
|
|
435
|
+
$value: font_size,
|
|
436
|
+
$extensions: extensions
|
|
437
|
+
};
|
|
438
|
+
} else {
|
|
439
|
+
let name = `fontSize-${hash(parsed.value.toString() + parsed.unit)}`;
|
|
440
|
+
if (font_sizes[name]) font_sizes[name].$extensions[EXTENSION_USAGE_COUNT] += extensions[EXTENSION_USAGE_COUNT];
|
|
441
|
+
else font_sizes[name] = {
|
|
442
|
+
$type: "dimension",
|
|
443
|
+
$value: parsed,
|
|
444
|
+
$extensions: extensions
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return font_sizes;
|
|
449
|
+
})(),
|
|
450
|
+
font_family: (() => {
|
|
451
|
+
let families = Object.create(null);
|
|
452
|
+
let unique = get_unique(analysis.values.fontFamilies);
|
|
453
|
+
for (let font_family in unique) {
|
|
454
|
+
let parsed = destructure_font_family(font_family);
|
|
455
|
+
let name = `fontFamily-${hash(font_family)}`;
|
|
456
|
+
let extensions = {
|
|
457
|
+
[EXTENSION_AUTHORED_AS]: font_family,
|
|
458
|
+
[EXTENSION_USAGE_COUNT]: get_count(unique[font_family])
|
|
459
|
+
};
|
|
460
|
+
if (parsed === void 0) families[name] = {
|
|
461
|
+
$value: font_family,
|
|
462
|
+
$extensions: extensions
|
|
463
|
+
};
|
|
464
|
+
else families[name] = {
|
|
465
|
+
$type: "fontFamily",
|
|
466
|
+
$value: parsed,
|
|
467
|
+
$extensions: extensions
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
return families;
|
|
471
|
+
})(),
|
|
472
|
+
line_height: (() => {
|
|
473
|
+
let line_heights = Object.create(null);
|
|
474
|
+
let unique = get_unique(analysis.values.lineHeights);
|
|
475
|
+
for (let line_height in unique) {
|
|
476
|
+
let parsed = destructure_line_height(line_height);
|
|
477
|
+
let extensions = {
|
|
478
|
+
[EXTENSION_AUTHORED_AS]: line_height,
|
|
479
|
+
[EXTENSION_USAGE_COUNT]: get_count(unique[line_height])
|
|
480
|
+
};
|
|
481
|
+
if (parsed === null) {
|
|
482
|
+
let name = `lineHeight-${hash(line_height)}`;
|
|
483
|
+
line_heights[name] = {
|
|
484
|
+
$value: line_height,
|
|
485
|
+
$extensions: extensions
|
|
486
|
+
};
|
|
487
|
+
} else if (typeof parsed === "number") {
|
|
488
|
+
let name = `lineHeight-${hash(parsed)}`;
|
|
489
|
+
if (line_heights[name]) line_heights[name].$extensions[EXTENSION_USAGE_COUNT] += extensions[EXTENSION_USAGE_COUNT];
|
|
490
|
+
else line_heights[name] = {
|
|
491
|
+
$type: "number",
|
|
492
|
+
$value: parsed,
|
|
493
|
+
$extensions: extensions
|
|
494
|
+
};
|
|
495
|
+
} else if (typeof parsed === "object") if (parsed.unit === "px" || parsed.unit === "rem") {
|
|
496
|
+
let name = `lineHeight-${hash(parsed.value.toString() + parsed.unit)}`;
|
|
497
|
+
if (line_heights[name]) line_heights[name].$extensions[EXTENSION_USAGE_COUNT] += extensions[EXTENSION_USAGE_COUNT];
|
|
498
|
+
else line_heights[name] = {
|
|
499
|
+
$type: "dimension",
|
|
500
|
+
$value: parsed,
|
|
501
|
+
$extensions: extensions
|
|
502
|
+
};
|
|
503
|
+
} else {
|
|
504
|
+
let name = `lineHeight-${hash(line_height)}`;
|
|
505
|
+
line_heights[name] = {
|
|
506
|
+
$value: line_height,
|
|
507
|
+
$extensions: extensions
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return line_heights;
|
|
512
|
+
})(),
|
|
513
|
+
gradient: (() => {
|
|
514
|
+
let gradients = Object.create(null);
|
|
515
|
+
let unique = get_unique(analysis.values.gradients);
|
|
516
|
+
for (let gradient in unique) gradients[`gradient-${hash(gradient)}`] = {
|
|
517
|
+
$value: gradient,
|
|
518
|
+
$extensions: {
|
|
519
|
+
[EXTENSION_AUTHORED_AS]: gradient,
|
|
520
|
+
[EXTENSION_USAGE_COUNT]: get_count(unique[gradient])
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
return gradients;
|
|
524
|
+
})(),
|
|
525
|
+
box_shadow: (() => {
|
|
526
|
+
let shadows = Object.create(null);
|
|
527
|
+
let unique = get_unique(analysis.values.boxShadows);
|
|
528
|
+
for (let box_shadow in unique) {
|
|
529
|
+
let name = `boxShadow-${hash(box_shadow)}`;
|
|
530
|
+
let parsed = destructure_box_shadow(box_shadow);
|
|
531
|
+
let extensions = {
|
|
532
|
+
[EXTENSION_AUTHORED_AS]: box_shadow,
|
|
533
|
+
[EXTENSION_USAGE_COUNT]: get_count(unique[box_shadow])
|
|
534
|
+
};
|
|
535
|
+
if (parsed === null) shadows[name] = {
|
|
536
|
+
$value: box_shadow,
|
|
537
|
+
$extensions: extensions
|
|
538
|
+
};
|
|
539
|
+
else shadows[name] = {
|
|
540
|
+
$type: "shadow",
|
|
541
|
+
$value: parsed.length === 1 ? parsed[0] : parsed,
|
|
542
|
+
$extensions: extensions
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
return shadows;
|
|
546
|
+
})(),
|
|
547
|
+
radius: (() => {
|
|
548
|
+
let radii = Object.create(null);
|
|
549
|
+
let unique = get_unique(analysis.values.borderRadiuses);
|
|
550
|
+
for (let radius in unique) {
|
|
551
|
+
let name = `radius-${hash(radius)}`;
|
|
552
|
+
radii[name] = {
|
|
553
|
+
$value: radius,
|
|
554
|
+
$extensions: {
|
|
555
|
+
[EXTENSION_AUTHORED_AS]: radius,
|
|
556
|
+
[EXTENSION_USAGE_COUNT]: get_count(unique[radius])
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
return radii;
|
|
561
|
+
})(),
|
|
562
|
+
duration: (() => {
|
|
563
|
+
let durations = Object.create(null);
|
|
564
|
+
let unique = get_unique(analysis.values.animations.durations);
|
|
565
|
+
for (let duration in unique) {
|
|
566
|
+
let parsed = convert(duration);
|
|
567
|
+
let is_valid = parsed < Number.MAX_SAFE_INTEGER - 1;
|
|
568
|
+
let extensions = {
|
|
569
|
+
[EXTENSION_AUTHORED_AS]: duration,
|
|
570
|
+
[EXTENSION_USAGE_COUNT]: get_count(unique[duration])
|
|
571
|
+
};
|
|
572
|
+
if (is_valid) {
|
|
573
|
+
let name = `duration-${hash(parsed.toString())}`;
|
|
574
|
+
if (durations[name]) durations[name].$extensions[EXTENSION_USAGE_COUNT] += extensions[EXTENSION_USAGE_COUNT];
|
|
575
|
+
else durations[name] = {
|
|
576
|
+
$type: "duration",
|
|
577
|
+
$value: {
|
|
578
|
+
value: parsed,
|
|
579
|
+
unit: "ms"
|
|
580
|
+
},
|
|
581
|
+
$extensions: extensions
|
|
582
|
+
};
|
|
583
|
+
} else {
|
|
584
|
+
let name = `duration-${hash("invalid" + parsed.toString())}`;
|
|
585
|
+
durations[name] = {
|
|
586
|
+
$value: duration,
|
|
587
|
+
$extensions: extensions
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return durations;
|
|
592
|
+
})(),
|
|
593
|
+
easing: (() => {
|
|
594
|
+
let easings = Object.create(null);
|
|
595
|
+
let unique = get_unique(analysis.values.animations.timingFunctions);
|
|
596
|
+
for (let easing in unique) {
|
|
597
|
+
let name = `easing-${hash(easing)}`;
|
|
598
|
+
let value = destructure_easing(easing);
|
|
599
|
+
let extensions = {
|
|
600
|
+
[EXTENSION_AUTHORED_AS]: easing,
|
|
601
|
+
[EXTENSION_USAGE_COUNT]: get_count(unique[easing])
|
|
602
|
+
};
|
|
603
|
+
if (value !== null) easings[name] = {
|
|
604
|
+
$value: value,
|
|
605
|
+
$type: "cubicBezier",
|
|
606
|
+
$extensions: extensions
|
|
607
|
+
};
|
|
608
|
+
else easings[name] = {
|
|
609
|
+
$value: easing,
|
|
610
|
+
$extensions: extensions
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
return easings;
|
|
614
|
+
})()
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
//#endregion
|
|
618
|
+
export { EXTENSION_AUTHORED_AS, EXTENSION_CSS_PROPERTIES, EXTENSION_USAGE_COUNT, analysis_to_tokens, color_to_token, css_to_tokens };
|
package/package.json
CHANGED
|
@@ -1,49 +1,57 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@projectwallace/css-design-tokens",
|
|
3
|
+
"version": "0.11.1",
|
|
3
4
|
"description": "Generate spec-compliant Design Tokens from CSS.",
|
|
4
|
-
"
|
|
5
|
+
"keywords": [
|
|
6
|
+
"color",
|
|
7
|
+
"css",
|
|
8
|
+
"design-tokens",
|
|
9
|
+
"font",
|
|
10
|
+
"spec",
|
|
11
|
+
"token"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/projectwallace/css-design-tokens",
|
|
5
14
|
"license": "EUPL-1.2",
|
|
6
15
|
"author": "Bart Veneman <bart@projectwallace.com>",
|
|
7
16
|
"repository": {
|
|
8
17
|
"type": "git",
|
|
9
18
|
"url": "git+https://github.com/projectwallace/css-design-tokens.git"
|
|
10
19
|
},
|
|
11
|
-
"homepage": "https://github.com/projectwallace/css-design-tokens",
|
|
12
|
-
"issues": "https://github.com/projectwallace/css-design-tokens/issues",
|
|
13
|
-
"keywords": [
|
|
14
|
-
"css",
|
|
15
|
-
"design-tokens",
|
|
16
|
-
"spec"
|
|
17
|
-
],
|
|
18
|
-
"type": "module",
|
|
19
20
|
"files": [
|
|
20
21
|
"dist"
|
|
21
22
|
],
|
|
22
|
-
"
|
|
23
|
+
"type": "module",
|
|
24
|
+
"main": "dist/index.js",
|
|
23
25
|
"types": "dist/index.d.ts",
|
|
24
26
|
"exports": {
|
|
25
27
|
"types": "./dist/index.d.ts",
|
|
26
|
-
"default": "./dist/
|
|
27
|
-
},
|
|
28
|
-
"engines": {
|
|
29
|
-
"node": ">=22"
|
|
28
|
+
"default": "./dist/index.js"
|
|
30
29
|
},
|
|
31
30
|
"scripts": {
|
|
32
|
-
"test": "vitest
|
|
33
|
-
"build": "
|
|
34
|
-
"check": "tsc --noEmit"
|
|
31
|
+
"test": "vitest --coverage",
|
|
32
|
+
"build": "tsdown",
|
|
33
|
+
"check": "tsc --noEmit",
|
|
34
|
+
"lint": "oxlint; oxfmt --check"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@projectwallace/css-analyzer": "^
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"css-
|
|
37
|
+
"@projectwallace/css-analyzer": "^9.3.0",
|
|
38
|
+
"@projectwallace/css-parser": "^0.13.5",
|
|
39
|
+
"color-sorter": "^7.0.1",
|
|
40
|
+
"colorjs.io": "^0.6.1",
|
|
41
|
+
"css-time-sort": "^3.0.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
|
|
44
|
+
"@codecov/rollup-plugin": "^1.9.1",
|
|
45
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
46
|
+
"oxfmt": "^0.36.0",
|
|
47
|
+
"oxlint": "^1.51.0",
|
|
48
|
+
"publint": "^0.3.18",
|
|
49
|
+
"tsdown": "^0.21.1",
|
|
50
|
+
"typescript": "^5.9.3",
|
|
51
|
+
"vitest": "^4.0.18"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=22"
|
|
55
|
+
},
|
|
56
|
+
"issues": "https://github.com/projectwallace/css-design-tokens/issues"
|
|
49
57
|
}
|