@workday/canvas-kit-styling-transform 13.2.1 → 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,169 @@
1
+ /// <reference types="node" />
2
+ import path from 'node:path';
3
+ import ts from 'typescript';
4
+
5
+ import {getVariablesFromFiles} from './utils/getCssVariables';
6
+ import {handleCalc} from './utils/handleCalc';
7
+ import {handleCreateStencil} from './utils/handleCreateStencil';
8
+ import {handleCreateStyles} from './utils/handleCreateStyles';
9
+ import {handleCreateVars} from './utils/handleCreateVars';
10
+ import {handleCssVar} from './utils/handleCssVar';
11
+ import {handleInjectGlobal} from './utils/handleInjectGlobal';
12
+ import {handleKeyframes} from './utils/handleKeyframes';
13
+ import {handleParentModifier} from './utils/handleParentModifier';
14
+ import {handlePx2Rem} from './utils/handlePx2Rem';
15
+ import {NodeTransformer, ObjectTransform, TransformerContext} from './utils/types';
16
+
17
+ export type NestedStyleObject = {[key: string]: string | NestedStyleObject};
18
+
19
+ export interface StyleTransformerOptions extends TransformerContext {
20
+ fallbackFiles?: string[];
21
+ transformers?: NodeTransformer[];
22
+ }
23
+
24
+ let vars: TransformerContext['names'] = {};
25
+ let extractedNames: TransformerContext['extractedNames'] = {};
26
+ let styles: TransformerContext['styles'] = {};
27
+ let cache: TransformerContext['cache'] = {};
28
+ let loadedFallbacks = false;
29
+
30
+ /**
31
+ * The reset is used in tests and should not be called normally.
32
+ */
33
+ export function _reset() {
34
+ vars = {};
35
+ extractedNames = {};
36
+ styles = {};
37
+ cache = {};
38
+ loadedFallbacks = false;
39
+ }
40
+
41
+ /**
42
+ * Optional list of transformers. Useful to override for tests
43
+ */
44
+ const defaultTransformers = [
45
+ handleKeyframes,
46
+ handleCreateVars,
47
+ handleCreateStyles,
48
+ handleCreateStencil,
49
+ handleInjectGlobal,
50
+ ];
51
+ export default styleTransformer;
52
+ export function styleTransformer(
53
+ program: ts.Program,
54
+ {fallbackFiles = [], ...options}: Partial<StyleTransformerOptions> = {}
55
+ ): ts.TransformerFactory<ts.SourceFile> {
56
+ const {names, ...transformContext} = withDefaultContext(program.getTypeChecker(), options);
57
+
58
+ if (!loadedFallbacks) {
59
+ const files: string[] = fallbackFiles
60
+ .filter(file => file) // don't process empty files
61
+ .map(file => {
62
+ // Find the fully-qualified path name. This could error which should give "module not found" errors
63
+ return file.startsWith('.') ? path.resolve(process.cwd(), file) : require.resolve(file);
64
+ })
65
+ .map(file => {
66
+ console.log(`Loading CSS variable fallback file: ${file}`);
67
+ return ts.sys.readFile(file) || '';
68
+ });
69
+
70
+ const fallbackVars = getVariablesFromFiles(files);
71
+ console.log(`Found ${Object.keys(fallbackVars).length} variables.`);
72
+
73
+ // eslint-disable-next-line guard-for-in
74
+ for (const key in fallbackVars) {
75
+ names[key] = fallbackVars[key];
76
+ }
77
+ loadedFallbacks = true;
78
+ }
79
+
80
+ return context => {
81
+ const visit: ts.Visitor = node => {
82
+ if (!transformContext.fileName) {
83
+ transformContext.fileName = node.getSourceFile()?.fileName;
84
+ transformContext.prefix = transformContext.getPrefix(transformContext.fileName);
85
+ }
86
+
87
+ if (
88
+ ts.isSourceFile(node) &&
89
+ node.fileName !== 'test.ts' &&
90
+ transformContext.styles[transformContext.getFileName(node.fileName)] &&
91
+ transformContext.extractCSS
92
+ ) {
93
+ ts.sys.writeFile(
94
+ transformContext.getFileName(transformContext.getFileName(node.fileName)),
95
+ (transformContext.styles[transformContext.getFileName(node.fileName)] || []).join('\n')
96
+ );
97
+ }
98
+
99
+ const newNode = transformContext.transform(node, {
100
+ names,
101
+ ...transformContext,
102
+ });
103
+
104
+ return newNode || ts.visitEachChild(node, visit, context);
105
+ };
106
+
107
+ return (node => ts.visitNode(node, visit)) as ts.Transformer<ts.SourceFile>;
108
+ };
109
+ }
110
+
111
+ export function withDefaultContext(
112
+ checker: ts.TypeChecker,
113
+ {transformers, ...input}: Partial<StyleTransformerOptions> = {}
114
+ ): TransformerContext {
115
+ return {
116
+ prefix: 'css',
117
+ getPrefix: path => input.prefix || 'css',
118
+ names: vars,
119
+ extractedNames,
120
+ styles,
121
+ cache,
122
+ checker,
123
+ seed: '',
124
+ extractCSS: false,
125
+ getFileName: path => path.replace(/\.tsx?/, '.css'),
126
+ objectTransforms: [] as ObjectTransform[],
127
+ transform: handleTransformers(transformers || defaultTransformers),
128
+ ...input,
129
+ propertyTransforms: [handleCalc, handlePx2Rem, handleCssVar, handleParentModifier].concat(
130
+ input.propertyTransforms || []
131
+ ),
132
+ } as TransformerContext;
133
+ }
134
+
135
+ /**
136
+ * This function is useful for tests or a custom build. The `styleTransformer` function is used by
137
+ * the https://www.npmjs.com/package/ts-patch package.
138
+ */
139
+ export function transform(
140
+ program: ts.Program,
141
+ fileName = 'test.ts',
142
+ options?: Partial<StyleTransformerOptions>
143
+ ) {
144
+ const source =
145
+ program.getSourceFile(fileName) || ts.createSourceFile(fileName, '', ts.ScriptTarget.ES2019);
146
+
147
+ const printer = ts.createPrinter();
148
+
149
+ const transformers = [styleTransformer(program, options)];
150
+
151
+ return printer.printFile(
152
+ ts.transform(source, transformers).transformed.find(s => s.fileName === source.fileName) ||
153
+ source
154
+ );
155
+ }
156
+
157
+ const handleTransformers =
158
+ (transformers: ((node: ts.Node, context: TransformerContext) => ts.Node | void)[]) =>
159
+ (node: ts.Node, context: TransformerContext) => {
160
+ return transformers.reduce((result, transformer) => {
161
+ return result || transformer(node, context);
162
+ }, undefined as ts.Node | void);
163
+ };
164
+
165
+ export function getConfig(basePath = '.') {
166
+ const tsconfigPath = ts.findConfigFile(basePath, ts.sys.fileExists, 'styling.config.ts');
167
+
168
+ return tsconfigPath;
169
+ }
@@ -0,0 +1,105 @@
1
+ import {serializeStyles as serializedStylesEmotion} from '@emotion/serialize';
2
+ import crypto from 'node:crypto';
3
+ import {compile, serialize} from 'stylis';
4
+ import ts from 'typescript';
5
+
6
+ import {generateUniqueId} from '@workday/canvas-kit-styling';
7
+
8
+ import {prettyStringify} from './stylisFns';
9
+ import {NestedStyleObject, TransformerContext} from './types';
10
+
11
+ /**
12
+ * Creates an AST node representation of the passed in `styleObj`, but in the format of `{name:
13
+ * string, styles: serializedStyles}`. The `name` is hard-coded here to work with both server-side
14
+ * and client-side style injection. This results in a stable style key for Emotion while also
15
+ * optimizing style serialization.
16
+ *
17
+ * If `name` is provided, the name will be whatever `name` is, replacing "{hash}" with the hash
18
+ * created via `serializeStyles`. For example: 'animation-{hash}' will be converted into
19
+ * 'animation-abc123'
20
+ */
21
+ export function createStyleObjectNode(styles: string, name?: string) {
22
+ const styleExpression = ts.factory.createStringLiteral(styles);
23
+
24
+ // create an emotion-optimized object: https://github.com/emotion-js/emotion/blob/f3b268f7c52103979402da919c9c0dd3f9e0e189/packages/serialize/src/index.js#L315-L322
25
+ // Looks like: `{name: $hash, styles: $styleText }`
26
+ return ts.factory.createObjectLiteralExpression(
27
+ [
28
+ ts.factory.createPropertyAssignment(
29
+ ts.factory.createIdentifier('name'),
30
+ ts.factory.createStringLiteral(name || generateUniqueId()) // We might be using values that are resolved at runtime, but should still be static. We're only supporting the `cs` function running once per file, so a stable id based on a hash is not necessary
31
+ ),
32
+ ts.factory.createPropertyAssignment(
33
+ ts.factory.createIdentifier('styles'),
34
+ styleExpression // In the future we can extract CSS from here by running the `stylis` compiler directly. Emotion does this here: https://github.com/emotion-js/emotion/blob/f3b268f7c52103979402da919c9c0dd3f9e0e189/packages/cache/src/index.js#L188-L245
35
+ ),
36
+ ],
37
+ false
38
+ );
39
+ }
40
+
41
+ /**
42
+ * Compiles CSS using stylis. Emotion's `serializeStyles` creates an unwrapped string for cache
43
+ * storage and it often needs to be wrapped by a CSS selector or `@keyframes`. This function does
44
+ * this the same way Emotion does it internally.
45
+ */
46
+ export function compileCSS(input: string): string {
47
+ return serialize(compile(input), prettyStringify);
48
+ }
49
+
50
+ /**
51
+ * Serialize styles and put them to style output. The styles will be serialized via Emotion. Returns
52
+ * the serialized styles.
53
+ * @param node
54
+ * @param input
55
+ * @param template The template for creating styles for static CSS. There are two placeholders: `%n`
56
+ * represents the hash name while `%s` represents the string styles.
57
+ * @param context
58
+ * @returns
59
+ */
60
+ export function serializeStyles(
61
+ node: ts.Node,
62
+ input: NestedStyleObject | string,
63
+ template: string,
64
+ context: TransformerContext
65
+ ) {
66
+ const {getFileName, styles, cache, names, extractedNames} = context;
67
+ const fileName = getFileName(node.getSourceFile().fileName);
68
+ const serialized = serializedStylesEmotion([input]);
69
+ const hash = getHash(node, context);
70
+ serialized.name = hash;
71
+
72
+ if (!cache[hash]) {
73
+ const styleOutput = compileCSS(
74
+ template.replace('%s', serialized.styles).replace('%n', serialized.name)
75
+ );
76
+
77
+ let extractedStyleOutput = styleOutput;
78
+
79
+ for (const key in names) {
80
+ if (extractedNames[names[key]]) {
81
+ // @ts-ignore replaceAll was added in es2021, but our lib versions don't go past es2019. replaceAll is available in node 15+
82
+ extractedStyleOutput = extractedStyleOutput.replaceAll(
83
+ names[key],
84
+ extractedNames[names[key]]
85
+ );
86
+ }
87
+ }
88
+ styles[fileName] = styles[fileName] || [];
89
+ styles[fileName].push(extractedStyleOutput);
90
+ cache[hash] = styleOutput;
91
+ }
92
+
93
+ return serialized;
94
+ }
95
+
96
+ /**
97
+ * Generate a deterministic hash that is unique to the seed +
98
+ */
99
+ export function getHash(node: ts.Node, context: TransformerContext) {
100
+ const content = context.seed + node.getStart() + node.getEnd();
101
+ // Convert content to a sha256 hash and then convert to a base36 number for better compression
102
+ return Number(
103
+ `0x${crypto.createHash('sha256').update(content).digest('hex').slice(0, 7)}`
104
+ ).toString(36);
105
+ }
@@ -0,0 +1,36 @@
1
+ import {compile, Element} from 'stylis';
2
+
3
+ export function getVariablesFromFiles(files: string[]): Record<string, string> {
4
+ return files.reduce((result, file) => {
5
+ extractVariables(compile(file));
6
+ return {...result, ...extractVariables(compile(file))};
7
+ }, {} as Record<string, string>);
8
+ }
9
+
10
+ export function extractVariables(
11
+ blocks: Element[] | string,
12
+ variables: Record<string, string> = {}
13
+ ): Record<string, string> {
14
+ if (typeof blocks === 'string') {
15
+ return variables;
16
+ }
17
+ return blocks
18
+ .filter(block => block.type === 'rule')
19
+ .reduce(
20
+ (result, rule) => {
21
+ if (Array.isArray(rule.children)) {
22
+ rule.children.forEach(child => {
23
+ if (
24
+ typeof child.props === 'string' &&
25
+ child.props.startsWith('--') &&
26
+ typeof child.children === 'string'
27
+ ) {
28
+ result[child.props] = child.children;
29
+ }
30
+ });
31
+ }
32
+ return result;
33
+ },
34
+ {...variables}
35
+ );
36
+ }
@@ -0,0 +1,57 @@
1
+ import ts from 'typescript';
2
+ import {TransformerContext} from './types';
3
+
4
+ /**
5
+ * Creates an error message around a node. It will look something like:
6
+ *
7
+ * ```
8
+ * Unknown type at: "fontSize".
9
+ * File: test.ts, Line: 6, Character: 17.
10
+ * const styles = createStyles({
11
+ * fontSize: fontSize
12
+ * ========
13
+ * })
14
+ * ```
15
+ */
16
+ export function getErrorMessage(node: ts.Node, context: TransformerContext) {
17
+ const sourceFile = node.getSourceFile();
18
+
19
+ const {line} = node.getSourceFile().getLineAndCharacterOfPosition(node.pos);
20
+ const lineStarts = sourceFile.getLineStarts();
21
+
22
+ const lineStartIndex = lineStarts.findIndex(s => s >= node.pos) - 1;
23
+
24
+ // get a whole line's text given a lineStarts index
25
+ function getLine(sourceFile: ts.SourceFile, startIndex: number) {
26
+ const lineStarts = sourceFile.getLineStarts();
27
+
28
+ return sourceFile.text.substring(
29
+ lineStarts[Math.max(0, startIndex)],
30
+ startIndex + 1 >= lineStarts.length ? undefined : lineStarts[startIndex + 1]
31
+ );
32
+ }
33
+
34
+ // Create a full context message with source code and highlighting
35
+ const lineBefore = getLine(sourceFile, lineStartIndex - 1);
36
+ const lineCurrent = getLine(sourceFile, lineStartIndex);
37
+ const lineAfter = getLine(sourceFile, lineStartIndex + 1);
38
+ const highlightedLine =
39
+ ''
40
+ .padStart(node.getStart() - lineStarts[lineStartIndex], ' ')
41
+ .padEnd(node.getStart() - lineStarts[lineStartIndex] + node.getWidth(), '=') + '\n';
42
+
43
+ /** This should look something like:
44
+ * ```
45
+ * const styles = createStyles({
46
+ * fontSize: fontSize
47
+ * ========
48
+ * })
49
+ * ```
50
+ */
51
+ const fullContext = lineBefore + lineCurrent + highlightedLine + lineAfter;
52
+
53
+ const character = node.getStart() - lineStarts[lineStartIndex];
54
+ return `File: ${sourceFile.fileName}:${line + 1}:${character}.\n${fullContext}\nOriginal File: ${
55
+ context.fileName
56
+ }`;
57
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Looks for a variable value that doesn't include a fallback and automatically adds one if found in
3
+ * the current cache of names. This allows fallbacks to be automatically included in environments
4
+ * without the names defined. This is most useful for Storybook or other sandboxes that may not have
5
+ * CSS Variables defined. The fallbacks will allow the UI to look correct without additional setup.
6
+ * Fallbacks come from the `fallbackFiles` transform configuration.
7
+ */
8
+ export function getFallbackVariable(
9
+ variableName: string,
10
+ names: Record<string, string>
11
+ ): string | undefined {
12
+ const variable = variableName.includes('var(') ? variableName : names[variableName];
13
+ if (variable && variable.includes('var(')) {
14
+ return variable.replace(
15
+ /(var\(([A-Za-z0-9\-_]+)\))/,
16
+ (
17
+ /** matched substring "var(--var-name)" */ _,
18
+ /** the full match of the first group "var(--var-name)" */ varMatch,
19
+ /** the variable name - match of the second group "--var-name" */ cssVarName
20
+ ) => {
21
+ const value = names[cssVarName];
22
+ if (value && value.startsWith('var')) {
23
+ return getFallbackVariable(value, names);
24
+ }
25
+ return value || varMatch;
26
+ }
27
+ );
28
+ }
29
+ if (variable) {
30
+ return variable;
31
+ }
32
+
33
+ return;
34
+ }
@@ -0,0 +1,13 @@
1
+ import ts from 'typescript';
2
+ import crypto from 'node:crypto';
3
+
4
+ import {TransformerContext} from './types';
5
+
6
+ export function getHash(node: ts.Node, context: TransformerContext) {
7
+ const fileName = context.getFileName(node.getSourceFile().fileName);
8
+ return crypto
9
+ .createHash('md5')
10
+ .update(fileName + node.pos) // file name + position should be unique and repeatable
11
+ .digest('hex')
12
+ .substring(0, 6);
13
+ }
@@ -0,0 +1,32 @@
1
+ import ts from 'typescript';
2
+
3
+ /**
4
+ * This function returns a calculated name of a node by walking up the AST and looking for nodes
5
+ * with a `name` property that has an `Identifier` node type. The result is dash-case. This is
6
+ * useful for automatically generating variable names based on a TS file.
7
+ *
8
+ * In the following example, the `baz` node would have a name of `foo-bar-baz`.
9
+ * ```ts
10
+ * const foo = {
11
+ * bar: {
12
+ * baz: ''
13
+ * }
14
+ * }
15
+ * ```
16
+ */
17
+ export function getVarName(node: ts.Node, parts: string[] = []): string {
18
+ // base case. Join all the parts
19
+ if (!node.parent || node.kind === ts.SyntaxKind.VariableStatement) {
20
+ return parts.join('.');
21
+ }
22
+
23
+ // Any node with a `name` property that is an identifier can add to the var name
24
+ if (
25
+ (node as any).name &&
26
+ (ts.isIdentifier((node as any).name) || ts.isStringLiteral((node as any).name))
27
+ ) {
28
+ return getVarName(node.parent, [(node as any).name.text, ...parts]);
29
+ }
30
+
31
+ return getVarName(node.parent, parts);
32
+ }
@@ -0,0 +1,33 @@
1
+ import ts from 'typescript';
2
+
3
+ import {calc} from '@workday/canvas-kit-styling';
4
+ import {createPropertyTransform} from '../createPropertyTransform';
5
+ import {parseNodeToStaticValue} from './parseNodeToStaticValue';
6
+
7
+ export const handleCalc = createPropertyTransform((node, context) => {
8
+ if (
9
+ ts.isCallExpression(node) &&
10
+ ts.isPropertyAccessExpression(node.expression) &&
11
+ ts.isIdentifier(node.expression.expression) &&
12
+ node.expression.expression.text === 'calc' &&
13
+ ts.isIdentifier(node.expression.name)
14
+ ) {
15
+ function toStaticValue(node: ts.Node) {
16
+ return parseNodeToStaticValue(node, context);
17
+ }
18
+ const args = node.arguments;
19
+ const method = node.expression.name.text;
20
+
21
+ if (method === 'add' || method === 'subtract') {
22
+ return calc[method](toStaticValue(args[0]).toString(), toStaticValue(args[1]).toString());
23
+ }
24
+ if (method === 'multiply' || method === 'divide') {
25
+ return calc[method](toStaticValue(args[0]).toString(), toStaticValue(args[1]));
26
+ }
27
+ if (method === 'negate') {
28
+ return calc.negate(toStaticValue(args[0]).toString());
29
+ }
30
+ }
31
+
32
+ return;
33
+ });