-
Notifications
You must be signed in to change notification settings - Fork 16
/
index.js
109 lines (87 loc) · 2.5 KB
/
index.js
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
106
107
108
109
import { createMarkupForStyles } from './CSSPropertyOperations';
export function sortObject(obj) {
return Object.keys(obj)
.sort()
.reduce((acc, key) => {
const val = obj[key];
if (val || val === 0) acc[key] = val;
return acc;
}, {});
}
export function createHash(str) {
let i = str.length;
if (i === 0) return 0;
let hash = 5381;
while (i) hash = (hash * 33) ^ str.charCodeAt(--i);
return hash >>> 0;
}
export function stringifyObject(obj) {
const keys = Object.keys(obj);
let str = '';
for (let i = 0, len = keys.length; i < len; i++) {
str += keys[i] + obj[keys[i]];
}
return str;
}
const SYMBOL_SET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(
''
);
export function extendedToString(num, base) {
let conversion = '';
if (base > SYMBOL_SET.length || base <= 1 || !Number.isInteger(base))
throw new Error(
`${base} should be an integer between 1 and ${SYMBOL_SET.length}`
);
while (num >= 1) {
conversion = SYMBOL_SET[num - base * Math.floor(num / base)] + conversion;
num = Math.floor(num / base);
}
return base < 11 ? parseInt(conversion) : conversion;
}
export function createClassName(obj) {
const hash = extendedToString(createHash(stringifyObject(obj)), 62);
return hash ? '_' + hash : undefined;
}
export function createMarkup(obj) {
return createMarkupForStyles(obj);
}
export function isEmpty(obj) {
return !Object.keys(obj).length;
}
export function isPseudo({ style, rule }) {
return rule.charAt(0) === ':' && typeof style === 'object';
}
export function isMediaQuery({ style, rule }) {
return rule.charAt(0) === '@' && typeof style === 'object';
}
function handle(type, acc, { style, rule }, pseudos = []) {
const hash = createClassName(sortObject(style));
const rules = pseudos.length ? [[].concat(rule, style, pseudos)] : rule;
acc[type] = acc[type].concat(rules);
acc.style[rule] = hash;
return acc;
}
export function seperateStyles(styles) {
return Object.keys(styles).reduce(
(acc, rule) => {
const content = {
style: styles[rule],
rule
};
if (isPseudo(content)) {
return handle('pseudos', acc, content);
}
if (isMediaQuery(content)) {
const { style, pseudos } = seperateStyles(content.style);
return handle('mediaQueries', acc, { rule, style }, pseudos);
}
acc.style[rule] = content.style;
return acc;
},
{
style: {},
pseudos: [],
mediaQueries: []
}
);
}