Skip to content

Commit 8112e0b

Browse files
committed
generateGetColorOptionsTsCode
1 parent 7ee51ab commit 8112e0b

File tree

9 files changed

+273
-49
lines changed

9 files changed

+273
-49
lines changed

src/bin/generate_theme/parseColorOptions.ts renamed to src/bin/css_to_ts/colorOptions.ts

Lines changed: 98 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,46 +5,10 @@ import css from "css";
55
import { assert } from "tsafe/assert";
66
import { data_fr_theme } from "../sharedTypes";
77
import { exclude } from "tsafe/exclude";
8+
import { multiReplace } from "../tools/multiReplace";
9+
import * as crypto from "crypto";
810

9-
/*
10-
This type doesn't exist
11-
type ColorOptions = {
12-
blueFrance: {
13-
_975_75: {
14-
default: string;
15-
hover: string;
16-
active: string;
17-
}
18-
}
19-
20-
};
21-
22-
23-
export function getColorOptions(colorScheme: ColorScheme) {
24-
const isDark: boolean = (() => {
25-
switch (colorScheme) {
26-
case "dark":
27-
return true;
28-
case "light":
29-
return false;
30-
}
31-
})();
32-
33-
return {
34-
"blueFrance": {
35-
"_975_75": {
36-
"default": isDark ? "#44033" : "#303022",
37-
"hover": isDark ? "#433033" : "#33300",
38-
"active": isDark ? "#334343" : "#30333"
39-
}
40-
}
41-
} as const;
42-
}
43-
*/
44-
45-
/*
46-
https://www.systeme-de-design.gouv.fr/elements-d-interface/fondamentaux-identite-de-l-etat/couleurs-palette
47-
*/
11+
// https://www.systeme-de-design.gouv.fr/elements-d-interface/fondamentaux-identite-de-l-etat/couleurs-palette
4812

4913
export type Variant = "main" | "sun" | "moon";
5014

@@ -331,10 +295,9 @@ export function parseColorOptionName(colorOptionName: `--${string}`): ParsedColo
331295
}
332296
}
333297

334-
// YAGNI
335-
//export declare function stringifyColorOptionName(parsedColorOptionName: ParsedColorOptionName): `--${string}`
336-
337298
/**
299+
* Exported only for tests
300+
*
338301
* getThemePath(parseColorOptionName("--pink-macaron-sun-406-moon-833-hover"))
339302
* ->
340303
* ["pinkMacaron", "_sun_406_moon_833", "hover"]
@@ -363,6 +326,7 @@ export type ColorOption = {
363326
};
364327
};
365328

329+
/** Exported only for tests */
366330
export function parseColorOptions(rawCssCode: string): ColorOption[] {
367331
const parsedCss = css.parse(rawCssCode);
368332

@@ -425,3 +389,95 @@ export function parseColorOptions(rawCssCode: string): ColorOption[] {
425389
})
426390
.filter(exclude(undefined));
427391
}
392+
393+
export function generateGetColorOptionsTsCode(colorOptions: ColorOption[]) {
394+
const obj: any = {};
395+
396+
const keyValues: Record<string, string> = {};
397+
398+
colorOptions.forEach(colorOption => {
399+
const value = (() => {
400+
if (typeof colorOption.color === "string") {
401+
return colorOption.color;
402+
}
403+
404+
const hash = crypto
405+
.createHash("sha256")
406+
.update(colorOption.themePath.join(""))
407+
.digest("hex");
408+
409+
keyValues[
410+
`"${hash}"`
411+
] = `isDark ? "${colorOption.color.dark}" : "${colorOption.color.light}"`;
412+
413+
return hash;
414+
})();
415+
416+
function req(obj: any, path: string[]): void {
417+
const [propertyName, ...pathRest] = path;
418+
419+
if (pathRest.length === 0) {
420+
obj[propertyName] = value;
421+
return;
422+
}
423+
424+
if (obj[propertyName] === undefined) {
425+
obj[propertyName] = {};
426+
}
427+
428+
req(obj[propertyName], pathRest);
429+
}
430+
431+
req(obj, colorOption.themePath);
432+
});
433+
434+
Object.values(obj).forEach((obj: any) => {
435+
/*
436+
obj=
437+
{
438+
"sun113_625": {
439+
"default": isDark ? "#a00000" : "#00000d",
440+
"active": isDark ? "#b00000" : "#00000e"
441+
},
442+
"main525": {
443+
"default": "#00000f"
444+
}
445+
}
446+
*/
447+
448+
Object.entries(obj as any).forEach(([key, subObj]: any) => {
449+
//key = main525
450+
//subObj = { "default": "#00000f" }
451+
452+
const keys = Object.keys(subObj as any);
453+
454+
if (keys.length === 1 && keys[0] === "default") {
455+
obj[key] = subObj.default;
456+
}
457+
});
458+
});
459+
460+
return [
461+
`export function getColorOptions(colorScheme: ColorScheme) {`,
462+
` const isDark: boolean = (() => {`,
463+
` switch (colorScheme) {`,
464+
` case "dark": return true;`,
465+
` case "light": return false;`,
466+
` }`,
467+
` })();`,
468+
``,
469+
` return {`,
470+
multiReplace({
471+
"input": JSON.stringify(obj, null, 2),
472+
keyValues
473+
})
474+
.replace(/^{\n/, "")
475+
.replace(/\n}$/, "")
476+
.split("\n")
477+
.map(line => line.replace(/^[ ]{2}/, ""))
478+
.map(line => ` ${line}`)
479+
.join("\n"),
480+
` } as const;`,
481+
`}`
482+
].join("\n");
483+
}
File renamed without changes.

