UNPKG

3.53 kBJavaScriptView Raw
1'use strict';
2
3const t = require('babel-types');
4const generate = require('babel-generator').default;
5const vm = require('vm');
6const invariant = require('invariant');
7const getClassNameFromCache = require('../getClassNameFromCache');
8
9function extractStaticTernaries(ternaries, evalContext, cacheObject) {
10 invariant(
11 Array.isArray(ternaries),
12 'extractStaticTernaries expects param 1 to be an array of ternaries'
13 );
14 invariant(
15 typeof evalContext === 'object' && evalContext !== null,
16 'extractStaticTernaries expects param 2 to be an object'
17 );
18 invariant(
19 typeof cacheObject === 'object' && cacheObject !== null,
20 'extractStaticTernaries expects param 3 to be an object'
21 );
22
23 if (ternaries.length === 0) {
24 return null;
25 }
26
27 const ternariesByKey = {};
28 for (let idx = -1, len = ternaries.length; ++idx < len; ) {
29 const { name, ternary } = ternaries[idx];
30
31 const consequentValue = vm.runInContext(
32 generate(ternary.consequent).code,
33 evalContext
34 );
35 const alternateValue = vm.runInContext(
36 generate(ternary.alternate).code,
37 evalContext
38 );
39
40 const key = generate(ternary.test).code;
41 ternariesByKey[key] = ternariesByKey[key] || {
42 test: ternary.test,
43 consequentStyles: {},
44 alternateStyles: {},
45 };
46 ternariesByKey[key].consequentStyles[name] = consequentValue;
47 ternariesByKey[key].alternateStyles[name] = alternateValue;
48 }
49
50 const stylesByClassName = {};
51
52 const ternaryExpression = Object.keys(ternariesByKey)
53 .map((key, idx) => {
54 const { test, consequentStyles, alternateStyles } = ternariesByKey[key];
55 const consequentClassName =
56 getClassNameFromCache(consequentStyles, cacheObject) || '';
57 const alternateClassName =
58 getClassNameFromCache(alternateStyles, cacheObject) || '';
59
60 if (!consequentClassName && !alternateClassName) {
61 return null;
62 }
63
64 if (consequentClassName) {
65 stylesByClassName[consequentClassName] = consequentStyles;
66 }
67
68 if (alternateClassName) {
69 stylesByClassName[alternateClassName] = alternateStyles;
70 }
71
72 if (consequentClassName && alternateClassName) {
73 if (idx > 0) {
74 // if it's not the first ternary, add a leading space
75 return t.binaryExpression(
76 '+',
77 t.stringLiteral(' '),
78 t.conditionalExpression(
79 test,
80 t.stringLiteral(consequentClassName),
81 t.stringLiteral(alternateClassName)
82 )
83 );
84 } else {
85 return t.conditionalExpression(
86 test,
87 t.stringLiteral(consequentClassName),
88 t.stringLiteral(alternateClassName)
89 );
90 }
91 } else {
92 // if only one className is present, put the padding space inside the ternary
93 return t.conditionalExpression(
94 test,
95 t.stringLiteral(
96 (idx > 0 && consequentClassName ? ' ' : '') + consequentClassName
97 ),
98 t.stringLiteral(
99 (idx > 0 && alternateClassName ? ' ' : '') + alternateClassName
100 )
101 );
102 }
103 })
104 .filter(f => f)
105 .reduce(
106 (acc, val) => (acc ? t.binaryExpression('+', acc, val) : val),
107 null
108 );
109
110 if (!ternaryExpression) {
111 return null;
112 }
113
114 return {
115 // styles to be extracted
116 stylesByClassName,
117 // ternaries grouped into one binary expression
118 ternaryExpression,
119 };
120}
121
122module.exports = extractStaticTernaries;