@workday/canvas-kit-styling-transform 13.2.0 → 13.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/dist/commonjs/index.d.ts +14 -0
  2. package/dist/commonjs/index.d.ts.map +1 -0
  3. package/dist/commonjs/index.js +28 -0
  4. package/dist/commonjs/lib/createObjectTransform.d.ts +10 -0
  5. package/dist/commonjs/lib/createObjectTransform.d.ts.map +1 -0
  6. package/dist/commonjs/lib/createObjectTransform.js +14 -0
  7. package/dist/commonjs/lib/createPropertyTransform.d.ts +7 -0
  8. package/dist/commonjs/lib/createPropertyTransform.d.ts.map +1 -0
  9. package/dist/commonjs/lib/createPropertyTransform.js +11 -0
  10. package/dist/commonjs/lib/createTypeScriptWatchProgram.d.ts +16 -0
  11. package/dist/commonjs/lib/createTypeScriptWatchProgram.d.ts.map +1 -0
  12. package/dist/commonjs/lib/createTypeScriptWatchProgram.js +45 -0
  13. package/dist/commonjs/lib/styleTransform.d.ts +23 -0
  14. package/dist/commonjs/lib/styleTransform.d.ts.map +1 -0
  15. package/dist/commonjs/lib/styleTransform.js +131 -0
  16. package/dist/commonjs/lib/utils/createStyleObjectNode.d.ts +35 -0
  17. package/dist/commonjs/lib/utils/createStyleObjectNode.d.ts.map +1 -0
  18. package/dist/commonjs/lib/utils/createStyleObjectNode.js +84 -0
  19. package/dist/commonjs/lib/utils/getCssVariables.d.ts +4 -0
  20. package/dist/commonjs/lib/utils/getCssVariables.d.ts.map +1 -0
  21. package/dist/commonjs/lib/utils/getCssVariables.js +31 -0
  22. package/dist/commonjs/lib/utils/getErrorMessage.d.ts +16 -0
  23. package/dist/commonjs/lib/utils/getErrorMessage.d.ts.map +1 -0
  24. package/dist/commonjs/lib/utils/getErrorMessage.js +45 -0
  25. package/dist/commonjs/lib/utils/getFallbackVariable.d.ts +9 -0
  26. package/dist/commonjs/lib/utils/getFallbackVariable.d.ts.map +1 -0
  27. package/dist/commonjs/lib/utils/getFallbackVariable.js +30 -0
  28. package/dist/commonjs/lib/utils/getHash.d.ts +4 -0
  29. package/dist/commonjs/lib/utils/getHash.d.ts.map +1 -0
  30. package/dist/commonjs/lib/utils/getHash.js +16 -0
  31. package/dist/commonjs/lib/utils/getVarName.d.ts +17 -0
  32. package/dist/commonjs/lib/utils/getVarName.d.ts.map +1 -0
  33. package/dist/commonjs/lib/utils/getVarName.js +34 -0
  34. package/dist/commonjs/lib/utils/handleCalc.d.ts +2 -0
  35. package/dist/commonjs/lib/utils/handleCalc.d.ts.map +1 -0
  36. package/dist/commonjs/lib/utils/handleCalc.js +33 -0
  37. package/dist/commonjs/lib/utils/handleCreateStencil.d.ts +7 -0
  38. package/dist/commonjs/lib/utils/handleCreateStencil.d.ts.map +1 -0
  39. package/dist/commonjs/lib/utils/handleCreateStencil.js +309 -0
  40. package/dist/commonjs/lib/utils/handleCreateStyles.d.ts +3 -0
  41. package/dist/commonjs/lib/utils/handleCreateStyles.d.ts.map +1 -0
  42. package/dist/commonjs/lib/utils/handleCreateStyles.js +86 -0
  43. package/dist/commonjs/lib/utils/handleCreateVars.d.ts +3 -0
  44. package/dist/commonjs/lib/utils/handleCreateVars.d.ts.map +1 -0
  45. package/dist/commonjs/lib/utils/handleCreateVars.js +65 -0
  46. package/dist/commonjs/lib/utils/handleCssVar.d.ts +2 -0
  47. package/dist/commonjs/lib/utils/handleCssVar.d.ts.map +1 -0
  48. package/dist/commonjs/lib/utils/handleCssVar.js +19 -0
  49. package/dist/commonjs/lib/utils/handleInjectGlobal.d.ts +3 -0
  50. package/dist/commonjs/lib/utils/handleInjectGlobal.d.ts.map +1 -0
  51. package/dist/commonjs/lib/utils/handleInjectGlobal.js +40 -0
  52. package/dist/commonjs/lib/utils/handleKeyframes.d.ts +3 -0
  53. package/dist/commonjs/lib/utils/handleKeyframes.d.ts.map +1 -0
  54. package/dist/commonjs/lib/utils/handleKeyframes.js +48 -0
  55. package/dist/commonjs/lib/utils/handleParentModifier.d.ts +2 -0
  56. package/dist/commonjs/lib/utils/handleParentModifier.d.ts.map +1 -0
  57. package/dist/commonjs/lib/utils/handleParentModifier.js +26 -0
  58. package/dist/commonjs/lib/utils/handlePx2Rem.d.ts +2 -0
  59. package/dist/commonjs/lib/utils/handlePx2Rem.d.ts.map +1 -0
  60. package/dist/commonjs/lib/utils/handlePx2Rem.js +19 -0
  61. package/dist/commonjs/lib/utils/injectStyles.d.ts +3 -0
  62. package/dist/commonjs/lib/utils/injectStyles.d.ts.map +1 -0
  63. package/dist/commonjs/lib/utils/injectStyles.js +11 -0
  64. package/dist/commonjs/lib/utils/isImportedFromStyling.d.ts +7 -0
  65. package/dist/commonjs/lib/utils/isImportedFromStyling.d.ts.map +1 -0
  66. package/dist/commonjs/lib/utils/isImportedFromStyling.js +24 -0
  67. package/dist/commonjs/lib/utils/parseNodeToStaticValue.d.ts +11 -0
  68. package/dist/commonjs/lib/utils/parseNodeToStaticValue.d.ts.map +1 -0
  69. package/dist/commonjs/lib/utils/parseNodeToStaticValue.js +217 -0
  70. package/dist/commonjs/lib/utils/parseObjectToStaticValue.d.ts +15 -0
  71. package/dist/commonjs/lib/utils/parseObjectToStaticValue.d.ts.map +1 -0
  72. package/dist/commonjs/lib/utils/parseObjectToStaticValue.js +168 -0
  73. package/dist/commonjs/lib/utils/stylisFns.d.ts +3 -0
  74. package/dist/commonjs/lib/utils/stylisFns.d.ts.map +1 -0
  75. package/dist/commonjs/lib/utils/stylisFns.js +45 -0
  76. package/dist/commonjs/lib/utils/types.d.ts +210 -0
  77. package/dist/commonjs/lib/utils/types.d.ts.map +1 -0
  78. package/dist/commonjs/lib/utils/types.js +2 -0
  79. package/dist/commonjs/lib/webpack-loader.d.ts +7 -0
  80. package/dist/commonjs/lib/webpack-loader.d.ts.map +1 -0
  81. package/dist/commonjs/lib/webpack-loader.js +21 -0
  82. package/dist/commonjs/lib/webpackPlugin.d.ts +31 -0
  83. package/dist/commonjs/lib/webpackPlugin.d.ts.map +1 -0
  84. package/dist/commonjs/lib/webpackPlugin.js +38 -0
  85. package/dist/commonjs/spec/createProgramFromSource.d.ts +8 -0
  86. package/dist/commonjs/spec/createProgramFromSource.d.ts.map +1 -0
  87. package/dist/commonjs/spec/createProgramFromSource.js +111 -0
  88. package/dist/commonjs/spec/findNodes.d.ts +3 -0
  89. package/dist/commonjs/spec/findNodes.d.ts.map +1 -0
  90. package/dist/commonjs/spec/findNodes.js +33 -0
  91. package/dist/commonjs/testing.d.ts +4 -0
  92. package/dist/commonjs/testing.d.ts.map +1 -0
  93. package/dist/commonjs/testing.js +11 -0
  94. package/dist/es6/index.d.ts +14 -0
  95. package/dist/es6/index.d.ts.map +1 -0
  96. package/dist/es6/index.js +14 -0
  97. package/dist/es6/lib/createObjectTransform.d.ts +10 -0
  98. package/dist/es6/lib/createObjectTransform.d.ts.map +1 -0
  99. package/dist/es6/lib/createObjectTransform.js +10 -0
  100. package/dist/es6/lib/createPropertyTransform.d.ts +7 -0
  101. package/dist/es6/lib/createPropertyTransform.d.ts.map +1 -0
  102. package/dist/es6/lib/createPropertyTransform.js +7 -0
  103. package/dist/es6/lib/createTypeScriptWatchProgram.d.ts +16 -0
  104. package/dist/es6/lib/createTypeScriptWatchProgram.d.ts.map +1 -0
  105. package/dist/es6/lib/createTypeScriptWatchProgram.js +36 -0
  106. package/dist/es6/lib/styleTransform.d.ts +23 -0
  107. package/dist/es6/lib/styleTransform.d.ts.map +1 -0
  108. package/dist/es6/lib/styleTransform.js +120 -0
  109. package/dist/es6/lib/utils/createStyleObjectNode.d.ts +35 -0
  110. package/dist/es6/lib/utils/createStyleObjectNode.d.ts.map +1 -0
  111. package/dist/es6/lib/utils/createStyleObjectNode.js +74 -0
  112. package/dist/es6/lib/utils/getCssVariables.d.ts +4 -0
  113. package/dist/es6/lib/utils/getCssVariables.d.ts.map +1 -0
  114. package/dist/es6/lib/utils/getCssVariables.js +26 -0
  115. package/dist/es6/lib/utils/getErrorMessage.d.ts +16 -0
  116. package/dist/es6/lib/utils/getErrorMessage.d.ts.map +1 -0
  117. package/dist/es6/lib/utils/getErrorMessage.js +41 -0
  118. package/dist/es6/lib/utils/getFallbackVariable.d.ts +9 -0
  119. package/dist/es6/lib/utils/getFallbackVariable.d.ts.map +1 -0
  120. package/dist/es6/lib/utils/getFallbackVariable.js +26 -0
  121. package/dist/es6/lib/utils/getHash.d.ts +4 -0
  122. package/dist/es6/lib/utils/getHash.d.ts.map +1 -0
  123. package/dist/es6/lib/utils/getHash.js +9 -0
  124. package/dist/es6/lib/utils/getVarName.d.ts +17 -0
  125. package/dist/es6/lib/utils/getVarName.d.ts.map +1 -0
  126. package/dist/es6/lib/utils/getVarName.js +27 -0
  127. package/dist/es6/lib/utils/handleCalc.d.ts +2 -0
  128. package/dist/es6/lib/utils/handleCalc.d.ts.map +1 -0
  129. package/dist/es6/lib/utils/handleCalc.js +27 -0
  130. package/dist/es6/lib/utils/handleCreateStencil.d.ts +7 -0
  131. package/dist/es6/lib/utils/handleCreateStencil.d.ts.map +1 -0
  132. package/dist/es6/lib/utils/handleCreateStencil.js +301 -0
  133. package/dist/es6/lib/utils/handleCreateStyles.d.ts +3 -0
  134. package/dist/es6/lib/utils/handleCreateStyles.d.ts.map +1 -0
  135. package/dist/es6/lib/utils/handleCreateStyles.js +79 -0
  136. package/dist/es6/lib/utils/handleCreateVars.d.ts +3 -0
  137. package/dist/es6/lib/utils/handleCreateVars.d.ts.map +1 -0
  138. package/dist/es6/lib/utils/handleCreateVars.js +58 -0
  139. package/dist/es6/lib/utils/handleCssVar.d.ts +2 -0
  140. package/dist/es6/lib/utils/handleCssVar.d.ts.map +1 -0
  141. package/dist/es6/lib/utils/handleCssVar.js +13 -0
  142. package/dist/es6/lib/utils/handleInjectGlobal.d.ts +3 -0
  143. package/dist/es6/lib/utils/handleInjectGlobal.d.ts.map +1 -0
  144. package/dist/es6/lib/utils/handleInjectGlobal.js +33 -0
  145. package/dist/es6/lib/utils/handleKeyframes.d.ts +3 -0
  146. package/dist/es6/lib/utils/handleKeyframes.d.ts.map +1 -0
  147. package/dist/es6/lib/utils/handleKeyframes.js +41 -0
  148. package/dist/es6/lib/utils/handleParentModifier.d.ts +2 -0
  149. package/dist/es6/lib/utils/handleParentModifier.d.ts.map +1 -0
  150. package/dist/es6/lib/utils/handleParentModifier.js +20 -0
  151. package/dist/es6/lib/utils/handlePx2Rem.d.ts +2 -0
  152. package/dist/es6/lib/utils/handlePx2Rem.d.ts.map +1 -0
  153. package/dist/es6/lib/utils/handlePx2Rem.js +13 -0
  154. package/dist/es6/lib/utils/injectStyles.d.ts +3 -0
  155. package/dist/es6/lib/utils/injectStyles.d.ts.map +1 -0
  156. package/dist/es6/lib/utils/injectStyles.js +7 -0
  157. package/dist/es6/lib/utils/isImportedFromStyling.d.ts +7 -0
  158. package/dist/es6/lib/utils/isImportedFromStyling.d.ts.map +1 -0
  159. package/dist/es6/lib/utils/isImportedFromStyling.js +17 -0
  160. package/dist/es6/lib/utils/parseNodeToStaticValue.d.ts +11 -0
  161. package/dist/es6/lib/utils/parseNodeToStaticValue.d.ts.map +1 -0
  162. package/dist/es6/lib/utils/parseNodeToStaticValue.js +209 -0
  163. package/dist/es6/lib/utils/parseObjectToStaticValue.d.ts +15 -0
  164. package/dist/es6/lib/utils/parseObjectToStaticValue.d.ts.map +1 -0
  165. package/dist/es6/lib/utils/parseObjectToStaticValue.js +159 -0
  166. package/dist/es6/lib/utils/stylisFns.d.ts +3 -0
  167. package/dist/es6/lib/utils/stylisFns.d.ts.map +1 -0
  168. package/dist/es6/lib/utils/stylisFns.js +41 -0
  169. package/dist/es6/lib/utils/types.d.ts +210 -0
  170. package/dist/es6/lib/utils/types.d.ts.map +1 -0
  171. package/dist/es6/lib/utils/types.js +1 -0
  172. package/dist/es6/lib/webpack-loader.d.ts +7 -0
  173. package/dist/es6/lib/webpack-loader.d.ts.map +1 -0
  174. package/dist/es6/lib/webpack-loader.js +15 -0
  175. package/dist/es6/lib/webpackPlugin.d.ts +31 -0
  176. package/dist/es6/lib/webpackPlugin.d.ts.map +1 -0
  177. package/dist/es6/lib/webpackPlugin.js +31 -0
  178. package/dist/es6/spec/createProgramFromSource.d.ts +8 -0
  179. package/dist/es6/spec/createProgramFromSource.d.ts.map +1 -0
  180. package/dist/es6/spec/createProgramFromSource.js +81 -0
  181. package/dist/es6/spec/findNodes.d.ts +3 -0
  182. package/dist/es6/spec/findNodes.d.ts.map +1 -0
  183. package/dist/es6/spec/findNodes.js +26 -0
  184. package/dist/es6/testing.d.ts +4 -0
  185. package/dist/es6/testing.d.ts.map +1 -0
  186. package/dist/es6/testing.js +3 -0
  187. package/index.ts +19 -0
  188. package/lib/createObjectTransform.ts +12 -0
  189. package/lib/createPropertyTransform.ts +9 -0
  190. package/lib/createTypeScriptWatchProgram.ts +52 -0
  191. package/lib/styleTransform.ts +169 -0
  192. package/lib/utils/createStyleObjectNode.ts +105 -0
  193. package/lib/utils/getCssVariables.ts +36 -0
  194. package/lib/utils/getErrorMessage.ts +57 -0
  195. package/lib/utils/getFallbackVariable.ts +34 -0
  196. package/lib/utils/getHash.ts +13 -0
  197. package/lib/utils/getVarName.ts +32 -0
  198. package/lib/utils/handleCalc.ts +33 -0
  199. package/lib/utils/handleCreateStencil.ts +442 -0
  200. package/lib/utils/handleCreateStyles.ts +97 -0
  201. package/lib/utils/handleCreateVars.ts +90 -0
  202. package/lib/utils/handleCssVar.ts +19 -0
  203. package/lib/utils/handleInjectGlobal.ts +51 -0
  204. package/lib/utils/handleKeyframes.ts +60 -0
  205. package/lib/utils/handleParentModifier.ts +29 -0
  206. package/lib/utils/handlePx2Rem.ts +22 -0
  207. package/lib/utils/injectStyles.ts +14 -0
  208. package/lib/utils/isImportedFromStyling.ts +21 -0
  209. package/lib/utils/parseNodeToStaticValue.ts +281 -0
  210. package/lib/utils/parseObjectToStaticValue.ts +201 -0
  211. package/lib/utils/stylisFns.ts +56 -0
  212. package/lib/utils/types.ts +223 -0
  213. package/lib/webpack-loader.ts +28 -0
  214. package/lib/webpackPlugin.ts +69 -0
  215. package/package.json +19 -14
  216. package/index.js +0 -22
