@atlaskit/tokens 1.49.1 → 1.50.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.
- package/CHANGELOG.md +1584 -1594
- package/README.md +14 -8
- package/codemods/css-to-design-tokens/lib/colors.tsx +47 -49
- package/codemods/css-to-design-tokens/lib/declaration.tsx +26 -26
- package/codemods/css-to-design-tokens/lib/legacy-colors.tsx +326 -326
- package/codemods/css-to-design-tokens/lib/meta.tsx +116 -122
- package/codemods/css-to-design-tokens/lib/tokens.tsx +28 -35
- package/codemods/css-to-design-tokens/lib/value.tsx +70 -72
- package/codemods/css-to-design-tokens/transform.tsx +68 -72
- package/codemods/hypermod.config.tsx +5 -5
- package/codemods/remove-fallbacks-color/transform.tsx +16 -18
- package/codemods/theme-to-design-tokens/transform.tsx +505 -588
- package/codemods/theme-to-design-tokens/utils/ast-meta.tsx +139 -147
- package/codemods/theme-to-design-tokens/utils/ast.tsx +23 -34
- package/codemods/theme-to-design-tokens/utils/color.tsx +25 -26
- package/codemods/theme-to-design-tokens/utils/css-utils.tsx +27 -30
- package/codemods/theme-to-design-tokens/utils/fuzzy-search.tsx +272 -290
- package/codemods/theme-to-design-tokens/utils/legacy-colors.tsx +224 -224
- package/codemods/theme-to-design-tokens/utils/named-colors.tsx +148 -148
- package/codemods/theme-to-design-tokens/utils/string-utils.tsx +10 -16
- package/codemods/utils/tokens.tsx +371 -371
- package/dist/cjs/artifacts/atlassian-dark-token-value-for-contrast-check.js +1 -1
- package/dist/cjs/artifacts/atlassian-light-token-value-for-contrast-check.js +1 -1
- package/dist/cjs/artifacts/generated-pairs.js +1 -1
- package/dist/cjs/artifacts/theme-import-map.js +1 -1
- package/dist/cjs/artifacts/themes/atlassian-typography-minor3.js +2 -2
- package/dist/cjs/artifacts/token-default-values.js +1 -1
- package/dist/cjs/artifacts/token-names.js +1 -1
- package/dist/cjs/artifacts/tokens-raw/atlassian-typography-minor3.js +3 -3
- package/dist/es2019/artifacts/atlassian-dark-token-value-for-contrast-check.js +1 -1
- package/dist/es2019/artifacts/atlassian-light-token-value-for-contrast-check.js +1 -1
- package/dist/es2019/artifacts/generated-pairs.js +1 -1
- package/dist/es2019/artifacts/theme-import-map.js +1 -1
- package/dist/es2019/artifacts/themes/atlassian-typography-minor3.js +2 -2
- package/dist/es2019/artifacts/token-default-values.js +1 -1
- package/dist/es2019/artifacts/token-names.js +1 -1
- package/dist/es2019/artifacts/tokens-raw/atlassian-typography-minor3.js +3 -3
- package/dist/esm/artifacts/atlassian-dark-token-value-for-contrast-check.js +1 -1
- package/dist/esm/artifacts/atlassian-light-token-value-for-contrast-check.js +1 -1
- package/dist/esm/artifacts/generated-pairs.js +1 -1
- package/dist/esm/artifacts/theme-import-map.js +1 -1
- package/dist/esm/artifacts/themes/atlassian-typography-minor3.js +2 -2
- package/dist/esm/artifacts/token-default-values.js +1 -1
- package/dist/esm/artifacts/token-names.js +1 -1
- package/dist/esm/artifacts/tokens-raw/atlassian-typography-minor3.js +3 -3
- package/dist/types/artifacts/atlassian-dark-token-value-for-contrast-check.d.ts +1 -1
- package/dist/types/artifacts/atlassian-light-token-value-for-contrast-check.d.ts +1 -1
- package/dist/types/artifacts/generated-pairs.d.ts +1 -1
- package/dist/types/artifacts/theme-import-map.d.ts +2 -2
- package/dist/types/artifacts/themes/atlassian-typography-minor3.d.ts +2 -2
- package/dist/types/artifacts/token-default-values.d.ts +1 -1
- package/dist/types/artifacts/token-names.d.ts +1 -1
- package/dist/types/artifacts/tokens-raw/atlassian-typography-minor3.d.ts +1 -1
- package/dist/types/artifacts/types-internal.d.ts +1 -1
- package/dist/types/artifacts/types.d.ts +1 -1
- package/dist/types/babel-plugin/plugin.d.ts +1 -1
- package/dist/types/custom-theme.d.ts +2 -2
- package/dist/types/enable-global-theme.d.ts +2 -2
- package/dist/types/entry-points/css-type-schema.codegen.d.ts +1 -1
- package/dist/types/entry-points/token-ids.d.ts +1 -1
- package/dist/types/get-global-theme.d.ts +1 -1
- package/dist/types/get-ssr-auto-script.d.ts +1 -1
- package/dist/types/get-theme-html-attrs.d.ts +1 -1
- package/dist/types/get-theme-styles.d.ts +1 -1
- package/dist/types/get-token.d.ts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/load-custom-theme-styles.d.ts +1 -1
- package/dist/types/set-global-theme.d.ts +2 -2
- package/dist/types/theme-state-transformer.d.ts +1 -1
- package/dist/types/utils/color-detection.d.ts +1 -1
- package/dist/types/utils/color-mode-listeners.d.ts +1 -1
- package/dist/types/utils/configure-page.d.ts +1 -1
- package/dist/types/utils/contrast-mode-listeners.d.ts +1 -1
- package/dist/types/utils/custom-theme-loading-utils.d.ts +1 -1
- package/dist/types/utils/custom-theme-token-contrast-check.d.ts +1 -1
- package/dist/types/utils/generate-custom-color-ramp.d.ts +2 -2
- package/dist/types/utils/get-increased-contrast-theme.d.ts +1 -1
- package/dist/types/utils/get-theme-preferences.d.ts +1 -1
- package/dist/types/utils/theme-loading.d.ts +1 -1
- package/dist/types-ts4.5/artifacts/atlassian-dark-token-value-for-contrast-check.d.ts +1 -1
- package/dist/types-ts4.5/artifacts/atlassian-light-token-value-for-contrast-check.d.ts +1 -1
- package/dist/types-ts4.5/artifacts/generated-pairs.d.ts +1 -1
- package/dist/types-ts4.5/artifacts/theme-import-map.d.ts +2 -2
- package/dist/types-ts4.5/artifacts/themes/atlassian-typography-minor3.d.ts +2 -2
- package/dist/types-ts4.5/artifacts/token-default-values.d.ts +1 -1
- package/dist/types-ts4.5/artifacts/token-names.d.ts +1 -1
- package/dist/types-ts4.5/artifacts/tokens-raw/atlassian-typography-minor3.d.ts +1 -1
- package/dist/types-ts4.5/artifacts/types-internal.d.ts +1 -1
- package/dist/types-ts4.5/artifacts/types.d.ts +1 -1
- package/dist/types-ts4.5/babel-plugin/plugin.d.ts +1 -1
- package/dist/types-ts4.5/custom-theme.d.ts +2 -2
- package/dist/types-ts4.5/enable-global-theme.d.ts +2 -2
- package/dist/types-ts4.5/entry-points/css-type-schema.codegen.d.ts +1 -1
- package/dist/types-ts4.5/entry-points/token-ids.d.ts +1 -1
- package/dist/types-ts4.5/get-global-theme.d.ts +1 -1
- package/dist/types-ts4.5/get-ssr-auto-script.d.ts +1 -1
- package/dist/types-ts4.5/get-theme-html-attrs.d.ts +1 -1
- package/dist/types-ts4.5/get-theme-styles.d.ts +1 -1
- package/dist/types-ts4.5/get-token.d.ts +1 -1
- package/dist/types-ts4.5/index.d.ts +1 -1
- package/dist/types-ts4.5/load-custom-theme-styles.d.ts +1 -1
- package/dist/types-ts4.5/set-global-theme.d.ts +2 -2
- package/dist/types-ts4.5/theme-state-transformer.d.ts +1 -1
- package/dist/types-ts4.5/utils/color-detection.d.ts +1 -1
- package/dist/types-ts4.5/utils/color-mode-listeners.d.ts +1 -1
- package/dist/types-ts4.5/utils/configure-page.d.ts +1 -1
- package/dist/types-ts4.5/utils/contrast-mode-listeners.d.ts +1 -1
- package/dist/types-ts4.5/utils/custom-theme-loading-utils.d.ts +1 -1
- package/dist/types-ts4.5/utils/custom-theme-token-contrast-check.d.ts +1 -1
- package/dist/types-ts4.5/utils/generate-custom-color-ramp.d.ts +2 -2
- package/dist/types-ts4.5/utils/get-increased-contrast-theme.d.ts +1 -1
- package/dist/types-ts4.5/utils/get-theme-preferences.d.ts +1 -1
- package/dist/types-ts4.5/utils/theme-loading.d.ts +1 -1
- package/package.json +3 -5
- package/report.api.md +2071 -2090
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import { hasImportDeclaration, isDecendantOfType } from '@hypermod/utils';
|
|
3
|
-
import type {
|
|
4
|
-
API,
|
|
5
|
-
Collection,
|
|
6
|
-
FileInfo,
|
|
7
|
-
JSCodeshift,
|
|
8
|
-
TemplateElement,
|
|
9
|
-
} from 'jscodeshift';
|
|
3
|
+
import type { API, Collection, FileInfo, JSCodeshift, TemplateElement } from 'jscodeshift';
|
|
10
4
|
|
|
11
5
|
import CSSTransformer from '../css-to-design-tokens/transform';
|
|
12
6
|
import { activeTokens } from '../utils/tokens';
|
|
@@ -14,615 +8,538 @@ import { activeTokens } from '../utils/tokens';
|
|
|
14
8
|
import { isDecendantOfToken, isParentOfToken } from './utils/ast';
|
|
15
9
|
import { cleanMeta, getMetaFromAncestors } from './utils/ast-meta';
|
|
16
10
|
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
includesHardCodedColor,
|
|
12
|
+
isBoldColor,
|
|
13
|
+
isHardCodedColor,
|
|
14
|
+
isLegacyColor,
|
|
15
|
+
isLegacyNamedColor,
|
|
22
16
|
} from './utils/color';
|
|
23
|
-
import {
|
|
24
|
-
containsReplaceableCSSDeclarations,
|
|
25
|
-
findEndIndexOfCSSExpression,
|
|
26
|
-
} from './utils/css-utils';
|
|
17
|
+
import { containsReplaceableCSSDeclarations, findEndIndexOfCSSExpression } from './utils/css-utils';
|
|
27
18
|
import Search from './utils/fuzzy-search';
|
|
28
19
|
import { legacyColorMetaMap } from './utils/legacy-colors';
|
|
29
|
-
import {
|
|
30
|
-
findFirstNonspaceIndexAfter,
|
|
31
|
-
kebabize,
|
|
32
|
-
splitAtIndex,
|
|
33
|
-
} from './utils/string-utils';
|
|
20
|
+
import { findFirstNonspaceIndexAfter, kebabize, splitAtIndex } from './utils/string-utils';
|
|
34
21
|
|
|
35
22
|
function insertTokenImport(j: JSCodeshift, source: Collection<any>) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
23
|
+
if (hasImportDeclaration(j, source, '@atlaskit/tokens')) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
39
26
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
27
|
+
const newImport = j.importDeclaration(
|
|
28
|
+
[j.importSpecifier(j.identifier('token'))],
|
|
29
|
+
j.stringLiteral('@atlaskit/tokens'),
|
|
30
|
+
);
|
|
44
31
|
|
|
45
|
-
|
|
32
|
+
source.get().node.program.body.unshift(newImport);
|
|
46
33
|
}
|
|
47
34
|
|
|
48
35
|
function buildToken(j: JSCodeshift, tokenId: string, node: any) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
36
|
+
const callExpr = j.callExpression(
|
|
37
|
+
j.identifier('token'),
|
|
38
|
+
[j.stringLiteral(tokenId), node].filter(Boolean),
|
|
39
|
+
);
|
|
53
40
|
|
|
54
|
-
|
|
41
|
+
return callExpr;
|
|
55
42
|
}
|
|
56
43
|
|
|
57
44
|
// Wrap over the j.templateElement builder to provide a more convenient API.
|
|
58
45
|
function buildTemplateElement(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
46
|
+
j: JSCodeshift,
|
|
47
|
+
text: string,
|
|
48
|
+
options: { tail?: boolean; fromNode?: TemplateElement | null } = {
|
|
49
|
+
tail: false,
|
|
50
|
+
fromNode: null,
|
|
51
|
+
},
|
|
65
52
|
) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
53
|
+
let tail;
|
|
54
|
+
if (options.fromNode) {
|
|
55
|
+
tail = options.fromNode.tail;
|
|
56
|
+
} else {
|
|
57
|
+
tail = !!options.tail;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return j.templateElement({ raw: text, cooked: null }, tail);
|
|
74
61
|
}
|
|
75
62
|
|
|
76
63
|
function getColorFromIdentifier(expression: any) {
|
|
77
|
-
|
|
64
|
+
let value = '';
|
|
78
65
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
66
|
+
if (expression.type === 'Identifier') {
|
|
67
|
+
value = expression.name;
|
|
68
|
+
}
|
|
82
69
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
70
|
+
if (expression.type === 'StringLiteral') {
|
|
71
|
+
value = expression.value;
|
|
72
|
+
}
|
|
86
73
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
74
|
+
if (
|
|
75
|
+
expression.type === 'MemberExpression' &&
|
|
76
|
+
expression.object.name === 'colors' &&
|
|
77
|
+
isLegacyColor(expression.property.name)
|
|
78
|
+
) {
|
|
79
|
+
value = expression.property.name;
|
|
80
|
+
}
|
|
94
81
|
|
|
95
|
-
|
|
82
|
+
return value;
|
|
96
83
|
}
|
|
97
84
|
|
|
98
|
-
function getTokenFromNode(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const search = Search(possibleTokens, false);
|
|
236
|
-
const results: [number, string][] = search.get(meta.join(' '));
|
|
237
|
-
|
|
238
|
-
let tokenId = ['MISSING_TOKEN'];
|
|
239
|
-
|
|
240
|
-
if (results) {
|
|
241
|
-
tokenId = results.map((result) => result[1]) as any;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
return tokenId[0];
|
|
85
|
+
function getTokenFromNode(j: JSCodeshift, path: any, value: string, propertyName: string): string {
|
|
86
|
+
const valueMeta = cleanMeta(legacyColorMetaMap[value!] || []);
|
|
87
|
+
const ancestorMeta = cleanMeta(
|
|
88
|
+
[...getMetaFromAncestors(j, path), ...kebabize(propertyName).split('-')] || [],
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
let property = cleanMeta([kebabize(propertyName)])[0];
|
|
92
|
+
|
|
93
|
+
// Attempt to find a property from ancestors if one is not found
|
|
94
|
+
if (!property || !['border', 'icon', 'background', 'text'].includes(property)) {
|
|
95
|
+
if (ancestorMeta.includes('border')) {
|
|
96
|
+
property = 'border';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (ancestorMeta.includes('icon')) {
|
|
100
|
+
property = 'icon';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (ancestorMeta.includes('background')) {
|
|
104
|
+
property = 'background';
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (ancestorMeta.includes('color')) {
|
|
108
|
+
property = 'text';
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
let meta: string[] = [];
|
|
113
|
+
let possibleTokens = activeTokens;
|
|
114
|
+
|
|
115
|
+
if (property === 'text') {
|
|
116
|
+
possibleTokens = activeTokens.filter((token) => token.includes('.text'));
|
|
117
|
+
|
|
118
|
+
if (valueMeta.includes('neutral')) {
|
|
119
|
+
meta.push('color', 'text');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (valueMeta.includes('neutral') && (value === 'N400' || value === 'N500')) {
|
|
123
|
+
meta.push('color', 'text', 'subtle');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (
|
|
127
|
+
valueMeta.includes('neutral') &&
|
|
128
|
+
(value === 'N80' ||
|
|
129
|
+
value === 'N100' ||
|
|
130
|
+
value === 'N200' ||
|
|
131
|
+
value === 'N300' ||
|
|
132
|
+
value === 'N400')
|
|
133
|
+
) {
|
|
134
|
+
meta.push('color', 'text', 'subtlest');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// handle non-neutrals
|
|
138
|
+
if (!valueMeta.includes('neutral')) {
|
|
139
|
+
meta.push('color', ...ancestorMeta, ...valueMeta);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (property === 'background' || property === 'background-color') {
|
|
144
|
+
if (ancestorMeta.includes('disabled')) {
|
|
145
|
+
// disabled backgrounds
|
|
146
|
+
meta.push(property, ...ancestorMeta);
|
|
147
|
+
} else if (
|
|
148
|
+
// Surfaces
|
|
149
|
+
valueMeta.includes('neutral') &&
|
|
150
|
+
value !== 'N100' &&
|
|
151
|
+
value !== 'N200' &&
|
|
152
|
+
value !== 'N300' &&
|
|
153
|
+
value !== 'N400' &&
|
|
154
|
+
value !== 'N500' &&
|
|
155
|
+
value !== 'N600' &&
|
|
156
|
+
value !== 'N700' &&
|
|
157
|
+
value !== 'N800'
|
|
158
|
+
) {
|
|
159
|
+
meta.push('surface', ...ancestorMeta);
|
|
160
|
+
} else if (value.includes('N0')) {
|
|
161
|
+
// default surface
|
|
162
|
+
meta.push('elevation', 'surface');
|
|
163
|
+
} else if (valueMeta.includes('neutral') && isBoldColor(value)) {
|
|
164
|
+
// bold netural backgrounds
|
|
165
|
+
meta.push('background', 'neutral', 'bold');
|
|
166
|
+
} else if (valueMeta.includes('neutral')) {
|
|
167
|
+
// netural backgrounds
|
|
168
|
+
meta.push('background', 'neutral');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (
|
|
173
|
+
property === 'border' ||
|
|
174
|
+
property === 'border-color' ||
|
|
175
|
+
property === 'border-left' ||
|
|
176
|
+
property === 'border-right' ||
|
|
177
|
+
property === 'border-top' ||
|
|
178
|
+
property === 'border-bottom' ||
|
|
179
|
+
property === 'outline' ||
|
|
180
|
+
property === 'outline-color'
|
|
181
|
+
) {
|
|
182
|
+
possibleTokens = activeTokens.filter(
|
|
183
|
+
(token) => token.includes('.border') || token.includes('.focus'),
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
if (valueMeta.includes('neutral')) {
|
|
187
|
+
// standard netural boarder
|
|
188
|
+
meta.push('color', 'border', ...ancestorMeta);
|
|
189
|
+
} else {
|
|
190
|
+
meta.push('border', ...valueMeta, ...ancestorMeta);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (ancestorMeta.includes('icon')) {
|
|
195
|
+
possibleTokens = activeTokens.filter((token) => token.includes('.icon'));
|
|
196
|
+
|
|
197
|
+
if (ancestorMeta.includes('disabled')) {
|
|
198
|
+
// disabled backgrounds
|
|
199
|
+
meta.push('disabled');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
meta.push('color', 'icon', ...valueMeta);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Fallback if guided behavior yields nothing
|
|
206
|
+
if (meta.length === 0) {
|
|
207
|
+
meta.push(property, ...valueMeta, ...ancestorMeta);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const search = Search(possibleTokens, false);
|
|
211
|
+
const results: [number, string][] = search.get(meta.join(' '));
|
|
212
|
+
|
|
213
|
+
let tokenId = ['MISSING_TOKEN'];
|
|
214
|
+
|
|
215
|
+
if (results) {
|
|
216
|
+
tokenId = results.map((result) => result[1]) as any;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return tokenId[0];
|
|
245
220
|
}
|
|
246
221
|
|
|
247
222
|
function parseCSSPropertyName(cssString: string) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
223
|
+
const lastColonIndex = cssString.lastIndexOf(':');
|
|
224
|
+
if (lastColonIndex === -1) {
|
|
225
|
+
return { colonIndex: null, cssPropertyName: null };
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const propertyNameEndIndex = Math.max(
|
|
229
|
+
cssString.lastIndexOf(';', lastColonIndex),
|
|
230
|
+
cssString.lastIndexOf(' ', lastColonIndex),
|
|
231
|
+
-1,
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
const startIndex = propertyNameEndIndex + 1;
|
|
235
|
+
return {
|
|
236
|
+
cssPropertyName: cssString.slice(startIndex, lastColonIndex).trim(),
|
|
237
|
+
colonIndex: lastColonIndex,
|
|
238
|
+
};
|
|
264
239
|
}
|
|
265
240
|
|
|
266
|
-
export default async function transformer(
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
// possible to proceed because we cannot find where the value ends from a
|
|
571
|
-
// single following quasi.
|
|
572
|
-
const valueStartIndex = findFirstNonspaceIndexAfter(
|
|
573
|
-
precedingQuasiText,
|
|
574
|
-
colonIndex,
|
|
575
|
-
);
|
|
576
|
-
|
|
577
|
-
const [newPrecedingQuasiText, partialValueBeginning] = splitAtIndex(
|
|
578
|
-
precedingQuasiText,
|
|
579
|
-
valueStartIndex,
|
|
580
|
-
);
|
|
581
|
-
|
|
582
|
-
const followingQuasi = mainPath.value.quasis[expressionIndex + 1];
|
|
583
|
-
const followingQuasiText = followingQuasi.value.raw;
|
|
584
|
-
|
|
585
|
-
const valueEndIndex = findEndIndexOfCSSExpression(
|
|
586
|
-
followingQuasiText,
|
|
587
|
-
followingQuasi.tail,
|
|
588
|
-
);
|
|
589
|
-
if (!valueEndIndex) {
|
|
590
|
-
console.warn(
|
|
591
|
-
'cannot find end of box-shadow value, please check manually',
|
|
592
|
-
);
|
|
593
|
-
return false;
|
|
594
|
-
}
|
|
595
|
-
const [partialValueEnd, newFollowingQuasiText] = splitAtIndex(
|
|
596
|
-
followingQuasiText,
|
|
597
|
-
valueEndIndex + 1,
|
|
598
|
-
);
|
|
599
|
-
|
|
600
|
-
const internalQuasis = [
|
|
601
|
-
buildTemplateElement(j, partialValueBeginning, { tail: false }),
|
|
602
|
-
buildTemplateElement(j, partialValueEnd, { tail: true }),
|
|
603
|
-
];
|
|
604
|
-
const internalExpressions = [expressionPath.value];
|
|
605
|
-
const newFallback = j.templateLiteral(
|
|
606
|
-
internalQuasis,
|
|
607
|
-
internalExpressions,
|
|
608
|
-
);
|
|
609
|
-
const newExpression = buildToken(j, tokenId, newFallback);
|
|
610
|
-
|
|
611
|
-
newQuasis[expressionIndex] = buildTemplateElement(
|
|
612
|
-
j,
|
|
613
|
-
newPrecedingQuasiText,
|
|
614
|
-
{ fromNode: newQuasis[expressionIndex] },
|
|
615
|
-
);
|
|
616
|
-
newExpressions[expressionIndex] = newExpression;
|
|
617
|
-
newQuasis[expressionIndex + 1] = buildTemplateElement(
|
|
618
|
-
j,
|
|
619
|
-
newFollowingQuasiText,
|
|
620
|
-
{ fromNode: newQuasis[expressionIndex] },
|
|
621
|
-
);
|
|
622
|
-
}
|
|
623
|
-
mainPath.replace(j.templateLiteral(newQuasis, newExpressions));
|
|
624
|
-
return true;
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
return transformed ? source.toSource() : file.source;
|
|
241
|
+
export default async function transformer(file: FileInfo, api: API, debug = false) {
|
|
242
|
+
const j = api.jscodeshift;
|
|
243
|
+
const source = j(file.source);
|
|
244
|
+
let transformed = false;
|
|
245
|
+
|
|
246
|
+
// Objects
|
|
247
|
+
source.find(j.ObjectProperty).forEach((path) => {
|
|
248
|
+
if (path.value.value.type === 'ObjectExpression') {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Avoid transforming objects that are default arguments
|
|
253
|
+
if (
|
|
254
|
+
path.parent.parent.value.type === 'ArrowFunctionExpression' ||
|
|
255
|
+
path.parent.parent.value.type === 'FunctionDeclaration'
|
|
256
|
+
) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (isParentOfToken(j, path.value.value)) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const value = getColorFromIdentifier(path.value.value);
|
|
265
|
+
|
|
266
|
+
if (
|
|
267
|
+
!value ||
|
|
268
|
+
(!includesHardCodedColor(value) &&
|
|
269
|
+
!isHardCodedColor(value) &&
|
|
270
|
+
!isLegacyColor(value) &&
|
|
271
|
+
!isLegacyNamedColor(value))
|
|
272
|
+
) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
let key;
|
|
277
|
+
|
|
278
|
+
if (path.value.key.type === 'NumericLiteral' || path.value.key.type === 'StringLiteral') {
|
|
279
|
+
key = path.value.key.value.toString();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (path.value.key.type === 'Identifier') {
|
|
283
|
+
key = path.value.key.name;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Key is a node type we do not support
|
|
287
|
+
if (!key) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const tokenId = getTokenFromNode(j, path, value, key);
|
|
292
|
+
|
|
293
|
+
insertTokenImport(j, source);
|
|
294
|
+
|
|
295
|
+
j(path).replaceWith(j.objectProperty(path.value.key, buildToken(j, tokenId, path.value.value)));
|
|
296
|
+
|
|
297
|
+
transformed = true;
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// JSX props
|
|
301
|
+
source.find(j.JSXAttribute).forEach((path) => {
|
|
302
|
+
if (path.value?.value?.type !== 'JSXExpressionContainer') {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (isParentOfToken(j, path)) {
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const expression = path.value.value.expression;
|
|
311
|
+
const value = getColorFromIdentifier(expression);
|
|
312
|
+
|
|
313
|
+
if (
|
|
314
|
+
!value ||
|
|
315
|
+
(!includesHardCodedColor(value) &&
|
|
316
|
+
!isHardCodedColor(value) &&
|
|
317
|
+
!isLegacyColor(value) &&
|
|
318
|
+
!isLegacyNamedColor(value))
|
|
319
|
+
) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const tokenId = getTokenFromNode(j, path, value, path.value.name.name as string);
|
|
324
|
+
insertTokenImport(j, source);
|
|
325
|
+
|
|
326
|
+
j(path)
|
|
327
|
+
.find(j.JSXExpressionContainer)
|
|
328
|
+
.forEach((path) => {
|
|
329
|
+
const tokenNode = buildToken(j, tokenId, path.value.expression);
|
|
330
|
+
j(path).replaceWith(j.jsxExpressionContainer(tokenNode));
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
transformed = true;
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// Strings
|
|
337
|
+
source.find(j.StringLiteral).forEach((path) => {
|
|
338
|
+
j(path)
|
|
339
|
+
.filter((expression) => !isDecendantOfType(j, expression, j.ObjectExpression))
|
|
340
|
+
.forEach((path) => {
|
|
341
|
+
const value = path.value.value;
|
|
342
|
+
|
|
343
|
+
if (replaceStringLiteralIfItConsistsOnlyOfColor(j, path, value)) {
|
|
344
|
+
transformed = true;
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
const templateLiteralPaths = source.find(j.TemplateLiteral).paths();
|
|
350
|
+
|
|
351
|
+
for (const path of templateLiteralPaths) {
|
|
352
|
+
// Background: a 'type: TemplateLiteral' Node has quasis and expressions
|
|
353
|
+
// (see ast-types/src/gen/namedTypes.ts), and invariant holds that
|
|
354
|
+
// quasis.length === expression.length + 1.
|
|
355
|
+
//
|
|
356
|
+
// eg `${foo}bar` has quasis [Node(''), Node('bar')] and expressions
|
|
357
|
+
// [Node('foo')]. Each quasi has type: 'TemplateElement'; expressions are
|
|
358
|
+
// probably safe to treat as subtypes of Expression, though ast-types
|
|
359
|
+
// codebase has a more involved definition.
|
|
360
|
+
if (path.value.expressions.length === 0) {
|
|
361
|
+
// A single-quasi (equivalently, no-expression) template literal is
|
|
362
|
+
// basically just a string literal, possibly multi-line. We handle the
|
|
363
|
+
// simple `#ababab` case here, and the multi-line case after.
|
|
364
|
+
const text = path.value.quasis[0].value.raw;
|
|
365
|
+
|
|
366
|
+
if (replaceStringLiteralIfItConsistsOnlyOfColor(j, path, text)) {
|
|
367
|
+
transformed = true;
|
|
368
|
+
}
|
|
369
|
+
} else {
|
|
370
|
+
j(path)
|
|
371
|
+
.find(j.Expression)
|
|
372
|
+
.filter((expressionPath) => {
|
|
373
|
+
// jscodeshift walks over the whole tree; we are interested only in
|
|
374
|
+
// the direct children: i.e. top-level expressions appearing in ${}.
|
|
375
|
+
return expressionPath.parent === path;
|
|
376
|
+
})
|
|
377
|
+
.forEach((expressionPath, expressionIndex) => {
|
|
378
|
+
if (replaceTemplateLiteralExpression(j, path, expressionPath, expressionIndex)) {
|
|
379
|
+
transformed = true;
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// No matter if we have one big quasi or many small chunks between
|
|
385
|
+
// expressions (which potentially have been transformed), try to pass them
|
|
386
|
+
// through the CSS transformer; it's robust enough to understand malformed
|
|
387
|
+
// CSS that would result if we split e.g. this template:
|
|
388
|
+
//
|
|
389
|
+
// `${gridSize}px; color: red;`, giving `px; color: red;` as input; or
|
|
390
|
+
// `@media ${mobile} { color: red }`, giving `{ color: red }`.
|
|
391
|
+
const quasiPaths = j(path)
|
|
392
|
+
.find(j.TemplateElement)
|
|
393
|
+
.filter((quasiPath) => {
|
|
394
|
+
return quasiPath.parent === path;
|
|
395
|
+
})
|
|
396
|
+
.paths();
|
|
397
|
+
|
|
398
|
+
for (const quasiPath of quasiPaths) {
|
|
399
|
+
const text = quasiPath.value.value.raw;
|
|
400
|
+
if (includesHardCodedColor(text) && containsReplaceableCSSDeclarations(text)) {
|
|
401
|
+
const newCSS = await CSSTransformer(text);
|
|
402
|
+
|
|
403
|
+
j(quasiPath).replaceWith(buildTemplateElement(j, newCSS));
|
|
404
|
+
transformed = true;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function replaceStringLiteralIfItConsistsOnlyOfColor(j: any, path: any, value: string) {
|
|
410
|
+
if (isDecendantOfToken(j, path)) {
|
|
411
|
+
return false;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
if (isHardCodedColor(value) && !isLegacyColor(value) && !isLegacyNamedColor(value)) {
|
|
415
|
+
const parent = path.parent.value;
|
|
416
|
+
let key = '';
|
|
417
|
+
|
|
418
|
+
if (parent.type === 'VariableDeclarator') {
|
|
419
|
+
key = parent.id.name;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const tokenId = getTokenFromNode(j, path, value, key);
|
|
423
|
+
|
|
424
|
+
insertTokenImport(j, source);
|
|
425
|
+
|
|
426
|
+
j(path).replaceWith(buildToken(j, tokenId, path.value));
|
|
427
|
+
|
|
428
|
+
return true;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function replaceTemplateLiteralExpression(
|
|
435
|
+
j: any,
|
|
436
|
+
mainPath: any,
|
|
437
|
+
expressionPath: any,
|
|
438
|
+
expressionIndex: any,
|
|
439
|
+
) {
|
|
440
|
+
const expression = expressionPath.value;
|
|
441
|
+
if (!(expression.type === 'MemberExpression' || expression.type === 'Identifier')) {
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (isDecendantOfToken(j, expressionPath)) {
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const value = getColorFromIdentifier(expression);
|
|
450
|
+
|
|
451
|
+
if (
|
|
452
|
+
!value ||
|
|
453
|
+
(!includesHardCodedColor(value) &&
|
|
454
|
+
!isHardCodedColor(value) &&
|
|
455
|
+
!isLegacyColor(value) &&
|
|
456
|
+
!isLegacyNamedColor(value))
|
|
457
|
+
) {
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const precedingQuasi = mainPath.value.quasis[expressionIndex];
|
|
462
|
+
const precedingQuasiText = precedingQuasi.value.raw;
|
|
463
|
+
const { cssPropertyName, colonIndex } = parseCSSPropertyName(precedingQuasiText);
|
|
464
|
+
|
|
465
|
+
if (!cssPropertyName) {
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const tokenId = getTokenFromNode(j, expressionPath, value, cssPropertyName);
|
|
470
|
+
|
|
471
|
+
insertTokenImport(j, source);
|
|
472
|
+
|
|
473
|
+
const newQuasis = [...mainPath.value.quasis];
|
|
474
|
+
const newExpressions = [...mainPath.value.expressions];
|
|
475
|
+
|
|
476
|
+
if (cssPropertyName !== 'box-shadow') {
|
|
477
|
+
const tokenExpression = buildToken(j, tokenId, expressionPath.value);
|
|
478
|
+
|
|
479
|
+
newExpressions[expressionIndex] = tokenExpression;
|
|
480
|
+
} else {
|
|
481
|
+
// box-shadow is a multi-part property where the color can appear at any
|
|
482
|
+
// part position (even though the standard suggests that color comes
|
|
483
|
+
// last, browsers' CSS parsers are more lax). If we get here, then the
|
|
484
|
+
// color part is replaceable. Textually, it's something like:
|
|
485
|
+
//
|
|
486
|
+
// <rules before>; box-shadow: 0 1px ${colors.N50} 2rem; <rules after>
|
|
487
|
+
//
|
|
488
|
+
// the fallback value will be multipart, i.e. the token call is
|
|
489
|
+
//
|
|
490
|
+
// token(<replacedValue>, `0 1px ${colors.N50} 2rem`)
|
|
491
|
+
//
|
|
492
|
+
// and it's wrapped in a substitution like this:
|
|
493
|
+
//
|
|
494
|
+
// <rules before>; box-shadow: ${token(<...>)}; <rules after>
|
|
495
|
+
//
|
|
496
|
+
// We stich the fallback from the last part of preceding quasi (after
|
|
497
|
+
// colon) and the first part of the following quasi (before ';' or '}').
|
|
498
|
+
//
|
|
499
|
+
// If multiple box-shadows are comma-separated but only one of them has a
|
|
500
|
+
// replaceable color and others are hard-coded, this logic would still
|
|
501
|
+
// work. When multiple shadows have expressions, it's unfortunately not
|
|
502
|
+
// possible to proceed because we cannot find where the value ends from a
|
|
503
|
+
// single following quasi.
|
|
504
|
+
const valueStartIndex = findFirstNonspaceIndexAfter(precedingQuasiText, colonIndex);
|
|
505
|
+
|
|
506
|
+
const [newPrecedingQuasiText, partialValueBeginning] = splitAtIndex(
|
|
507
|
+
precedingQuasiText,
|
|
508
|
+
valueStartIndex,
|
|
509
|
+
);
|
|
510
|
+
|
|
511
|
+
const followingQuasi = mainPath.value.quasis[expressionIndex + 1];
|
|
512
|
+
const followingQuasiText = followingQuasi.value.raw;
|
|
513
|
+
|
|
514
|
+
const valueEndIndex = findEndIndexOfCSSExpression(followingQuasiText, followingQuasi.tail);
|
|
515
|
+
if (!valueEndIndex) {
|
|
516
|
+
console.warn('cannot find end of box-shadow value, please check manually');
|
|
517
|
+
return false;
|
|
518
|
+
}
|
|
519
|
+
const [partialValueEnd, newFollowingQuasiText] = splitAtIndex(
|
|
520
|
+
followingQuasiText,
|
|
521
|
+
valueEndIndex + 1,
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
const internalQuasis = [
|
|
525
|
+
buildTemplateElement(j, partialValueBeginning, { tail: false }),
|
|
526
|
+
buildTemplateElement(j, partialValueEnd, { tail: true }),
|
|
527
|
+
];
|
|
528
|
+
const internalExpressions = [expressionPath.value];
|
|
529
|
+
const newFallback = j.templateLiteral(internalQuasis, internalExpressions);
|
|
530
|
+
const newExpression = buildToken(j, tokenId, newFallback);
|
|
531
|
+
|
|
532
|
+
newQuasis[expressionIndex] = buildTemplateElement(j, newPrecedingQuasiText, {
|
|
533
|
+
fromNode: newQuasis[expressionIndex],
|
|
534
|
+
});
|
|
535
|
+
newExpressions[expressionIndex] = newExpression;
|
|
536
|
+
newQuasis[expressionIndex + 1] = buildTemplateElement(j, newFollowingQuasiText, {
|
|
537
|
+
fromNode: newQuasis[expressionIndex],
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
mainPath.replace(j.templateLiteral(newQuasis, newExpressions));
|
|
541
|
+
return true;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
return transformed ? source.toSource() : file.source;
|
|
628
545
|
}
|