src/bin/tools/multiReplace.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import * as crypto from "crypto";
2+
3+
export function multiReplace(params: { input: string; keyValues: Record<string, string> }) {
4+
const { input, keyValues } = params;
5+
6+
let output = input;
7+
8+
const keyByHash = new Map<string, string>();
9+
10+
Object.keys(keyValues).forEach(key => {
11+
const hash = crypto.createHash("sha256").update(key).digest("hex");
12+
13+
const newOutput = output.replace(new RegExp(key, "g"), hash);
14+
15+
if (newOutput === output) {
16+
return;
17+
}
18+
19+
keyByHash.set(hash, key);
20+
21+
output = newOutput;
22+
});
23+
24+
Array.from(keyByHash.entries()).forEach(
25+
([hash, key]) => (output = output.replace(new RegExp(hash, "g"), keyValues[key]))
26+
);
27+
28+
return output;
29+
}
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import { generateGetColorOptionsTsCode } from "../../../bin/css_to_ts/colorOptions";
2+
import type { ColorOption } from "../../../bin/css_to_ts/colorOptions";
3+
import { assert } from "tsafe/assert";
4+
5+
console.log(`Running test ${__filename}`);
6+
7+
const input: ColorOption[] = [
8+
{
9+
"themePath": ["name1Name2", "_111", "default"],
10+
"color": "#000000"
11+
},
12+
{
13+
"themePath": ["name1Name2", "_111", "hover"],
14+
"color": "#000001"
15+
},
16+
{
17+
"themePath": ["name1Name2", "sun111", "default"],
18+
"color": "#000002"
19+
},
20+
{
21+
"themePath": ["name1Name2", "sun111", "hover"],
22+
"color": "#000003"
23+
},
24+
{
25+
"themePath": ["name1Name2", "_111_222", "default"],
26+
"color": { "light": "#000004", "dark": "#100000" }
27+
},
28+
{
29+
"themePath": ["name1Name2", "_111_222", "hover"],
30+
"color": { "light": "#000005", "dark": "#200000" }
31+
},
32+
{
33+
"themePath": ["name1Name2", "sun111_222", "default"],
34+
"color": { "light": "#000006", "dark": "#300000" }
35+
},
36+
{
37+
"themePath": ["name1Name2", "sun111_222", "hover"],
38+
"color": { "light": "#000007", "dark": "#400000" }
39+
},
40+
{
41+
"themePath": ["name1Name2", "_111moon222", "default"],
42+
"color": { "light": "#000008", "dark": "#500000" }
43+
},
44+
{
45+
"themePath": ["name1Name2", "_111moon222", "hover"],
46+
"color": { "light": "#000009", "dark": "#600000" }
47+
},
48+
{
49+
"themePath": ["name1Name2", "sun111moon222", "default"],
50+
"color": { "light": "#00000a", "dark": "#700000" }
51+
},
52+
{
53+
"themePath": ["name1Name2", "sun111moon222", "hover"],
54+
"color": { "light": "#00000b", "dark": "#800000" }
55+
},
56+
{
57+
"themePath": ["grey", "_1000_50", "hover"],
58+
"color": { "light": "#00000c", "dark": "#900000" }
59+
},
60+
{
61+
"themePath": ["blueFrance", "sun113_625", "default"],
62+
"color": { "light": "#00000d", "dark": "#a00000" }
63+
},
64+
{
65+
"themePath": ["blueFrance", "sun113_625", "active"],
66+
"color": { "light": "#00000e", "dark": "#b00000" }
67+
},
68+
{
69+
"themePath": ["blueFrance", "main525", "default"],
70+
"color": "#00000f"
71+
},
72+
{
73+
"themePath": ["purpleGlycine", "sun319moon630", "hover"],
74+
"color": { "light": "#000010", "dark": "#c00000" }
75+
}
76+
];
77+
78+
const expected = `
79+
export function getColorOptions(colorScheme: ColorScheme) {
80+
const isDark: boolean = (() => {
81+
switch (colorScheme) {
82+
case "dark": return true;
83+
case "light": return false;
84+
}
85+
})();
86+
87+
return {
88+
"name1Name2": {
89+
"_111": {
90+
"default": "#000000",
91+
"hover": "#000001"
92+
},
93+
"sun111": {
94+
"default": "#000002",
95+
"hover": "#000003"
96+
},
97+
"_111_222": {
98+
"default": isDark ? "#100000" : "#000004",
99+
"hover": isDark ? "#200000" : "#000005"
100+
},
101+
"sun111_222": {
102+
"default": isDark ? "#300000" : "#000006",
103+
"hover": isDark ? "#400000" : "#000007"
104+
},
105+
"_111moon222": {
106+
"default": isDark ? "#500000" : "#000008",
107+
"hover": isDark ? "#600000" : "#000009"
108+
},
109+
"sun111moon222": {
110+
"default": isDark ? "#700000" : "#00000a",
111+
"hover": isDark ? "#800000" : "#00000b"
112+
}
113+
},
114+
"grey": {
115+
"_1000_50": {
116+
"hover": isDark ? "#900000" : "#00000c"
117+
}
118+
},
119+
"blueFrance": {
120+
"sun113_625": {
121+
"default": isDark ? "#a00000" : "#00000d",
122+
"active": isDark ? "#b00000" : "#00000e"
123+
},
124+
"main525": "#00000f"
125+
},
126+
"purpleGlycine": {
127+
"sun319moon630": {
128+
"hover": isDark ? "#c00000" : "#000010"
129+
}
130+
}
131+
} as const;
132+
}`.replace(/^\n/, "");
133+
134+
const got = generateGetColorOptionsTsCode(input);
135+
136+
assert(got === expected);
137+
138+
console.log("PASS");