@@ -0,0 +1,442 @@
1
+ import ts from 'typescript';
2
+
3
+ import {slugify} from '@workday/canvas-kit-styling';
4
+
5
+ import {getVarName} from './getVarName';
6
+ import {maybeWrapCSSVariables, parseObjectToStaticValue} from './parseObjectToStaticValue';
7
+ import {createStyleObjectNode, serializeStyles} from './createStyleObjectNode';
8
+ import {getValueFromAliasedSymbol, parseNodeToStaticValue} from './parseNodeToStaticValue';
9
+ import {NestedStyleObject, NodeTransformer, TransformerContext} from './types';
10
+ import {isImportedFromStyling} from './isImportedFromStyling';
11
+ import {getHash} from './getHash';
12
+
13
+ /**
14
+ * Handle all arguments of the CallExpression `createStencil()`
15
+ */
16
+ export const handleCreateStencil: NodeTransformer = (node, context) => {
17
+ const {checker, names, extractedNames} = context;
18
+ /**
19
+ * This will match whenever a `createStencil()` call expression is encountered. It will loop
20
+ * over all the config to extract variables and styles.
21
+ *
22
+ */
23
+ if (
24
+ ts.isCallExpression(node) &&
25
+ ts.isIdentifier(node.expression) &&
26
+ node.expression.text === 'createStencil' &&
27
+ isImportedFromStyling(node.expression, checker)
28
+ ) {
29
+ const config = node.arguments[0];
30
+
31
+ // We need to keep track of stencil variables and values to automatically merge into the base
32
+ // styles
33
+ const stencilVariables: Record<string, string> = {};
34
+
35
+ // Stencil name is the variable name
36
+ const stencilName = getVarName(node.expression);
37
+ const stencilHash = getHash(node, context);
38
+
39
+ if (ts.isObjectLiteralExpression(config)) {
40
+ config.properties.forEach(property => {
41
+ if (
42
+ ts.isPropertyAssignment(property) &&
43
+ property.name &&
44
+ ts.isIdentifier(property.name) &&
45
+ property.name.text === 'extends' &&
46
+ ts.isIdentifier(property.initializer)
47
+ ) {
48
+ const className = getClassName(property.initializer.text, context);
49
+ const extendsStencilName = property.initializer.text;
50
+
51
+ if (
52
+ !Object.values(context.styles).some(fileStyles => {
53
+ return fileStyles.some(rule => rule.includes(`.${className}`));
54
+ })
55
+ ) {
56
+ // Process the extended stencil since those styles haven't been processed yet
57
+ getValueFromAliasedSymbol(property.initializer, '', context);
58
+ }
59
+
60
+ // attach all variables from extends stencil
61
+ Object.keys(names).forEach(key => {
62
+ if (key.startsWith(`${extendsStencilName}.`)) {
63
+ // We want to copy a new entry into variables that is the extended stencil with the same variable name as the base variable name
64
+ names[key.replace(extendsStencilName, stencilName)] = names[key];
65
+ }
66
+ });
67
+ }
68
+ });
69
+
70
+ // get variables first
71
+ const varsConfig = config.properties.find(property => {
72
+ return (
73
+ property.name &&
74
+ ts.isIdentifier(property.name) &&
75
+ property.name.text === 'vars' &&
76
+ ts.isPropertyAssignment(property)
77
+ );
78
+ }) as ts.PropertyAssignment | undefined;
79
+
80
+ function extractNames(node: ts.Node): any {
81
+ if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name)) {
82
+ if (ts.isObjectLiteralExpression(node.initializer)) {
83
+ return node.initializer.properties.map(extractNames);
84
+ }
85
+
86
+ const varName = getVarName(node.name);
87
+ const varValue = `--${getClassName(varName, context)}`;
88
+ names[varName] = `--${node.name.text}-${slugify(stencilName).replace(
89
+ '-stencil',
90
+ ''
91
+ )}-${stencilHash}`;
92
+
93
+ names[node.name.text] = names[varName];
94
+ extractedNames[names[varName]] = varValue;
95
+
96
+ // Evaluate the variable defaults
97
+ const value = parseNodeToStaticValue(node.initializer, context).toString();
98
+ if (value) {
99
+ // Only add the stencil variable if there's a value. An empty string means no default.
100
+ stencilVariables[names[varName]] = String(maybeWrapCSSVariables(value, names));
101
+ }
102
+ }
103
+ }
104
+
105
+ if (varsConfig && ts.isObjectLiteralExpression(varsConfig.initializer)) {
106
+ varsConfig.initializer.properties.forEach(variable => {
107
+ extractNames(variable);
108
+ });
109
+ }
110
+
111
+ const configProperties = config.properties.map((property, index, properties) => {
112
+ if (property.name && ts.isIdentifier(property.name)) {
113
+ // base config object
114
+ if (property.name.text === 'base') {
115
+ const styleObj = parseStyleBlock(property, context, stencilName);
116
+
117
+ if (styleObj) {
118
+ const initializer = createStyleReplacementNode(
119
+ property,
120
+ {
121
+ ...stencilVariables,
122
+ boxSizing: 'border-box',
123
+ ...styleObj,
124
+ },
125
+ getClassName(getVarName(property.name), context),
126
+ context
127
+ );
128
+
129
+ return updateStyleProperty(property, initializer);
130
+ }
131
+ }
132
+
133
+ // modifiers config object
134
+ if (
135
+ property.name.text === 'modifiers' &&
136
+ ts.isPropertyAssignment(property) &&
137
+ ts.isObjectLiteralExpression(property.initializer)
138
+ ) {
139
+ // modifier key
140
+ return ts.factory.updatePropertyAssignment(
141
+ property,
142
+ property.name,
143
+ ts.factory.updateObjectLiteralExpression(
144
+ property.initializer,
145
+ property.initializer.properties.map(modifierProperty => {
146
+ if (
147
+ ts.isPropertyAssignment(modifierProperty) &&
148
+ modifierProperty.name &&
149
+ ts.isIdentifier(modifierProperty.name) &&
150
+ ts.isObjectLiteralExpression(modifierProperty.initializer)
151
+ ) {
152
+ // modifier value
153
+ return ts.factory.updatePropertyAssignment(
154
+ modifierProperty,
155
+ modifierProperty.name,
156
+ ts.factory.updateObjectLiteralExpression(
157
+ modifierProperty.initializer,
158
+ modifierProperty.initializer.properties.map(modifier => {
159
+ const styleObj = parseStyleBlock(
160
+ modifier,
161
+ context,
162
+ getClassName(stencilName, context)
163
+ );
164
+
165
+ if (styleObj && modifier.name) {
166
+ const stencilClassName = getClassName(stencilName, context);
167
+ const fullModifierName = getClassName(
168
+ getVarName(modifier.name),
169
+ context
170
+ );
171
+ const className = `${stencilClassName}.${fullModifierName.replace(
172
+ `${stencilClassName}--`,
173
+ ''
174
+ )}`;
175
+ const initializer = createStyleReplacementNode(
176
+ modifier,
177
+ styleObj,
178
+ className,
179
+ context
180
+ );
181
+ return updateStyleProperty(modifier, initializer);
182
+ }
183
+
184
+ return modifier;
185
+ })
186
+ )
187
+ );
188
+ }
189
+
190
+ return property;
191
+ })
192
+ )
193
+ );
194
+ }
195
+
196
+ // compound config array
197
+ /**
198
+ * Compound config array. It looks like:
199
+ *
200
+ * ```ts
201
+ * compound: [
202
+ * {
203
+ * modifiers: { size: 'large', iconPosition: 'start' },
204
+ * styles: { padding: 20 }
205
+ * }
206
+ * ]
207
+ * ```
208
+ */
209
+ if (
210
+ property.name.text === 'compound' &&
211
+ ts.isPropertyAssignment(property) &&
212
+ ts.isArrayLiteralExpression(property.initializer)
213
+ ) {
214
+ return ts.factory.updatePropertyAssignment(
215
+ property,
216
+ property.name,
217
+ ts.factory.updateArrayLiteralExpression(
218
+ property.initializer,
219
+ property.initializer.elements.map(element => {
220
+ if (ts.isObjectLiteralExpression(element)) {
221
+ const selectors: string[] = [];
222
+
223
+ selectors.push(`.${getClassName(stencilName, context)}`);
224
+
225
+ return ts.factory.updateObjectLiteralExpression(
226
+ element,
227
+ element.properties.map((compoundProperty, index, compoundProperties) => {
228
+ /**
229
+ * If the property is `modifiers`, we want to extract selectors from it. For
230
+ * example,
231
+ *
232
+ * ```ts
233
+ * const button = createStencil({
234
+ * // other config
235
+ * compound: {
236
+ * modifiers: { size: 'large', inverse: true },
237
+ * styles: {}
238
+ * }
239
+ * })
240
+ * ```
241
+ *
242
+ * After this, `selectors` should contain ['.button--size-large',
243
+ * '.button--inverse']
244
+ */
245
+ if (
246
+ compoundProperty.name &&
247
+ ts.isIdentifier(compoundProperty.name) &&
248
+ compoundProperty.name.text === 'modifiers' &&
249
+ ts.isPropertyAssignment(compoundProperty) &&
250
+ ts.isObjectLiteralExpression(compoundProperty.initializer)
251
+ ) {
252
+ compoundProperty.initializer.properties.forEach(modifier => {
253
+ if (ts.isPropertyAssignment(modifier)) {
254
+ let className = '';
255
+ if (ts.isIdentifier(modifier.name)) {
256
+ className = slugify(modifier.name.text);
257
+ }
258
+
259
+ // The initializer should either be the `true` keyword or a string
260
+ // literal. We don't add `-true` to the name.
261
+ if (ts.isStringLiteral(modifier.initializer)) {
262
+ className += `-${modifier.initializer.text}`;
263
+ }
264
+
265
+ selectors.push(className);
266
+ }
267
+ });
268
+ return compoundProperty;
269
+ }
270
+
271
+ // styles key
272
+ if (
273
+ compoundProperty.name &&
274
+ ts.isIdentifier(compoundProperty.name) &&
275
+ compoundProperty.name.text === 'styles'
276
+ ) {
277
+ const styleObj = parseStyleBlock(compoundProperty, context, stencilName);
278
+
279
+ if (styleObj) {
280
+ // We need to inject compound style selectors into a file. We'll compound the
281
+ // selectors with multiple class names. This will increase specificity of compound
282
+ // selectors. This will be harder to override and we don't increase specificity in
283
+ // the runtime implementation, but runtime creates an extra CSS class name that
284
+ // isn't known to anyone. It seems unreasonable to expect CSS users to remember to
285
+ // add compound modifier class names. We'll make it so it is easier to author
286
+ // components in CSS and let them sort the specificity issues.
287
+ const serialized = serializeStyles(
288
+ compoundProperty,
289
+ styleObj,
290
+ `${selectors.join('.')}{%s}`,
291
+ context
292
+ );
293
+
294
+ const initializer = createStyleObjectNode(
295
+ serialized.styles,
296
+ serialized.name
297
+ );
298
+
299
+ return updateStyleProperty(compoundProperty, initializer);
300
+ }
301
+ }
302
+
303
+ return compoundProperty;
304
+ })
305
+ );
306
+ }
307
+
308
+ return element;
309
+ })
310
+ )
311
+ );
312
+ }
313
+ }
314
+
315
+ return property;
316
+ });
317
+
318
+ return ts.factory.updateCallExpression(node, node.expression, undefined, [
319
+ ts.factory.updateObjectLiteralExpression(config, configProperties),
320
+ ts.factory.createStringLiteral(
321
+ `${slugify(stencilName).replace('-stencil', '')}-${stencilHash}`
322
+ ),
323
+ ]);
324
+ }
325
+ }
326
+
327
+ return;
328
+ };
329
+
330
+ /**
331
+ * A style block is a `base`, `modifier`, or `compoundModifier` style block. It could be an ObjectLiteralExpression,
332
+ * an ArrowFunction, MethodDeclaration, etc.
333
+ */
334
+ function parseStyleBlock(
335
+ property: ts.ObjectLiteralElementLike,
336
+ context: TransformerContext,
337
+ stencilName: string
338
+ ): NestedStyleObject | undefined {
339
+ let styleObj: NestedStyleObject | undefined;
340
+ if (ts.isPropertyAssignment(property)) {
341
+ if (ts.isObjectLiteralExpression(property.initializer)) {
342
+ styleObj = parseObjectToStaticValue(property.initializer, {
343
+ ...context,
344
+ nameScope: `${stencilName}.vars.`,
345
+ });
346
+ }
347
+
348
+ if (isFunctionLikeDeclaration(property.initializer)) {
349
+ const returnNode = getReturnStatement(property.initializer);
350
+ if (returnNode) {
351
+ styleObj = parseObjectToStaticValue(returnNode, {
352
+ ...context,
353
+ nameScope: `${stencilName}.vars.`,
354
+ });
355
+ }
356
+ }
357
+ }
358
+
359
+ if (isFunctionLikeDeclaration(property)) {
360
+ const returnNode = getReturnStatement(property);
361
+ if (returnNode) {
362
+ styleObj = parseObjectToStaticValue(returnNode, {
363
+ ...context,
364
+ nameScope: `${stencilName}.vars.`,
365
+ });
366
+ }
367
+ }
368
+
369
+ return styleObj;
370
+ }
371
+
372
+ function getReturnStatement(node: ts.FunctionLikeDeclaration): ts.Node | undefined {
373
+ if (node.body && ts.isParenthesizedExpression(node.body)) {
374
+ return node.body.expression;
375
+ }
376
+
377
+ if (node.body && ts.isBlock(node.body)) {
378
+ let returnNode: ts.Node | undefined;
379
+
380
+ // look for the return statement. It must be a top-level statement in the block
381
+ node.body.statements.forEach(statement => {
382
+ // () => { return {} }
383
+ if (ts.isReturnStatement(statement)) {
384
+ returnNode = statement.expression;
385
+ }
386
+ });
387
+
388
+ return returnNode;
389
+ }
390
+
391
+ return undefined;
392
+ }
393
+
394
+ function isFunctionLikeDeclaration(node: ts.Node): node is ts.FunctionLikeDeclaration {
395
+ return (node as Object).hasOwnProperty('body');
396
+ }
397
+
398
+ function createStyleReplacementNode(
399
+ node: ts.Node,
400
+ styleObj: NestedStyleObject,
401
+ className: string,
402
+ context: TransformerContext
403
+ ) {
404
+ const {names, extractedNames} = context;
405
+ const serialized = serializeStyles(node, styleObj, `.${className}{%s}`, context);
406
+
407
+ const varName = getVarName(node);
408
+ const value = `css-${serialized.name}`;
409
+ names[varName] = value;
410
+ extractedNames[value] = getClassName(varName, context);
411
+
412
+ return createStyleObjectNode(serialized.styles, serialized.name);
413
+ }
414
+
415
+ export function getClassName(name: string, {prefix}: TransformerContext): string {
416
+ return (
417
+ `${prefix}-` +
418
+ slugify(name)
419
+ .replace('-vars', '')
420
+ .replace('-stencil', '')
421
+ .replace('-base', '')
422
+ .replace('-modifiers', '-')
423
+ .replace('-true', '')
424
+ .replace('-compound', '')
425
+ );
426
+ }
427
+
428
+ /**
429
+ * If the property is a `PropertyAssignment`, use the TypeScript factory updater to maximize
430
+ * sourcemap use. Otherwise, return a new property assignment. For example, a Stencil could be using
431
+ * a `MethodDeclaration` which means we return a different node type: `base({color}) {}`
432
+ */
433
+ function updateStyleProperty(
434
+ property: ts.ObjectLiteralElementLike,
435
+ initializer: ts.Expression
436
+ ): ts.PropertyAssignment {
437
+ if (ts.isPropertyAssignment(property)) {
438
+ return ts.factory.updatePropertyAssignment(property, property.name, initializer);
439
+ }
440
+
441
+ return ts.factory.createPropertyAssignment(property.name!, initializer);
442
+ }
@@ -0,0 +1,97 @@
1
+ import ts from 'typescript';
2
+
3
+ import {parseObjectToStaticValue, parseStyleObjFromType} from './parseObjectToStaticValue';
4
+ import {createStyleObjectNode, serializeStyles} from './createStyleObjectNode';
5
+ import {NestedStyleObject, NodeTransformer, TransformerContext} from './types';
6
+ import {isImportedFromStyling} from './isImportedFromStyling';
7
+ import {getVarName} from './getVarName';
8
+ import {slugify} from '@workday/canvas-kit-styling';
9
+
10
+ export const handleCreateStyles: NodeTransformer = (node, context) => {
11
+ const {checker, prefix} = context;
12
+ /**
13
+ * Check if the node is a call expression that looks like:
14
+ *
15
+ * ```ts
16
+ * createStyles({
17
+ * // properties
18
+ * })
19
+ * ```
20
+ *
21
+ * It will also make sure the `createStyles` function was imported from
22
+ * `@workday/canvas-kit-styling` to ensure we don't rewrite the AST of code we don't own.
23
+ *
24
+ * This transformation will pre-serialize the style objects and turn them into strings for
25
+ * faster runtime processing in Emotion. The following is an example of the transformation.
26
+ *
27
+ * ```ts
28
+ * // before transformation
29
+ * const myStyles = createStyles({
30
+ * fontSize: '1rem'
31
+ * })
32
+ *
33
+ * // after transformation
34
+ * const myStyles = createStyles({
35
+ * name: 'abc123',
36
+ * styles: 'font-size: 1rem;'
37
+ * })
38
+ * ```
39
+ *
40
+ * The after transformation already serialized the styles and goes through a shortcut process
41
+ * in `@emotion/css` where only the Emotion cache is checked and styles are inserted if the
42
+ * cache key wasn't found.
43
+ */
44
+ if (
45
+ ts.isCallExpression(node) &&
46
+ ts.isIdentifier(node.expression) &&
47
+ node.expression.text === 'createStyles' &&
48
+ isImportedFromStyling(node.expression, checker) &&
49
+ node.arguments.length > 0
50
+ ) {
51
+ const cssClassName = `${prefix}-${slugify(getVarName(node.expression))
52
+ .replace('-styles', '')
53
+ .replace('-modifiers', '-')
54
+ .replace('-true', '')}`;
55
+
56
+ const newArguments = [...node.arguments].map(arg => {
57
+ // An `ObjectLiteralExpression` is an object like `{foo:'bar'}`:
58
+ // https://ts-ast-viewer.com/#code/MYewdgzgLgBFCmBbADjAvDA3gKBjAZiCAFwwDkARgIYBOZ2AvkA
59
+ if (ts.isObjectLiteralExpression(arg)) {
60
+ const styleObj = parseObjectToStaticValue(arg, context);
61
+ return createStyleReplacementNode(node, styleObj, cssClassName, context);
62
+ }
63
+ // An Identifier is a variable. It could come from anywhere - imports, earlier
64
+ // assignments, etc. The easiest thing to do is to ask the TypeScript type checker what
65
+ // the type representation is and go from there.
66
+ if (ts.isIdentifier(arg)) {
67
+ const type = checker.getTypeAtLocation(arg);
68
+
69
+ // `createStyles` accepts strings as class names. If the class name is
70
+ if (type.isStringLiteral() || type.getFlags() & ts.TypeFlags.String) {
71
+ return arg;
72
+ }
73
+
74
+ // The type must be a object
75
+ const styleObj = parseStyleObjFromType(type, context);
76
+
77
+ return createStyleReplacementNode(node, styleObj, cssClassName, context);
78
+ }
79
+ return arg;
80
+ });
81
+
82
+ return ts.factory.updateCallExpression(node, node.expression, [], newArguments);
83
+ }
84
+
85
+ return;
86
+ };
87
+
88
+ function createStyleReplacementNode(
89
+ node: ts.Node,
90
+ styleObj: NestedStyleObject,
91
+ className: string,
92
+ context: TransformerContext
93
+ ) {
94
+ const serialized = serializeStyles(node, styleObj, `.${className}{%s}`, context);
95
+
96
+ return createStyleObjectNode(serialized.styles, serialized.name);
97
+ }
@@ -0,0 +1,90 @@
1
+ import ts from 'typescript';
2
+
3
+ import {slugify} from '@workday/canvas-kit-styling';
4
+
5
+ import {getVarName} from './getVarName';
6
+ import {NodeTransformer, TransformerContext} from './types';
7
+ import {getHash} from './getHash';
8
+
9
+ export const handleCreateVars: NodeTransformer = (node, context) => {
10
+ /**
11
+ * This will create a variable
12
+ */
13
+ if (
14
+ ts.isCallExpression(node) &&
15
+ ts.isIdentifier(node.expression) &&
16
+ node.expression.text === 'createVars'
17
+ ) {
18
+ const {id, vars} = addNames(node, context);
19
+
20
+ return ts.factory.updateCallExpression(
21
+ node,
22
+ node.expression,
23
+ [],
24
+ [
25
+ ts.factory.createObjectLiteralExpression(
26
+ [
27
+ ts.factory.createPropertyAssignment(
28
+ ts.factory.createIdentifier('id'),
29
+ ts.factory.createStringLiteral(id)
30
+ ),
31
+ ts.factory.createPropertyAssignment(
32
+ ts.factory.createIdentifier('args'),
33
+ ts.factory.createArrayLiteralExpression(
34
+ vars.map(val => ts.factory.createStringLiteral(val)),
35
+ false
36
+ )
37
+ ),
38
+ ],
39
+ false
40
+ ),
41
+ ]
42
+ );
43
+ }
44
+
45
+ /**
46
+ * Check to see if this node is an ObjectLiteralExpression with properties with `createVars`
47
+ * values.
48
+ *
49
+ * ```ts
50
+ * const foo = {
51
+ * bar: createVars('color')
52
+ * }
53
+ * ```
54
+ *
55
+ * This happens when names are imported from other files. We don't need to transform this, but
56
+ * we'll need to add names for property parsing.
57
+ */
58
+ if (ts.isObjectLiteralExpression(node)) {
59
+ node.properties.forEach(property => {
60
+ if (
61
+ ts.isPropertyAssignment(property) &&
62
+ ts.isCallExpression(property.initializer) &&
63
+ ts.isIdentifier(property.initializer.expression) &&
64
+ property.initializer.expression.text === 'createVars'
65
+ ) {
66
+ addNames(property.initializer, context);
67
+ }
68
+ });
69
+ }
70
+
71
+ return;
72
+ };
73
+
74
+ function addNames(node: ts.CallExpression, context: TransformerContext) {
75
+ const {prefix, names, extractedNames} = context;
76
+ const hash = getHash(node, context);
77
+
78
+ const varNamePrefix = getVarName(node);
79
+ const vars = node.arguments
80
+ .map(arg => ts.isStringLiteral(arg) && arg.text)
81
+ .filter(Boolean) as string[];
82
+
83
+ vars.forEach(v => {
84
+ const varName = `${varNamePrefix}.${v}`;
85
+ names[varName] = `--${v}-${hash}`;
86
+ extractedNames[names[varName]] = `--${prefix}-${slugify(varName).replace('-vars', '')}`;
87
+ });
88
+
89
+ return {id: hash, vars};
90
+ }
@@ -0,0 +1,19 @@
1
+ import ts from 'typescript';
2
+
3
+ import {cssVar} from '@workday/canvas-kit-styling';
4
+ import {createPropertyTransform} from '../createPropertyTransform';
5
+ import {parseNodeToStaticValue} from './parseNodeToStaticValue';
6
+
7
+ export const handleCssVar = createPropertyTransform((node, context) => {
8
+ if (
9
+ ts.isCallExpression(node) &&
10
+ ts.isIdentifier(node.expression) &&
11
+ node.expression.text === 'cssVar'
12
+ ) {
13
+ const args = node.arguments.map(arg => parseNodeToStaticValue(arg, context));
14
+
15
+ return cssVar(args[0] as string, (args[1] as string) || context.names[args[0]]);
16
+ }
17
+
18
+ return;
19
+ });
@@ -0,0 +1,51 @@
1
+ import ts from 'typescript';
2
+
3
+ import {isImportedFromStyling} from './isImportedFromStyling';
4
+ import {parseObjectToStaticValue} from './parseObjectToStaticValue';
5
+ import {createStyleObjectNode, serializeStyles} from './createStyleObjectNode';
6
+ import {NestedStyleObject, NodeTransformer, TransformerContext} from './types';
7
+ import {parseNodeToStaticValue} from './parseNodeToStaticValue';
8
+
9
+ export const handleInjectGlobal: NodeTransformer = (node, context) => {
10
+ const {checker} = context;
11
+
12
+ if (
13
+ ts.isTaggedTemplateExpression(node) &&
14
+ ts.isIdentifier(node.tag) &&
15
+ node.tag.text === 'injectGlobal' &&
16
+ isImportedFromStyling(node.tag, checker)
17
+ ) {
18
+ const styleObj = parseNodeToStaticValue(node.template, context).toString();
19
+
20
+ return ts.factory.createCallExpression(node.tag, undefined, [
21
+ createStyleReplacementNode(node, styleObj, context),
22
+ ]);
23
+ }
24
+
25
+ if (
26
+ ts.isCallExpression(node) &&
27
+ ts.isIdentifier(node.expression) &&
28
+ node.expression.text === 'injectGlobal' &&
29
+ isImportedFromStyling(node.expression, checker)
30
+ ) {
31
+ if (ts.isObjectLiteralExpression(node.arguments[0])) {
32
+ const styleObj = parseObjectToStaticValue(node.arguments[0], context);
33
+
34
+ return ts.factory.updateCallExpression(node, node.expression, undefined, [
35
+ createStyleReplacementNode(node, styleObj, context),
36
+ ]);
37
+ }
38
+ }
39
+
40
+ return;
41
+ };
42
+
43
+ function createStyleReplacementNode(
44
+ node: ts.Node,
45
+ styleObj: NestedStyleObject | string,
46
+ context: TransformerContext
47
+ ) {
48
+ const serialized = serializeStyles(node, styleObj, '%s', context);
49
+
50
+ return createStyleObjectNode(serialized.styles, serialized.name);
51
+ }