1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
/**
* Script to get information on which selectors use the brand color.
* This is needed to provide the accent color feature - the feature will create CSS rules
* to overwrite the color of these selectors.
*/
const css = require('css');
const fs = require('fs-extra');
const path = require('path');
const theme = require('@meetfranz/theme');
// Colors that should be replaced with the accent color
const accentColors = [
theme.DEFAULT_ACCENT_COLOR.toLowerCase(),
'#7367f0',
'#5e50ee',
];
const cssFile = path.join(__dirname, '..', '..', 'build', 'styles', 'main.css');
const outputFile = path.join(__dirname, '..', 'assets', 'themeInfo.json');
// Parse and extract the rules from a CSS stylesheet file
async function getRulesFromCssFile(file) {
const cssSrc = (await fs.readFile(file)).toString();
const cssTree = css.parse(cssSrc);
return cssTree.stylesheet?.rules;
}
/**
* Get all selectors from a list of parsed CSS rules that set any property to one of the specified
* values.
*
* This function will output an object in this format:
* {
* 'property-name': [ array of selectors ]
* }
*
* e.g.
* {
* 'background-color': [
* '.background',
* '.input-dark'
* ]
* }
*
* @param {Array} rules Rules as outputted by the `css` module
* @param {Array} values Array of values that should be searched for
*/
function getSelectorsDeclaringValues(rules, values) {
const output = {};
for (const rule of rules) {
if (rule.declarations) {
for (const declaration of rule.declarations) {
if (
declaration.type === 'declaration' &&
values.includes(declaration.value.toLowerCase())
) {
if (!output[declaration.property]) {
output[declaration.property] = [];
}
// eslint-disable-next-line unicorn/prefer-spread
output[declaration.property] = output[declaration.property].concat(
rule.selectors,
);
}
}
}
}
return output;
}
async function generateThemeInfo() {
if (!(await fs.pathExists(cssFile))) {
console.log('Please make sure to build the project first.');
return;
}
// Read and parse css bundle
const rules = await getRulesFromCssFile(cssFile);
console.log(`Found ${rules?.length} rules`);
// Get rules specifying the brand colors
const brandRules = getSelectorsDeclaringValues(rules, accentColors);
console.log(
`Found ${Object.keys(brandRules).join(
', ',
)} properties that set color to brand color`,
);
// Join array of declarations into a single string
for (const rule of Object.keys(brandRules)) {
brandRules[rule] = brandRules[rule].join(', ');
}
// Write object with theme info to file
fs.writeFile(outputFile, JSON.stringify(brandRules));
}
generateThemeInfo();
|