src/test/bin/parseColorOptions/getThemePath.test.ts renamed to src/test/bin/colorOptions/getThemePath.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { getThemePath } from "../../../bin/generate_theme/parseColorOptions";
2-
import type { ParsedColorOptionName } from "../../../bin/generate_theme/parseColorOptions";
1+
import { getThemePath } from "../../../bin/css_to_ts/colorOptions";
2+
import type { ParsedColorOptionName } from "../../../bin/css_to_ts/colorOptions";
33
import { same } from "evt/tools/inDepth/same";
44
import { assert } from "tsafe/assert";
55

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import "./parseColorOptionName.test";
22
import "./getThemePath.test";
33
import "./parseColorOptions.test";
4+
import "./generateGetColorOptionsTsCode.test";

src/test/bin/parseColorOptions/parseColorOptionName.test.ts renamed to src/test/bin/colorOptions/parseColorOptionName.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { parseColorOptionName } from "../../../bin/generate_theme/parseColorOptions";
2-
import type { ParsedColorOptionName } from "../../../bin/generate_theme/parseColorOptions";
1+
import { parseColorOptionName } from "../../../bin/css_to_ts/colorOptions";
2+
import type { ParsedColorOptionName } from "../../../bin/css_to_ts/colorOptions";
33
import { same } from "evt/tools/inDepth/same";
44
import { assert } from "tsafe/assert";
55

src/test/bin/parseColorOptions/parseColorOptions.test.ts renamed to src/test/bin/colorOptions/parseColorOptions.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { parseColorOptions } from "../../../bin/generate_theme/parseColorOptions";
2-
import type { ColorOption } from "../../../bin/generate_theme/parseColorOptions";
1+
import { parseColorOptions } from "../../../bin/css_to_ts/colorOptions";
2+
import type { ColorOption } from "../../../bin/css_to_ts/colorOptions";
33
import { same } from "evt/tools/inDepth/same";
44
import { assert } from "tsafe/assert";
55

src/test/bin/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
import "./parseColorOptions";
1+
import "./colorOptions";

0 commit comments

Comments
 (0)