/
getCSS.ts
105 lines (91 loc) 路 2.99 KB
/
getCSS.ts
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
104
105
import {kashe} from 'kashe';
import {StyleDefinition, UsedTypes, UsedTypesRef} from "./types";
import {extractUnmatchable, fromAst, getUnmatchableRules} from "./parser/fromAst";
import {assertIsReady, getStylesInText} from "./utils";
export const getUnusableStyles = kashe((def: StyleDefinition): UsedTypesRef => (
Object
.keys(def.ast || {})
.filter(key => getUnmatchableRules(def.ast[key]).length > 0)
.reduce((acc, file) => {
acc[file] = true;
return acc;
}, {} as UsedTypesRef)
));
export const astToUsedStyles = kashe((styles: string[], def: StyleDefinition) => {
const {lookup, ast} = def;
const fetches: Record<string, Record<string, boolean>> = {};
const visitedStyles = new Set<string>();
styles.forEach(className => {
if (visitedStyles.has(className)) {
return;
}
visitedStyles.add(className);
const classes = className.split(' ');
classes.forEach(singleClass => {
const files = lookup[singleClass];
if (files) {
files.forEach(file => {
if (!fetches[file]) {
fetches[file] = {};
}
fetches[file][singleClass] = true
});
}
});
});
return {
fetches,
usage: Object.keys(ast).filter(file => !!fetches[file])
}
});
export const getUsedStyles = (str: string, def: StyleDefinition): UsedTypes => {
assertIsReady(def);
const {usage} = astToUsedStyles(getStylesInText(str), def);
const flags = {
...getUnusableStyles(def),
...usage.reduce((acc, file) => {
acc[file] = true;
return acc;
}, {})
};
return Object.keys(
Object
.keys(def.ast)
.reduce((acc, file) => {
if (flags[file]) {
acc[file] = true
}
return acc;
}, {})
);
};
export const astToStyles = kashe((styles: string[], def: StyleDefinition, filter?: (selector: string) => boolean): string => {
const {ast} = def;
const {fetches, usage} = astToUsedStyles(styles, def);
return (
usage
.map(file => fromAst(Object.keys(fetches[file]), ast[file], filter))
.join('\n')
);
});
export const wrapInStyle = (styles: string) => (
styles
? `<style type="text/css" data-used-styles="true">${styles}</style>`
: ''
);
export const extractAllUnmatchable = kashe((def: StyleDefinition) => (
Object
.keys(def.ast || {})
.reduce((acc, file) => acc + extractUnmatchable(def.ast[file]), '')
));
export const criticalStylesToString = (str: string, def: StyleDefinition, filter?: (selector: string) => boolean): string => {
assertIsReady(def);
return astToStyles(getStylesInText(str), def, filter);
};
export const getCriticalRules = (str: string, def: StyleDefinition, filter?: (selector: string) => boolean): string => {
assertIsReady(def);
return extractAllUnmatchable(def) + astToStyles(getStylesInText(str), def, filter);
};
export const getCriticalStyles = (str: string, def: StyleDefinition, filter?: (selector: string) => boolean): string => {
return wrapInStyle(getCriticalRules(str, def, filter));
};