@workday/canvas-kit-styling-transform 10.3.16 → 11.0.0-alpha.590-next.0

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.
@@ -0,0 +1,3 @@
1
+ import styleTransformer from './lib/styleTransform';
2
+ export default styleTransformer;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../index.ts"],"names":[],"mappings":"AAAA,OAAO,gBAAgB,MAAM,sBAAsB,CAAC;AAEpD,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const styleTransform_1 = __importDefault(require("./lib/styleTransform"));
7
+ exports.default = styleTransform_1.default;
@@ -0,0 +1,5 @@
1
+ import { Element } from 'stylis';
2
+ export declare function getVariablesFromFiles(files: string[]): Record<string, string>;
3
+ export declare function extractVariables(blocks: Element[] | string, variables?: Record<string, string>): Record<string, string>;
4
+ export declare function getFallbackVariable(variableName: string, variables: Record<string, string>): string | undefined;
5
+ //# sourceMappingURL=getCssVariables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getCssVariables.d.ts","sourceRoot":"","sources":["../../../lib/getCssVariables.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,OAAO,EAAC,MAAM,QAAQ,CAAC;AAExC,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAK7E;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,EAC1B,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACrC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAuBxB;AAED,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,MAAM,GAAG,SAAS,CAwBpB"}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getFallbackVariable = exports.extractVariables = exports.getVariablesFromFiles = void 0;
4
+ const stylis_1 = require("stylis");
5
+ function getVariablesFromFiles(files) {
6
+ return files.reduce((result, file) => {
7
+ extractVariables(stylis_1.compile(file));
8
+ return { ...result, ...extractVariables(stylis_1.compile(file)) };
9
+ }, {});
10
+ }
11
+ exports.getVariablesFromFiles = getVariablesFromFiles;
12
+ function extractVariables(blocks, variables = {}) {
13
+ if (typeof blocks === 'string') {
14
+ return variables;
15
+ }
16
+ return blocks
17
+ .filter(block => block.type === 'rule')
18
+ .reduce((result, rule) => {
19
+ if (Array.isArray(rule.children)) {
20
+ rule.children.forEach(child => {
21
+ if (typeof child.props === 'string' &&
22
+ child.props.startsWith('--') &&
23
+ typeof child.children === 'string') {
24
+ result[child.props] = child.children;
25
+ }
26
+ });
27
+ }
28
+ return result;
29
+ }, { ...variables });
30
+ }
31
+ exports.extractVariables = extractVariables;
32
+ function getFallbackVariable(variableName, variables) {
33
+ const variable = variableName.includes('var(') ? variableName : variables[variableName];
34
+ if (variable && variable.includes('var(')) {
35
+ return variable.replace(/(var\(([A-Za-z0-9\-_]+)\))/, (
36
+ /** matched substring "var(--var-name)" */ _,
37
+ /** the full match of the first group "var(--var-name)" */ varMatch,
38
+ /** the variable name - match of the second group "--var-name" */ cssVarName, ...args) => {
39
+ const value = variables[cssVarName];
40
+ if (value && value.startsWith('var')) {
41
+ return getFallbackVariable(value, variables);
42
+ }
43
+ return value || varMatch;
44
+ });
45
+ }
46
+ if (variable) {
47
+ return variable;
48
+ }
49
+ return;
50
+ }
51
+ exports.getFallbackVariable = getFallbackVariable;
@@ -0,0 +1,12 @@
1
+ import ts from 'typescript';
2
+ export declare type NestedStyleObject = {
3
+ [key: string]: string | NestedStyleObject;
4
+ };
5
+ export interface StyleTransformerOptions {
6
+ prefix: string;
7
+ variables: Record<string, string>;
8
+ fallbackFiles?: string[];
9
+ }
10
+ export default function styleTransformer(program: ts.Program, { prefix, variables, fallbackFiles }?: Partial<StyleTransformerOptions>): ts.TransformerFactory<ts.SourceFile>;
11
+ export declare function transform(program: ts.Program, fileName: string, options?: Partial<StyleTransformerOptions>): string;
12
+ //# sourceMappingURL=styleTransform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styleTransform.d.ts","sourceRoot":"","sources":["../../../lib/styleTransform.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,YAAY,CAAC;AAe5B,oBAAY,iBAAiB,GAAG;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,iBAAiB,CAAA;CAAC,CAAC;AAmZ5E,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,CAAC,OAAO,UAAU,gBAAgB,CACtC,OAAO,EAAE,EAAE,CAAC,OAAO,EACnB,EAAC,MAAc,EAAE,SAAc,EAAE,aAAa,EAAC,GAAE,OAAO,CAAC,uBAAuB,CAG/E,GACA,EAAE,CAAC,kBAAkB,CAAC,EAAE,CAAC,UAAU,CAAC,CAgLtC;AAGD,wBAAgB,SAAS,CACvB,OAAO,EAAE,EAAE,CAAC,OAAO,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,OAAO,CAAC,uBAAuB,CAAC,UAY3C"}
@@ -0,0 +1,545 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.transform = void 0;
7
+ /// <reference types="node" />
8
+ const typescript_1 = __importDefault(require("typescript"));
9
+ const serialize_1 = require("@emotion/serialize");
10
+ const canvas_tokens_web_1 = require("@workday/canvas-tokens-web");
11
+ const node_path_1 = __importDefault(require("node:path"));
12
+ const canvas_kit_styling_1 = require("@workday/canvas-kit-styling");
13
+ const getCssVariables_1 = require("./getCssVariables");
14
+ const styleExpressionName = 'createStyles';
15
+ const cssVarExpressionName = 'cssVar';
16
+ const createVarExpressionName = 'createVars';
17
+ const styleImportString = '@workday/canvas-kit-styling';
18
+ const vars = {};
19
+ function getStyleValueFromType(node, type, checker) {
20
+ const value = getCSSValueAtLocation(node, checker, type);
21
+ if (value) {
22
+ if (value.startsWith('--')) {
23
+ return `var(${value})`;
24
+ }
25
+ return value;
26
+ }
27
+ const typeValue = checker.typeToString(type);
28
+ throw new Error(`Unknown type at: "${node.getText()}". Received "${typeValue}"\n${getErrorMessage(node)}\nFor static analysis of styles, please make sure all types resolve to string or numeric literals. Please use 'const' instead of 'let'. If using an object, cast using "as const" or use an interface with string or numeric literals.`);
29
+ }
30
+ /**
31
+ * A `PropertyExpression` is an expression with a dot in it. Like `a.b.c`. It may be nested. This
32
+ * function will walk the AST and create a string like `a.b.c` to be passed on to variable name
33
+ * generation. This will be used for CSS variable lookups.
34
+ */
35
+ function getPropertyAccessExpressionText(node) {
36
+ if (typescript_1.default.isIdentifier(node.name)) {
37
+ if (typescript_1.default.isIdentifier(node.expression)) {
38
+ return `${node.expression.text}.${node.name.text}`;
39
+ }
40
+ if (typescript_1.default.isPropertyAccessExpression(node.expression)) {
41
+ return `${getPropertyAccessExpressionText(node.expression)}.${node.name.text}`;
42
+ }
43
+ }
44
+ return '';
45
+ }
46
+ function parseStyleObjValue(initializer, variables, checker) {
47
+ /**
48
+ * String literals like 'red' or empty Template Expressions like `red`
49
+ */
50
+ if (typescript_1.default.isStringLiteral(initializer) || typescript_1.default.isNoSubstitutionTemplateLiteral(initializer)) {
51
+ return initializer.text;
52
+ }
53
+ // numeric literal values like `12`
54
+ if (typescript_1.default.isNumericLiteral(initializer)) {
55
+ return `${initializer.text}px`;
56
+ }
57
+ // The source file is using an identifier which will be known at runtime, we'll try to
58
+ // determine the type
59
+ if (typescript_1.default.isIdentifier(initializer)) {
60
+ const type = checker.getTypeAtLocation(initializer);
61
+ return getStyleValueFromType(initializer, type, checker);
62
+ }
63
+ /**
64
+ * ```ts
65
+ * PropertyAccessExpressions are dot-notation
66
+ *
67
+ * foo.bar.baz
68
+ * ```
69
+ */
70
+ if (typescript_1.default.isPropertyAccessExpression(initializer)) {
71
+ const type = checker.getTypeAtLocation(initializer);
72
+ return getStyleValueFromType(initializer, type, checker);
73
+ }
74
+ /**
75
+ * This will find patterns like:
76
+ *
77
+ * ```ts
78
+ * cssVar(myVars.color);
79
+ * cssVar(myVars.colors.background);
80
+ * cssVar(myVars.colors.background, 'red')
81
+ * ```
82
+ */
83
+ if (typescript_1.default.isCallExpression(initializer) &&
84
+ typescript_1.default.isIdentifier(initializer.expression) &&
85
+ initializer.expression.text === cssVarExpressionName) {
86
+ const value = getCSSValueAtLocation(initializer.arguments[0], checker);
87
+ const value2 = initializer.arguments[1]
88
+ ? parseStyleObjValue(initializer.arguments[1], variables, checker)
89
+ : undefined;
90
+ // handle fallback variables
91
+ const fallbackValue = getCssVariables_1.getFallbackVariable(value, variables);
92
+ if (value && (value2 || fallbackValue)) {
93
+ return `var(${value}, ${((value2 === null || value2 === void 0 ? void 0 : value2.startsWith('--')) ? `var(${value2})` : value2) || fallbackValue})`;
94
+ }
95
+ if (value) {
96
+ return `var(${value})`;
97
+ }
98
+ }
99
+ /**
100
+ * ```ts
101
+ * `border 1px ${myVars.colors.border}`
102
+ * ```
103
+ */
104
+ if (typescript_1.default.isTemplateExpression(initializer)) {
105
+ return getStyleValueFromTemplateExpression(initializer, variables, checker);
106
+ }
107
+ return '';
108
+ }
109
+ /**
110
+ * Gets a static string value from a template expression. It could recurse.
111
+ */
112
+ function getStyleValueFromTemplateExpression(node, variables, checker) {
113
+ if (!node) {
114
+ return '';
115
+ }
116
+ if (typescript_1.default.isTemplateExpression(node)) {
117
+ return (getStyleValueFromTemplateExpression(node.head, variables, checker) +
118
+ node.templateSpans
119
+ .map(value => getStyleValueFromTemplateExpression(value, variables, checker))
120
+ .join(''));
121
+ }
122
+ if (typescript_1.default.isTemplateHead(node) || typescript_1.default.isTemplateTail(node) || typescript_1.default.isTemplateMiddle(node)) {
123
+ return node.text;
124
+ }
125
+ if (typescript_1.default.isTemplateSpan(node)) {
126
+ return (parseStyleObjValue(node.expression, variables, checker) +
127
+ getStyleValueFromTemplateExpression(node.literal, variables, checker));
128
+ }
129
+ return '';
130
+ }
131
+ /**
132
+ * Gets a CSS value from an AST node
133
+ */
134
+ function getCSSValueAtLocation(node, checker,
135
+ /**
136
+ * Optional type. This works for cases where the node is a TypeNode or TypeScript infers the Type
137
+ * via a generic resolution. For example:
138
+ * ```ts
139
+ * function someFn<T extends string>(input: T): {fontSize: T} {
140
+ * return { fontSize: input }
141
+ * }
142
+ *
143
+ * // in styles
144
+ * ...someFn('12px')
145
+ * ```
146
+ *
147
+ * If we don't pass a type of the property given by `type.getProperties()`, TypeScript will
148
+ * resolve the type at the value node as `T` instead of `12px`. Allowing for a type override is
149
+ * useful when the caller may have more context about the type at a given node than we do.
150
+ */
151
+ type = checker.getTypeAtLocation(node)) {
152
+ const varsKey = getVarsKeyFromNode(node);
153
+ if (vars[varsKey]) {
154
+ return vars[varsKey];
155
+ }
156
+ if (type.isStringLiteral()) {
157
+ // This isn't a component variable, it is a static CSS variable
158
+ return type.value;
159
+ }
160
+ if (type.isNumberLiteral()) {
161
+ return `${type.value}px`;
162
+ }
163
+ if (node && typescript_1.default.isPropertyAccessExpression(node)) {
164
+ return getPropertyAccessExpressionText(node);
165
+ }
166
+ return '';
167
+ }
168
+ function getModuleSpecifierFromDeclaration(node) {
169
+ if (!node) {
170
+ return undefined;
171
+ }
172
+ if (typescript_1.default.isImportSpecifier(node) && typescript_1.default.isStringLiteral(node.parent.parent.parent.moduleSpecifier)) {
173
+ return node.parent.parent.parent.moduleSpecifier.text;
174
+ }
175
+ return undefined;
176
+ }
177
+ function getStyleFromProperty(property, prefix, variables, checker) {
178
+ if (typescript_1.default.isPropertyAssignment(property)) {
179
+ // All properties should be non-objects
180
+ // {foo: 'bar'}
181
+ if (typescript_1.default.isIdentifier(property.name)) {
182
+ const value = parseStyleObjValue(property.initializer, variables, checker);
183
+ if (value) {
184
+ return { [property.name.text]: value };
185
+ }
186
+ }
187
+ if (typescript_1.default.isComputedPropertyName(property.name)) {
188
+ if (typescript_1.default.isPropertyAccessExpression(property.name.expression)) {
189
+ const value = parseStyleObjValue(property.initializer, variables, checker);
190
+ if (value) {
191
+ // test if the property is a static value
192
+ getPropertyAccessExpressionText(property.name.expression);
193
+ const type = checker.getTypeAtLocation(property.name.expression);
194
+ checker.typeToString(type);
195
+ if (type.isStringLiteral()) {
196
+ return { [type.value]: value };
197
+ }
198
+ else {
199
+ const expressionText = getPropertyAccessExpressionText(property.name.expression);
200
+ const [id, name] = getVariableNameParts(expressionText);
201
+ return { [`--${prefix}-${canvas_kit_styling_1.slugify(id)}-${name}`]: value };
202
+ }
203
+ }
204
+ }
205
+ }
206
+ // String literal property names are special selectors with more styles
207
+ // {'&:hover': {}}
208
+ if (typescript_1.default.isStringLiteral(property.name)) {
209
+ return {
210
+ [property.name.text]: parseStyleObjFromNode(property.initializer, prefix, variables, checker),
211
+ };
212
+ }
213
+ }
214
+ /**
215
+ * A spread assignment looks like:
216
+ *
217
+ * ```ts
218
+ * {
219
+ * ...styles
220
+ * }
221
+ * ```
222
+ *
223
+ * https://ts-ast-viewer.com/#code/MYewdgzgLgBFCmBbADjAvDA3gMxCAXDAOQBGAhgE5EC+AUKJLAigEzpYB0Xzy1QA
224
+ */
225
+ if (typescript_1.default.isSpreadAssignment(property)) {
226
+ // Detect `focusRing` calls. This is temporary until we figure out a better way to do focus
227
+ // rings that doesn't require a special entry in the transform function.
228
+ //
229
+ // TODO: implement a fully working type resolver for CSS variables or remove support for them an
230
+ // remove all uses of `focusRing` from new styling code
231
+ if (typescript_1.default.isCallExpression(property.expression) &&
232
+ typescript_1.default.isIdentifier(property.expression.expression) &&
233
+ property.expression.expression.text === 'focusRing') {
234
+ const argumentObject = property.expression.arguments[0];
235
+ // defaults
236
+ const defaults = {
237
+ width: '2px',
238
+ separation: '0px',
239
+ inset: undefined,
240
+ innerColor: `var(${canvas_tokens_web_1.base.frenchVanilla100}, rgba(255,255,255,1))`,
241
+ outerColor: `var(${canvas_tokens_web_1.brand.common.focusOutline}, rgba(8,117,225,1))`,
242
+ };
243
+ if (argumentObject && typescript_1.default.isObjectLiteralExpression(argumentObject)) {
244
+ argumentObject.properties.forEach(property => {
245
+ if (typescript_1.default.isPropertyAssignment(property) && typescript_1.default.isIdentifier(property.name)) {
246
+ defaults[property.name.text] = parseStyleObjValue(property.initializer, variables, checker);
247
+ }
248
+ });
249
+ let boxShadow;
250
+ switch (defaults.inset) {
251
+ case 'outer':
252
+ boxShadow = `inset 0 0 0 ${defaults.separation} ${defaults.outerColor}, inset 0 0 0 calc(${defaults.width} + ${defaults.separation}) ${defaults.innerColor}`;
253
+ break;
254
+ case 'inner':
255
+ boxShadow = `inset 0 0 0 ${defaults.separation} ${defaults.innerColor}, 0 0 0 ${defaults.width} ${defaults.outerColor}`;
256
+ break;
257
+ default:
258
+ boxShadow = `0 0 0 ${defaults.separation} ${defaults.innerColor}, 0 0 0 calc(${defaults.width} + ${defaults.separation}) ${defaults.outerColor}`;
259
+ break;
260
+ }
261
+ return { boxShadow };
262
+ }
263
+ }
264
+ // Spread assignments are a bit complicated to use the AST to figure out, so we'll ask the
265
+ // TypeScript type checker.
266
+ const type = checker.getTypeAtLocation(property.expression);
267
+ checker.typeToString(type); //?
268
+ return parseStyleObjFromType(type, prefix, variables, checker);
269
+ }
270
+ return {};
271
+ }
272
+ /**
273
+ * If we're here, we have a `ts.Type` that represents a style object. We try to parse a style object
274
+ * from the AST, but we might have something that is more complicated like a function call or an
275
+ * identifier that represents an object. It could be imported from another file.
276
+ */
277
+ function parseStyleObjFromType(type, prefix, variables, checker) {
278
+ const styleObj = {};
279
+ // Gets all the properties of the type object
280
+ return type.getProperties().reduce((result, property) => {
281
+ const declaration = property.declarations[0];
282
+ if (declaration) {
283
+ const propType = checker.getTypeOfSymbolAtLocation(property, declaration);
284
+ return {
285
+ ...result,
286
+ [property.name]: getStyleValueFromType(declaration, propType, checker),
287
+ };
288
+ }
289
+ return result;
290
+ }, styleObj);
291
+ }
292
+ /**
293
+ * If the node is an `ObjectLiteralExpression`, we'll walk the `properties` of the AST node and
294
+ * create a style object for each property we find.
295
+ */
296
+ function parseStyleObjFromNode(node, prefix, variables, checker) {
297
+ const styleObj = {};
298
+ if (typescript_1.default.isObjectLiteralExpression(node)) {
299
+ return node.properties.reduce((result, property) => {
300
+ return { ...result, ...getStyleFromProperty(property, prefix, variables, checker) };
301
+ }, styleObj);
302
+ }
303
+ return styleObj;
304
+ }
305
+ /**
306
+ * Creates an AST node representation of the passed in `styleObj`, but in the format of `{name:
307
+ * string, styles: serializedStyles}`. The `name` is hard-coded here to work with both server-side
308
+ * and client-side style injection. This results in a stable style key for Emotion while also
309
+ * optimizing style serialization.
310
+ */
311
+ function createStyleObjectNode(styleObj) {
312
+ const serialized = serialize_1.serializeStyles([styleObj]);
313
+ const styleText = serialized.styles;
314
+ const styleExpression = typescript_1.default.factory.createStringLiteral(styleText);
315
+ // create an emotion-optimized object: https://github.com/emotion-js/emotion/blob/f3b268f7c52103979402da919c9c0dd3f9e0e189/packages/serialize/src/index.js#L315-L322
316
+ // Looks like: `{name: $hash, styles: $styleText }`
317
+ return typescript_1.default.factory.createObjectLiteralExpression([
318
+ typescript_1.default.factory.createPropertyAssignment(typescript_1.default.factory.createIdentifier('name'),
319
+ // TODO - we may need this to be a static variable for the CSS package
320
+ typescript_1.default.factory.createStringLiteral(canvas_kit_styling_1.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
321
+ ),
322
+ typescript_1.default.factory.createPropertyAssignment(typescript_1.default.factory.createIdentifier('styles'), 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
323
+ ),
324
+ ], false);
325
+ }
326
+ function styleTransformer(program, { prefix = 'css', variables = {}, fallbackFiles } = {
327
+ prefix: 'css',
328
+ variables: {},
329
+ }) {
330
+ if (fallbackFiles) {
331
+ const files = fallbackFiles
332
+ .filter(file => file) // don't process empty files
333
+ .map(file => {
334
+ // Find the fully-qualified path name. This could error which should give "module not found" errors
335
+ return file.startsWith('.') ? node_path_1.default.resolve(process.cwd(), file) : require.resolve(file);
336
+ })
337
+ .map(file => typescript_1.default.sys.readFile(file) || '');
338
+ // eslint-disable-next-line no-param-reassign
339
+ variables = getCssVariables_1.getVariablesFromFiles(files);
340
+ }
341
+ const checker = program.getTypeChecker();
342
+ return context => {
343
+ const visit = node => {
344
+ // eslint-disable-next-line no-param-reassign
345
+ node = typescript_1.default.visitEachChild(node, visit, context);
346
+ /**
347
+ * Check if the node is a call expression that looks like:
348
+ *
349
+ * ```ts
350
+ * createStyles({
351
+ * // properties
352
+ * })
353
+ * ```
354
+ *
355
+ * It will also make sure the `createStyles` function was imported from
356
+ * `@workday/canvas-kit-styling` to ensure we don't rewrite the AST of code we don't own.
357
+ *
358
+ * This transformation will pre-serialize the style objects and turn them into strings for
359
+ * faster runtime processing in Emotion. The following is an example of the transformation.
360
+ *
361
+ * ```ts
362
+ * // before transformation
363
+ * const myStyles = createStyles({
364
+ * fontSize: '1rem'
365
+ * })
366
+ *
367
+ * // after transformation
368
+ * const myStyles = createStyles({
369
+ * name: 'abc123',
370
+ * styles: 'font-size: 1rem;'
371
+ * })
372
+ * ```
373
+ *
374
+ * The after transformation already serialized the styles and goes through a shortcut process
375
+ * in `@emotion/css` where only the Emotion cache is checked and styles are inserted if the
376
+ * cache key wasn't found.
377
+ */
378
+ if (typescript_1.default.isCallExpression(node) &&
379
+ typescript_1.default.isIdentifier(node.expression) &&
380
+ node.expression.text === styleExpressionName &&
381
+ node.arguments.length > 0) {
382
+ // get the declaration of the symbol of the styleExpression
383
+ const symbol = checker.getSymbolAtLocation(node.expression);
384
+ const declaration = symbol === null || symbol === void 0 ? void 0 : symbol.declarations[0];
385
+ if (getModuleSpecifierFromDeclaration(declaration) === styleImportString) {
386
+ const newArguments = [...node.arguments].map(arg => {
387
+ // An `ObjectLiteralExpression` is an object like `{foo:'bar'}`:
388
+ // https://ts-ast-viewer.com/#code/MYewdgzgLgBFCmBbADjAvDA3gKBjAZiCAFwwDkARgIYBOZ2AvkA
389
+ if (typescript_1.default.isObjectLiteralExpression(arg)) {
390
+ const styleObj = parseStyleObjFromNode(arg, prefix, variables, checker);
391
+ return createStyleObjectNode(styleObj);
392
+ }
393
+ // An Identifier is a variable. It could come from anywhere - imports, earlier
394
+ // assignments, etc. The easiest thing to do is to ask the TypeScript type checker what
395
+ // the type representation is and go from there.
396
+ if (typescript_1.default.isIdentifier(arg)) {
397
+ const type = checker.getTypeAtLocation(arg);
398
+ // `createStyles` accepts strings as class names. If the class name is
399
+ if (type.isStringLiteral() || type.getFlags() & typescript_1.default.TypeFlags.String) {
400
+ return arg;
401
+ }
402
+ // The type must be a object
403
+ const styleObj = parseStyleObjFromType(type, prefix, variables, checker);
404
+ return createStyleObjectNode(styleObj);
405
+ }
406
+ return arg;
407
+ });
408
+ newArguments.forEach(argument => {
409
+ // TypeScript isn't expecting us to mutate arguments arguments and when emitting will
410
+ // try to do something where it checks the `parent` node of the argument. Using
411
+ // `ts.factory.create*`, the `parent` is `undefined` and this check will throw an error.
412
+ // In order to get past this error, we manually update the `parent` node of each
413
+ // argument to reference the existing call expression. This allows TypeScript to fully
414
+ // type check and/or emit.
415
+ argument.parent = node;
416
+ });
417
+ /**
418
+ * We're not supposed to mutate arguments since it is supposed to be read-only. But, if I
419
+ * return a new callExpression, there is no parent and it is no longer linked to the
420
+ * import module. This causes incorrect code when the module export type is `commonjs`.
421
+ * For example:
422
+ *
423
+ * ```ts
424
+ * // with new callExpression
425
+ * const canvas_kit_styling_1 = require(...)
426
+ *
427
+ * createStyles({...})
428
+ *
429
+ * // if we instead mutate arguments
430
+ * const canvas_kit_styling_1 = require(...)
431
+ *
432
+ * canvas_kit_styling_1.createStyles({...})
433
+ * ```
434
+ *
435
+ * My best guess as to why it fails when creating a new callExpression is the node's
436
+ * symbol declaration link gets lost. TypeScript then has no idea `createStyles` comes
437
+ * from an `ImportDeclaration` declaration node and when emitting `commonjs`, it doesn't
438
+ * prefix with the `canvas_kit_styling_1`. This is hacky, but the only thing that works
439
+ * correctly.
440
+ */
441
+ node.arguments = newArguments;
442
+ return node;
443
+ }
444
+ }
445
+ /**
446
+ * This will create a variable
447
+ */
448
+ if (typescript_1.default.isCallExpression(node) &&
449
+ typescript_1.default.isIdentifier(node.expression) &&
450
+ node.expression.text === createVarExpressionName) {
451
+ const id = canvas_kit_styling_1.slugify(getVarName(node));
452
+ const variables = node.arguments
453
+ .map(arg => typescript_1.default.isStringLiteral(arg) && arg.text)
454
+ .filter(Boolean);
455
+ variables.forEach(v => {
456
+ vars[`${id}-${v}`] = `--${prefix}-${id}-${v}`;
457
+ });
458
+ return typescript_1.default.factory.createCallExpression(node.expression, [], [
459
+ typescript_1.default.factory.createObjectLiteralExpression([
460
+ typescript_1.default.factory.createPropertyAssignment(typescript_1.default.factory.createIdentifier('id'), typescript_1.default.factory.createStringLiteral(`${prefix}-${id}`)),
461
+ typescript_1.default.factory.createPropertyAssignment(typescript_1.default.factory.createIdentifier('args'), typescript_1.default.factory.createArrayLiteralExpression(variables.map(val => typescript_1.default.factory.createStringLiteral(val)), false)),
462
+ ], false),
463
+ ]);
464
+ }
465
+ return node;
466
+ };
467
+ return node => typescript_1.default.visitNode(node, visit);
468
+ };
469
+ }
470
+ exports.default = styleTransformer;
471
+ // This should only be used for tests
472
+ function transform(program, fileName, options) {
473
+ const source = program.getSourceFile(fileName) || typescript_1.default.createSourceFile(fileName, '', typescript_1.default.ScriptTarget.ES2019);
474
+ const printer = typescript_1.default.createPrinter();
475
+ return printer.printFile(typescript_1.default
476
+ .transform(source, [styleTransformer(program, options)])
477
+ .transformed.find(s => (s.fileName = fileName)) || source);
478
+ }
479
+ exports.transform = transform;
480
+ function getVarName(node) {
481
+ const parent = node.parent;
482
+ if (typescript_1.default.isVariableDeclaration(parent) && typescript_1.default.isIdentifier(parent.name)) {
483
+ return parent.name.text;
484
+ }
485
+ if (typescript_1.default.isPropertyAssignment(parent) && typescript_1.default.isIdentifier(parent.name)) {
486
+ return `${getVarName(parent.parent)}-${parent.name.text}`;
487
+ }
488
+ return '';
489
+ }
490
+ /**
491
+ * Creates an error message around a node. It will look something like:
492
+ *
493
+ * ```
494
+ * Unknown type at: "fontSize".
495
+ * File: test.ts, Line: 6, Character: 17.
496
+ * const styles = createStyles({
497
+ * fontSize: fontSize
498
+ * ========
499
+ * })
500
+ * ```
501
+ */
502
+ function getErrorMessage(node) {
503
+ const sourceFile = node.getSourceFile();
504
+ const { line } = node.getSourceFile().getLineAndCharacterOfPosition(node.pos);
505
+ const lineStarts = sourceFile.getLineStarts();
506
+ const lineStartIndex = lineStarts.findIndex(s => s >= node.pos) - 1;
507
+ // get a whole line's text given a lineStarts index
508
+ function getLine(sourceFile, startIndex) {
509
+ const lineStarts = sourceFile.getLineStarts();
510
+ return sourceFile.text.substring(lineStarts[Math.max(0, startIndex)], startIndex + 1 >= lineStarts.length ? undefined : lineStarts[startIndex + 1]);
511
+ }
512
+ // Create a full context message with source code and highlighting
513
+ const lineBefore = getLine(sourceFile, lineStartIndex - 1);
514
+ const lineCurrent = getLine(sourceFile, lineStartIndex);
515
+ const lineAfter = getLine(sourceFile, lineStartIndex + 1);
516
+ const highlightedLine = ''
517
+ .padStart(node.getStart() - lineStarts[lineStartIndex], ' ')
518
+ .padEnd(node.getStart() - lineStarts[lineStartIndex] + node.getWidth(), '=') + '\n';
519
+ /** This should look something like:
520
+ * ```
521
+ * const styles = createStyles({
522
+ * fontSize: fontSize
523
+ * ========
524
+ * })
525
+ * ```
526
+ */
527
+ const fullContext = lineBefore + lineCurrent + highlightedLine + lineAfter;
528
+ const character = node.getStart() - lineStarts[lineStartIndex] + 1;
529
+ return `File: ${sourceFile.fileName}:${line + 1}:${character}.\n${fullContext}`;
530
+ }
531
+ function getVariableNameParts(input) {
532
+ const parts = input.split('.');
533
+ // grab the last item in the array. This will also mutate the array, removing the last item
534
+ const variable = parts.pop();
535
+ return [parts.join('.'), variable];
536
+ }
537
+ function getVarsKeyFromNode(node) {
538
+ if (typescript_1.default.isIdentifier(node)) {
539
+ return canvas_kit_styling_1.slugify(node.text);
540
+ }
541
+ if (typescript_1.default.isPropertyAccessExpression(node) && typescript_1.default.isIdentifier(node.name)) {
542
+ return `${getVarsKeyFromNode(node.expression)}-${node.name.text}`;
543
+ }
544
+ return '';
545
+ }
@@ -0,0 +1,3 @@
1
+ import styleTransformer from './lib/styleTransform';
2
+ export default styleTransformer;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../index.ts"],"names":[],"mappings":"AAAA,OAAO,gBAAgB,MAAM,sBAAsB,CAAC;AAEpD,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import styleTransformer from './lib/styleTransform';
2
+ export default styleTransformer;
@@ -0,0 +1,5 @@
1
+ import { Element } from 'stylis';
2
+ export declare function getVariablesFromFiles(files: string[]): Record<string, string>;
3
+ export declare function extractVariables(blocks: Element[] | string, variables?: Record<string, string>): Record<string, string>;
4
+ export declare function getFallbackVariable(variableName: string, variables: Record<string, string>): string | undefined;
5
+ //# sourceMappingURL=getCssVariables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getCssVariables.d.ts","sourceRoot":"","sources":["../../../lib/getCssVariables.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,OAAO,EAAC,MAAM,QAAQ,CAAC;AAExC,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAK7E;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,EAC1B,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACrC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAuBxB;AAED,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,MAAM,GAAG,SAAS,CAwBpB"}