@atlaskit/codemod-cli 0.13.3 → 0.14.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 +12 -0
- package/README.md +117 -3
- package/dist/cjs/cli.js +70 -75
- package/dist/cjs/filepath.js +65 -29
- package/dist/cjs/index.js +3 -3
- package/dist/cjs/main.js +329 -167
- package/dist/cjs/presets/css-to-design-tokens/css-to-design-tokens.js +86 -34
- package/dist/cjs/presets/css-to-design-tokens/utils/legacy-colors.js +3 -3
- package/dist/cjs/presets/css-to-design-tokens/utils/meta.js +19 -6
- package/dist/cjs/presets/index.js +3 -1
- package/dist/cjs/presets/styled-to-emotion/styled-to-emotion.js +19 -12
- package/dist/cjs/presets/theme-remove-deprecated-mixins/theme-remove-deprecated-mixins.js +51 -36
- package/dist/cjs/presets/theme-remove-deprecated-mixins/utils/replacements.js +25 -25
- package/dist/cjs/presets/theme-to-design-tokens/theme-to-design-tokens.js +378 -114
- package/dist/cjs/presets/theme-to-design-tokens/utils/ast-meta.js +33 -18
- package/dist/cjs/presets/theme-to-design-tokens/utils/ast.js +1 -1
- package/dist/cjs/presets/theme-to-design-tokens/utils/color.js +25 -17
- package/dist/cjs/presets/theme-to-design-tokens/utils/css-utils.js +38 -0
- package/dist/cjs/presets/theme-to-design-tokens/utils/fuzzy-search.js +10 -6
- package/dist/cjs/presets/theme-to-design-tokens/utils/legacy-colors.js +3 -3
- package/dist/cjs/presets/theme-to-design-tokens/utils/named-colors.js +1 -1
- package/dist/cjs/presets/theme-to-design-tokens/utils/string-utils.js +26 -0
- package/dist/cjs/presets/theme-to-design-tokens/utils/tokens.js +16 -2
- package/dist/cjs/sinceRef.js +69 -35
- package/dist/cjs/transforms.js +44 -26
- package/dist/cjs/types.js +27 -3
- package/dist/cjs/utils.js +6 -6
- package/dist/es2019/cli.js +4 -0
- package/dist/es2019/main.js +2 -0
- package/dist/es2019/presets/css-to-design-tokens/css-to-design-tokens.js +19 -8
- package/dist/es2019/presets/theme-to-design-tokens/theme-to-design-tokens.js +191 -32
- package/dist/es2019/presets/theme-to-design-tokens/utils/ast.js +1 -1
- package/dist/es2019/presets/theme-to-design-tokens/utils/color.js +12 -10
- package/dist/es2019/presets/theme-to-design-tokens/utils/css-utils.js +31 -0
- package/dist/es2019/presets/theme-to-design-tokens/utils/string-utils.js +13 -0
- package/dist/es2019/sinceRef.js +1 -0
- package/dist/esm/cli.js +4 -0
- package/dist/esm/main.js +3 -1
- package/dist/esm/presets/css-to-design-tokens/css-to-design-tokens.js +23 -12
- package/dist/esm/presets/theme-to-design-tokens/theme-to-design-tokens.js +346 -100
- package/dist/esm/presets/theme-to-design-tokens/utils/ast.js +1 -1
- package/dist/esm/presets/theme-to-design-tokens/utils/color.js +12 -10
- package/dist/esm/presets/theme-to-design-tokens/utils/css-utils.js +31 -0
- package/dist/esm/presets/theme-to-design-tokens/utils/string-utils.js +17 -0
- package/dist/esm/sinceRef.js +1 -0
- package/dist/types/presets/css-to-design-tokens/css-to-design-tokens.d.ts +2 -1
- package/dist/types/presets/theme-to-design-tokens/theme-to-design-tokens.d.ts +1 -1
- package/dist/types/presets/theme-to-design-tokens/utils/ast.d.ts +1 -1
- package/dist/types/presets/theme-to-design-tokens/utils/color.d.ts +2 -1
- package/dist/types/presets/theme-to-design-tokens/utils/css-utils.d.ts +2 -0
- package/dist/types/presets/theme-to-design-tokens/utils/string-utils.d.ts +3 -0
- package/dist/types-ts4.5/presets/css-to-design-tokens/css-to-design-tokens.d.ts +2 -1
- package/dist/types-ts4.5/presets/theme-to-design-tokens/theme-to-design-tokens.d.ts +1 -1
- package/dist/types-ts4.5/presets/theme-to-design-tokens/utils/ast.d.ts +1 -1
- package/dist/types-ts4.5/presets/theme-to-design-tokens/utils/color.d.ts +2 -1
- package/dist/types-ts4.5/presets/theme-to-design-tokens/utils/css-utils.d.ts +2 -0
- package/dist/types-ts4.5/presets/theme-to-design-tokens/utils/string-utils.d.ts +6 -0
- package/package.json +2 -2
- package/dist/cjs/version.json +0 -4
- package/dist/es2019/version.json +0 -4
- package/dist/esm/version.json +0 -4
package/dist/cjs/types.js
CHANGED
|
@@ -1,14 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
3
4
|
Object.defineProperty(exports, "__esModule", {
|
|
4
5
|
value: true
|
|
5
6
|
});
|
|
6
7
|
exports.ValidationError = exports.NoTransformsExistError = void 0;
|
|
8
|
+
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
9
|
+
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
10
|
+
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
|
|
11
|
+
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
|
|
12
|
+
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
|
|
13
|
+
var _wrapNativeSuper2 = _interopRequireDefault(require("@babel/runtime/helpers/wrapNativeSuper"));
|
|
14
|
+
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }
|
|
15
|
+
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
|
|
7
16
|
/** Converts required args to optional if they have a default
|
|
8
17
|
* Example: export type UserFlags = Default<Flags, keyof typeof defaultFlags>;
|
|
9
18
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
var ValidationError = /*#__PURE__*/function (_Error) {
|
|
20
|
+
(0, _inherits2.default)(ValidationError, _Error);
|
|
21
|
+
var _super = _createSuper(ValidationError);
|
|
22
|
+
function ValidationError() {
|
|
23
|
+
(0, _classCallCheck2.default)(this, ValidationError);
|
|
24
|
+
return _super.apply(this, arguments);
|
|
25
|
+
}
|
|
26
|
+
return (0, _createClass2.default)(ValidationError);
|
|
27
|
+
}( /*#__PURE__*/(0, _wrapNativeSuper2.default)(Error));
|
|
12
28
|
exports.ValidationError = ValidationError;
|
|
13
|
-
|
|
29
|
+
var NoTransformsExistError = /*#__PURE__*/function (_Error2) {
|
|
30
|
+
(0, _inherits2.default)(NoTransformsExistError, _Error2);
|
|
31
|
+
var _super2 = _createSuper(NoTransformsExistError);
|
|
32
|
+
function NoTransformsExistError() {
|
|
33
|
+
(0, _classCallCheck2.default)(this, NoTransformsExistError);
|
|
34
|
+
return _super2.apply(this, arguments);
|
|
35
|
+
}
|
|
36
|
+
return (0, _createClass2.default)(NoTransformsExistError);
|
|
37
|
+
}( /*#__PURE__*/(0, _wrapNativeSuper2.default)(Error));
|
|
14
38
|
exports.NoTransformsExistError = NoTransformsExistError;
|
package/dist/cjs/utils.js
CHANGED
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.fixLineEnding = void 0;
|
|
7
7
|
/* Utility functions to be used in codemod-cli. */
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
var returnLineEnding = function returnLineEnding(source) {
|
|
10
10
|
var cr = source.split('\r').length;
|
|
11
11
|
var lf = source.split('\n').length;
|
|
12
12
|
var crlf = source.split('\r\n').length;
|
|
@@ -22,7 +22,7 @@ const returnLineEnding = source => {
|
|
|
22
22
|
return 'LF';
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
|
-
|
|
25
|
+
var getLineEndingRegex = function getLineEndingRegex(type) {
|
|
26
26
|
if (['CR', 'LF', 'CRLF'].indexOf(type) === -1) {
|
|
27
27
|
throw new Error("Line ending '" + type + "' is not supported, use CR, LF or CRLF");
|
|
28
28
|
}
|
|
@@ -36,13 +36,13 @@ const getLineEndingRegex = type => {
|
|
|
36
36
|
return '\r\n';
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
var fixLineEnding = function fixLineEnding(source, lineEnding) {
|
|
40
|
+
var current = returnLineEnding(source);
|
|
41
41
|
if (current === lineEnding) {
|
|
42
42
|
return source;
|
|
43
43
|
}
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
var regexCurrentLineEnding = getLineEndingRegex(current);
|
|
45
|
+
var regexLineEnding = getLineEndingRegex(lineEnding);
|
|
46
46
|
if (current && regexLineEnding && regexCurrentLineEnding) {
|
|
47
47
|
return source.replace(new RegExp(regexCurrentLineEnding, 'g'), regexLineEnding);
|
|
48
48
|
}
|
package/dist/es2019/cli.js
CHANGED
|
@@ -67,13 +67,17 @@ Examples
|
|
|
67
67
|
});
|
|
68
68
|
main(cli.input, cli.flags).catch(e => {
|
|
69
69
|
if (e instanceof ValidationError) {
|
|
70
|
+
// eslint-disable-next-line no-console
|
|
70
71
|
console.error(cli.help);
|
|
72
|
+
// eslint-disable-next-line no-console
|
|
71
73
|
console.error(chalk.red(e.message));
|
|
72
74
|
process.exit(1);
|
|
73
75
|
} else if (e instanceof NoTransformsExistError) {
|
|
76
|
+
// eslint-disable-next-line no-console
|
|
74
77
|
console.warn(chalk.yellow(e.message));
|
|
75
78
|
process.exit(0);
|
|
76
79
|
} else {
|
|
80
|
+
// eslint-disable-next-line no-console
|
|
77
81
|
console.error(chalk.red(e));
|
|
78
82
|
process.exit(3);
|
|
79
83
|
}
|
package/dist/es2019/main.js
CHANGED
|
@@ -54,6 +54,7 @@ const resolveTransform = async (flags, transforms) => {
|
|
|
54
54
|
name
|
|
55
55
|
}) => name === flags.preset);
|
|
56
56
|
if (!transform) {
|
|
57
|
+
// eslint-disable-next-line no-console
|
|
57
58
|
console.warn(`No preset found for: ${chalk.bgRed(flags.preset)}`);
|
|
58
59
|
} else {
|
|
59
60
|
return transform; // Return only if transform found.
|
|
@@ -64,6 +65,7 @@ const resolveTransform = async (flags, transforms) => {
|
|
|
64
65
|
return parseTransformPath(flags.transform);
|
|
65
66
|
}
|
|
66
67
|
if (flags.transform && !hasTransform(flags.transform)) {
|
|
68
|
+
// eslint-disable-next-line no-console
|
|
67
69
|
console.warn(`No available transform found for: ${chalk.bgRed(flags.transform)}`);
|
|
68
70
|
}
|
|
69
71
|
return await getTransformPrompt(transforms);
|
|
@@ -6,6 +6,10 @@ import designTokens from '@atlaskit/tokens/token-names';
|
|
|
6
6
|
import Search from '../theme-to-design-tokens/utils/fuzzy-search';
|
|
7
7
|
import { knownVariables, knownColors, knownRawColors } from './utils/legacy-colors';
|
|
8
8
|
import { cleanMeta } from './utils/meta';
|
|
9
|
+
const options = {
|
|
10
|
+
syntax: lessSyntax,
|
|
11
|
+
from: undefined
|
|
12
|
+
};
|
|
9
13
|
const tokens = rawTokens.filter(t => t.attributes.state === 'active').map(t => t.name.replace(/\.\[default\]/g, '')).filter(t => !t.includes('UNSAFE') && !t.includes('interaction'));
|
|
10
14
|
const search = Search(tokens, false);
|
|
11
15
|
function isRule(node) {
|
|
@@ -27,8 +31,8 @@ function stripVar(prop) {
|
|
|
27
31
|
function stripLessVar(prop) {
|
|
28
32
|
return prop.substring(1);
|
|
29
33
|
}
|
|
30
|
-
function isColorProperty(prop) {
|
|
31
|
-
return prop === 'color' || prop === 'background' || prop === 'background-color' || prop === 'box-shadow' || prop === 'border' || prop === 'border-left' || prop === 'border-right' || prop === 'border-top' || prop === 'border-bottom' || prop === 'border-color';
|
|
34
|
+
export function isColorProperty(prop) {
|
|
35
|
+
return prop === 'color' || prop === 'background' || prop === 'background-color' || prop === 'box-shadow' || prop === 'border' || prop === 'border-left' || prop === 'border-right' || prop === 'border-top' || prop === 'border-bottom' || prop === 'border-color' || prop === 'outline';
|
|
32
36
|
}
|
|
33
37
|
function getDeclarationMeta(decl) {
|
|
34
38
|
if (decl.prop === 'color') {
|
|
@@ -77,6 +81,9 @@ const plugin = () => {
|
|
|
77
81
|
if (!isColorProperty(decl.prop)) {
|
|
78
82
|
return;
|
|
79
83
|
}
|
|
84
|
+
if (decl.value === 'none') {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
80
87
|
const searchTerms = [getDeclarationMeta(decl), ...getParentSelectors(decl).split(/\-|\.|\,|\ |\:|\&/).filter(el => !!el)];
|
|
81
88
|
let match;
|
|
82
89
|
const cssVarRe = /var\([^\)]+\)/g;
|
|
@@ -95,10 +102,10 @@ const plugin = () => {
|
|
|
95
102
|
}
|
|
96
103
|
|
|
97
104
|
// Less variables
|
|
98
|
-
const
|
|
99
|
-
if (
|
|
105
|
+
const lessVarMatch = decl.value.match(lessVarRe);
|
|
106
|
+
if (lessVarMatch) {
|
|
100
107
|
var _getMetaFromCssVar2;
|
|
101
|
-
match =
|
|
108
|
+
match = lessVarMatch[0];
|
|
102
109
|
searchTerms.push(...((_getMetaFromCssVar2 = getMetaFromCssVar(`--${stripLessVar(match)}`)) !== null && _getMetaFromCssVar2 !== void 0 ? _getMetaFromCssVar2 : []));
|
|
103
110
|
}
|
|
104
111
|
|
|
@@ -117,6 +124,7 @@ const plugin = () => {
|
|
|
117
124
|
searchTerms.push(...((_knownColors$decl$val = knownColors[decl.value.toLowerCase()]) !== null && _knownColors$decl$val !== void 0 ? _knownColors$decl$val : []));
|
|
118
125
|
}
|
|
119
126
|
if (!match) {
|
|
127
|
+
// eslint-disable-next-line no-console
|
|
120
128
|
console.warn(`Unable to find match for declaration: ${decl.prop}: ${decl.value}`);
|
|
121
129
|
return;
|
|
122
130
|
}
|
|
@@ -136,7 +144,10 @@ const plugin = () => {
|
|
|
136
144
|
};
|
|
137
145
|
};
|
|
138
146
|
export default async function transformer(file) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
147
|
+
const processor = postcss([plugin()]);
|
|
148
|
+
const src = typeof file === 'string' ? file : file.source;
|
|
149
|
+
const {
|
|
150
|
+
css
|
|
151
|
+
} = await processor.process(src, options);
|
|
152
|
+
return css;
|
|
142
153
|
}
|
|
@@ -3,15 +3,13 @@
|
|
|
3
3
|
import { isDecendantOfType, hasImportDeclaration } from '@codeshift/utils';
|
|
4
4
|
import { isDecendantOfToken, isParentOfToken } from './utils/ast';
|
|
5
5
|
import { cleanMeta, getMetaFromAncestors } from './utils/ast-meta';
|
|
6
|
-
import { includesHardCodedColor, isHardCodedColor, isLegacyColor, isLegacyNamedColor } from './utils/color';
|
|
6
|
+
import { includesHardCodedColor, isHardCodedColor, isLegacyColor, isLegacyNamedColor, isBoldColor } from './utils/color';
|
|
7
7
|
import Search from './utils/fuzzy-search';
|
|
8
8
|
import { legacyColorMetaMap } from './utils/legacy-colors';
|
|
9
9
|
import { tokens } from './utils/tokens';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return number > 300;
|
|
14
|
-
}
|
|
10
|
+
import { kebabize, findFirstNonspaceIndexAfter, splitAtIndex } from './utils/string-utils';
|
|
11
|
+
import { containsReplaceableCSSDeclarations, findEndIndexOfCSSExpression } from './utils/css-utils';
|
|
12
|
+
import CSSTransformer from '../css-to-design-tokens/css-to-design-tokens';
|
|
15
13
|
function insertTokenImport(j, source) {
|
|
16
14
|
if (hasImportDeclaration(j, source, '@atlaskit/tokens')) {
|
|
17
15
|
return;
|
|
@@ -23,6 +21,23 @@ function buildToken(j, tokenId, node) {
|
|
|
23
21
|
const callExpr = j.callExpression(j.identifier('token'), [j.stringLiteral(tokenId), node].filter(Boolean));
|
|
24
22
|
return callExpr;
|
|
25
23
|
}
|
|
24
|
+
|
|
25
|
+
// Wrap over the j.templateElement builder to provide a more convenient API.
|
|
26
|
+
function buildTemplateElement(j, text, options = {
|
|
27
|
+
tail: false,
|
|
28
|
+
fromNode: null
|
|
29
|
+
}) {
|
|
30
|
+
let tail;
|
|
31
|
+
if (options.fromNode) {
|
|
32
|
+
tail = options.fromNode.tail;
|
|
33
|
+
} else {
|
|
34
|
+
tail = !!options.tail;
|
|
35
|
+
}
|
|
36
|
+
return j.templateElement({
|
|
37
|
+
raw: text,
|
|
38
|
+
cooked: null
|
|
39
|
+
}, tail);
|
|
40
|
+
}
|
|
26
41
|
function getColorFromIdentifier(expression) {
|
|
27
42
|
let value = '';
|
|
28
43
|
if (expression.type === 'Identifier') {
|
|
@@ -126,10 +141,20 @@ function getTokenFromNode(j, path, value, propertyName) {
|
|
|
126
141
|
}
|
|
127
142
|
function parseCSSPropertyName(cssString) {
|
|
128
143
|
const lastColonIndex = cssString.lastIndexOf(':');
|
|
129
|
-
|
|
130
|
-
|
|
144
|
+
if (lastColonIndex === -1) {
|
|
145
|
+
return {
|
|
146
|
+
colonIndex: null,
|
|
147
|
+
cssPropertyName: null
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
const propertyNameEndIndex = Math.max(cssString.lastIndexOf(';', lastColonIndex), cssString.lastIndexOf(' ', lastColonIndex), -1);
|
|
151
|
+
const startIndex = propertyNameEndIndex + 1;
|
|
152
|
+
return {
|
|
153
|
+
cssPropertyName: cssString.slice(startIndex, lastColonIndex).trim(),
|
|
154
|
+
colonIndex: lastColonIndex
|
|
155
|
+
};
|
|
131
156
|
}
|
|
132
|
-
export default function transformer(file, api, debug = false) {
|
|
157
|
+
export default async function transformer(file, api, debug = false) {
|
|
133
158
|
const j = api.jscodeshift;
|
|
134
159
|
const source = j(file.source);
|
|
135
160
|
let transformed = false;
|
|
@@ -169,29 +194,6 @@ export default function transformer(file, api, debug = false) {
|
|
|
169
194
|
transformed = true;
|
|
170
195
|
});
|
|
171
196
|
|
|
172
|
-
// Template literals
|
|
173
|
-
source.find(j.TemplateLiteral).forEach(path => {
|
|
174
|
-
function replaceTemplateLiteralExpressions(j, expression, index) {
|
|
175
|
-
if (isDecendantOfToken(j, expression)) {
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
if (index >= path.value.quasis.length) {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
const quasi = path.value.quasis[index];
|
|
182
|
-
const value = getColorFromIdentifier(expression.value);
|
|
183
|
-
if (!value || !includesHardCodedColor(value) && !isHardCodedColor(value) && !isLegacyColor(value) && !isLegacyNamedColor(value)) {
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
const tokenId = getTokenFromNode(j, expression, value, parseCSSPropertyName(quasi.value.cooked || ''));
|
|
187
|
-
insertTokenImport(j, source);
|
|
188
|
-
expression.replace(buildToken(j, tokenId, expression.value));
|
|
189
|
-
}
|
|
190
|
-
j(path).find(j.Identifier).filter(expression => !isDecendantOfType(j, expression, j.MemberExpression)).forEach((expression, i) => replaceTemplateLiteralExpressions(j, expression, i));
|
|
191
|
-
j(path).find(j.MemberExpression).forEach((expression, i) => replaceTemplateLiteralExpressions(j, expression, i));
|
|
192
|
-
transformed = true;
|
|
193
|
-
});
|
|
194
|
-
|
|
195
197
|
// JSX props
|
|
196
198
|
source.find(j.JSXAttribute).forEach(path => {
|
|
197
199
|
var _path$value, _path$value$value;
|
|
@@ -214,5 +216,162 @@ export default function transformer(file, api, debug = false) {
|
|
|
214
216
|
});
|
|
215
217
|
transformed = true;
|
|
216
218
|
});
|
|
219
|
+
|
|
220
|
+
// Strings
|
|
221
|
+
source.find(j.StringLiteral).forEach(path => {
|
|
222
|
+
j(path).filter(expression => !isDecendantOfType(j, expression, j.ObjectExpression)).forEach(path => {
|
|
223
|
+
const value = path.value.value;
|
|
224
|
+
if (replaceStringLiteralIfItConsistsOnlyOfColor(j, path, value)) {
|
|
225
|
+
transformed = true;
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
const templateLiteralPaths = source.find(j.TemplateLiteral).paths();
|
|
230
|
+
for (const path of templateLiteralPaths) {
|
|
231
|
+
// Background: a 'type: TemplateLiteral' Node has quasis and expressions
|
|
232
|
+
// (see ast-types/src/gen/namedTypes.ts), and invariant holds that
|
|
233
|
+
// quasis.length === expression.length + 1.
|
|
234
|
+
//
|
|
235
|
+
// eg `${foo}bar` has quasis [Node(''), Node('bar')] and expressions
|
|
236
|
+
// [Node('foo')]. Each quasi has type: 'TemplateElement'; expressions are
|
|
237
|
+
// probably safe to treat as subtypes of Expression, though ast-types
|
|
238
|
+
// codebase has a more involved definition.
|
|
239
|
+
if (path.value.expressions.length === 0) {
|
|
240
|
+
// A single-quasi (equivalently, no-expression) template literal is
|
|
241
|
+
// basically just a string literal, possibly multi-line. We handle the
|
|
242
|
+
// simple `#ababab` case here, and the multi-line case after.
|
|
243
|
+
const text = path.value.quasis[0].value.raw;
|
|
244
|
+
if (replaceStringLiteralIfItConsistsOnlyOfColor(j, path, text)) {
|
|
245
|
+
transformed = true;
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
j(path).find(j.Expression).filter(expressionPath => {
|
|
249
|
+
// jscodeshift walks over the whole tree; we are interested only in
|
|
250
|
+
// the direct children: i.e. top-level expressions appearing in ${}.
|
|
251
|
+
return expressionPath.parent === path;
|
|
252
|
+
}).forEach((expressionPath, expressionIndex) => {
|
|
253
|
+
if (replaceTemplateLiteralExpression(j, path, expressionPath, expressionIndex)) {
|
|
254
|
+
transformed = true;
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// No matter if we have one big quasi or many small chunks between
|
|
260
|
+
// expressions (which potentially have been transformed), try to pass them
|
|
261
|
+
// through the CSS transformer; it's robust enough to understand malformed
|
|
262
|
+
// CSS that would result if we split e.g. this template:
|
|
263
|
+
//
|
|
264
|
+
// `${gridSize}px; color: red;`, giving `px; color: red;` as input; or
|
|
265
|
+
// `@media ${mobile} { color: red }`, giving `{ color: red }`.
|
|
266
|
+
const quasiPaths = j(path).find(j.TemplateElement).filter(quasiPath => {
|
|
267
|
+
return quasiPath.parent === path;
|
|
268
|
+
}).paths();
|
|
269
|
+
for (const quasiPath of quasiPaths) {
|
|
270
|
+
const text = quasiPath.value.value.raw;
|
|
271
|
+
if (includesHardCodedColor(text) && containsReplaceableCSSDeclarations(text)) {
|
|
272
|
+
const newCSS = await CSSTransformer(text);
|
|
273
|
+
j(quasiPath).replaceWith(buildTemplateElement(j, newCSS));
|
|
274
|
+
transformed = true;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
function replaceStringLiteralIfItConsistsOnlyOfColor(j, path, value) {
|
|
279
|
+
if (isDecendantOfToken(j, path)) {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
if (isHardCodedColor(value) && !isLegacyColor(value) && !isLegacyNamedColor(value)) {
|
|
283
|
+
const parent = path.parent.value;
|
|
284
|
+
let key = '';
|
|
285
|
+
if (parent.type === 'VariableDeclarator') {
|
|
286
|
+
key = parent.id.name;
|
|
287
|
+
}
|
|
288
|
+
const tokenId = getTokenFromNode(j, path, value, key);
|
|
289
|
+
insertTokenImport(j, source);
|
|
290
|
+
j(path).replaceWith(buildToken(j, tokenId, path.value));
|
|
291
|
+
return true;
|
|
292
|
+
}
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
function replaceTemplateLiteralExpression(j, mainPath, expressionPath, expressionIndex) {
|
|
296
|
+
const expression = expressionPath.value;
|
|
297
|
+
if (!(expression.type === 'MemberExpression' || expression.type === 'Identifier')) {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
if (isDecendantOfToken(j, expressionPath)) {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
const value = getColorFromIdentifier(expression);
|
|
304
|
+
if (!value || !includesHardCodedColor(value) && !isHardCodedColor(value) && !isLegacyColor(value) && !isLegacyNamedColor(value)) {
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
const precedingQuasi = mainPath.value.quasis[expressionIndex];
|
|
308
|
+
const precedingQuasiText = precedingQuasi.value.raw;
|
|
309
|
+
const {
|
|
310
|
+
cssPropertyName,
|
|
311
|
+
colonIndex
|
|
312
|
+
} = parseCSSPropertyName(precedingQuasiText);
|
|
313
|
+
if (!cssPropertyName) {
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
const tokenId = getTokenFromNode(j, expressionPath, value, cssPropertyName);
|
|
317
|
+
insertTokenImport(j, source);
|
|
318
|
+
const newQuasis = [...mainPath.value.quasis];
|
|
319
|
+
const newExpressions = [...mainPath.value.expressions];
|
|
320
|
+
if (cssPropertyName !== 'box-shadow') {
|
|
321
|
+
const tokenExpression = buildToken(j, tokenId, expressionPath.value);
|
|
322
|
+
newExpressions[expressionIndex] = tokenExpression;
|
|
323
|
+
} else {
|
|
324
|
+
// box-shadow is a multi-part property where the color can appear at any
|
|
325
|
+
// part position (even though the standard suggests that color comes
|
|
326
|
+
// last, browsers' CSS parsers are more lax). If we get here, then the
|
|
327
|
+
// color part is replaceable. Textually, it's something like:
|
|
328
|
+
//
|
|
329
|
+
// <rules before>; box-shadow: 0 1px ${colors.N50} 2rem; <rules after>
|
|
330
|
+
//
|
|
331
|
+
// the fallback value will be multipart, i.e. the token call is
|
|
332
|
+
//
|
|
333
|
+
// token(<replacedValue>, `0 1px ${colors.N50} 2rem`)
|
|
334
|
+
//
|
|
335
|
+
// and it's wrapped in a substitution like this:
|
|
336
|
+
//
|
|
337
|
+
// <rules before>; box-shadow: ${token(<...>)}; <rules after>
|
|
338
|
+
//
|
|
339
|
+
// We stich the fallback from the last part of preceding quasi (after
|
|
340
|
+
// colon) and the first part of the following quasi (before ';' or '}').
|
|
341
|
+
//
|
|
342
|
+
// If multiple box-shadows are comma-separated but only one of them has a
|
|
343
|
+
// replaceable color and others are hard-coded, this logic would still
|
|
344
|
+
// work. When multiple shadows have expressions, it's unfortunately not
|
|
345
|
+
// possible to proceed because we cannot find where the value ends from a
|
|
346
|
+
// single following quasi.
|
|
347
|
+
const valueStartIndex = findFirstNonspaceIndexAfter(precedingQuasiText, colonIndex);
|
|
348
|
+
const [newPrecedingQuasiText, partialValueBeginning] = splitAtIndex(precedingQuasiText, valueStartIndex);
|
|
349
|
+
const followingQuasi = mainPath.value.quasis[expressionIndex + 1];
|
|
350
|
+
const followingQuasiText = followingQuasi.value.raw;
|
|
351
|
+
const valueEndIndex = findEndIndexOfCSSExpression(followingQuasiText, followingQuasi.tail);
|
|
352
|
+
if (!valueEndIndex) {
|
|
353
|
+
console.warn('cannot find end of box-shadow value, please check manually');
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
const [partialValueEnd, newFollowingQuasiText] = splitAtIndex(followingQuasiText, valueEndIndex + 1);
|
|
357
|
+
const internalQuasis = [buildTemplateElement(j, partialValueBeginning, {
|
|
358
|
+
tail: false
|
|
359
|
+
}), buildTemplateElement(j, partialValueEnd, {
|
|
360
|
+
tail: true
|
|
361
|
+
})];
|
|
362
|
+
const internalExpressions = [expressionPath.value];
|
|
363
|
+
const newFallback = j.templateLiteral(internalQuasis, internalExpressions);
|
|
364
|
+
const newExpression = buildToken(j, tokenId, newFallback);
|
|
365
|
+
newQuasis[expressionIndex] = buildTemplateElement(j, newPrecedingQuasiText, {
|
|
366
|
+
fromNode: newQuasis[expressionIndex]
|
|
367
|
+
});
|
|
368
|
+
newExpressions[expressionIndex] = newExpression;
|
|
369
|
+
newQuasis[expressionIndex + 1] = buildTemplateElement(j, newFollowingQuasiText, {
|
|
370
|
+
fromNode: newQuasis[expressionIndex]
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
mainPath.replace(j.templateLiteral(newQuasis, newExpressions));
|
|
374
|
+
return true;
|
|
375
|
+
}
|
|
217
376
|
return transformed ? source.toSource() : file.source;
|
|
218
377
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isDecendantOfType } from '@codeshift/utils';
|
|
2
2
|
export function isDecendantOfToken(j, path) {
|
|
3
|
-
if (path.type === 'CallExpression' && path.callee.type === 'Identifier' && path.callee.name === 'token') {
|
|
3
|
+
if ('type' in path && path.type === 'CallExpression' && path.callee.type === 'Identifier' && path.callee.name === 'token') {
|
|
4
4
|
return true;
|
|
5
5
|
}
|
|
6
6
|
return j(path).closest(j.CallExpression, {
|
|
@@ -2,9 +2,10 @@ import { legacyColorMixins, legacyColors } from './legacy-colors';
|
|
|
2
2
|
import { namedColors } from './named-colors';
|
|
3
3
|
export const isLegacyColor = value => legacyColors.includes(value);
|
|
4
4
|
export const isLegacyNamedColor = value => legacyColorMixins.includes(value);
|
|
5
|
+
const colorRegexp = /#(?:[a-f0-9]{3}|[a-f0-9]{6}|[a-f0-9]{8})\b|(?:rgb|rgba|hsl|hsla|lch|lab|color)\([^\)]*\)/;
|
|
5
6
|
export const includesHardCodedColor = raw => {
|
|
6
7
|
const value = raw.toLowerCase();
|
|
7
|
-
if (
|
|
8
|
+
if (colorRegexp.exec(value)) {
|
|
8
9
|
return true;
|
|
9
10
|
}
|
|
10
11
|
for (let i = 0; i < namedColors.length; i++) {
|
|
@@ -14,17 +15,18 @@ export const includesHardCodedColor = raw => {
|
|
|
14
15
|
}
|
|
15
16
|
return false;
|
|
16
17
|
};
|
|
17
|
-
export const isHardCodedColor =
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
if (value.startsWith('rgb(') || value.startsWith('rgba(') || value.startsWith('hsl(') || value.startsWith('hsla(') || value.startsWith('lch(') || value.startsWith('lab(') || value.startsWith('color(')) {
|
|
18
|
+
export const isHardCodedColor = raw => {
|
|
19
|
+
const value = raw.toLowerCase();
|
|
20
|
+
if (namedColors.includes(value)) {
|
|
22
21
|
return true;
|
|
23
22
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
value.length === 4 || value.length === 7 || value.length === 9)) {
|
|
23
|
+
const match = value.toLowerCase().match(colorRegexp);
|
|
24
|
+
if (match && match[0] === value) {
|
|
27
25
|
return true;
|
|
28
26
|
}
|
|
29
27
|
return false;
|
|
30
|
-
};
|
|
28
|
+
};
|
|
29
|
+
export function isBoldColor(color) {
|
|
30
|
+
const number = parseInt(color.replace(/^./, ''), 10);
|
|
31
|
+
return number > 300;
|
|
32
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { isColorProperty } from '../../css-to-design-tokens/css-to-design-tokens';
|
|
2
|
+
export function containsReplaceableCSSDeclarations(input) {
|
|
3
|
+
const cssPattern = /(\S+)\s*:/g;
|
|
4
|
+
let match;
|
|
5
|
+
while ((match = cssPattern.exec(input)) !== null) {
|
|
6
|
+
if (isColorProperty(match[1])) {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
export function findEndIndexOfCSSExpression(text, isAtEndOfInput) {
|
|
13
|
+
// CSS expression can end *on* a semicolon or *before* a brace. In either
|
|
14
|
+
// case we treat the remaining part of the value to cover one character
|
|
15
|
+
// before that symbol.
|
|
16
|
+
const semicolonIndex = text.indexOf(';');
|
|
17
|
+
const braceIndex = text.indexOf('}');
|
|
18
|
+
if (semicolonIndex === -1 && braceIndex === -1) {
|
|
19
|
+
if (isAtEndOfInput) {
|
|
20
|
+
return text.length;
|
|
21
|
+
} else {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
} else if (semicolonIndex === -1) {
|
|
25
|
+
return braceIndex - 1;
|
|
26
|
+
} else if (braceIndex === -1) {
|
|
27
|
+
return semicolonIndex - 1;
|
|
28
|
+
} else {
|
|
29
|
+
return Math.min(semicolonIndex, braceIndex) - 1;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const kebabize = str => str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, ($, ofs) => (ofs ? '-' : '') + $.toLowerCase());
|
|
2
|
+
export function findFirstNonspaceIndexAfter(text, index) {
|
|
3
|
+
const rest = text.slice(index + 1);
|
|
4
|
+
const indexInRest = rest.search(/\S/);
|
|
5
|
+
if (indexInRest === -1) {
|
|
6
|
+
return text.length;
|
|
7
|
+
} else {
|
|
8
|
+
return index + 1 + indexInRest;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function splitAtIndex(text, index) {
|
|
12
|
+
return [text.slice(0, index), text.slice(index)];
|
|
13
|
+
}
|
package/dist/es2019/sinceRef.js
CHANGED
package/dist/esm/cli.js
CHANGED
|
@@ -51,13 +51,17 @@ function _run() {
|
|
|
51
51
|
});
|
|
52
52
|
main(cli.input, cli.flags).catch(function (e) {
|
|
53
53
|
if (e instanceof ValidationError) {
|
|
54
|
+
// eslint-disable-next-line no-console
|
|
54
55
|
console.error(cli.help);
|
|
56
|
+
// eslint-disable-next-line no-console
|
|
55
57
|
console.error(chalk.red(e.message));
|
|
56
58
|
process.exit(1);
|
|
57
59
|
} else if (e instanceof NoTransformsExistError) {
|
|
60
|
+
// eslint-disable-next-line no-console
|
|
58
61
|
console.warn(chalk.yellow(e.message));
|
|
59
62
|
process.exit(0);
|
|
60
63
|
} else {
|
|
64
|
+
// eslint-disable-next-line no-console
|
|
61
65
|
console.error(chalk.red(e));
|
|
62
66
|
process.exit(3);
|
|
63
67
|
}
|
package/dist/esm/main.js
CHANGED
|
@@ -95,6 +95,7 @@ var resolveTransform = /*#__PURE__*/function () {
|
|
|
95
95
|
_context2.next = 6;
|
|
96
96
|
break;
|
|
97
97
|
}
|
|
98
|
+
// eslint-disable-next-line no-console
|
|
98
99
|
console.warn("No preset found for: ".concat(chalk.bgRed(flags.preset)));
|
|
99
100
|
_context2.next = 7;
|
|
100
101
|
break;
|
|
@@ -108,6 +109,7 @@ var resolveTransform = /*#__PURE__*/function () {
|
|
|
108
109
|
return _context2.abrupt("return", parseTransformPath(flags.transform));
|
|
109
110
|
case 9:
|
|
110
111
|
if (flags.transform && !hasTransform(flags.transform)) {
|
|
112
|
+
// eslint-disable-next-line no-console
|
|
111
113
|
console.warn("No available transform found for: ".concat(chalk.bgRed(flags.transform)));
|
|
112
114
|
}
|
|
113
115
|
_context2.next = 12;
|
|
@@ -289,7 +291,7 @@ function _main() {
|
|
|
289
291
|
case 4:
|
|
290
292
|
_yield$parseArgs = _context5.sent;
|
|
291
293
|
packages = _yield$parseArgs.packages;
|
|
292
|
-
_process$env$_PACKAGE = "0.
|
|
294
|
+
_process$env$_PACKAGE = "0.14.0", _PACKAGE_VERSION_ = _process$env$_PACKAGE === void 0 ? '0.0.0-dev' : _process$env$_PACKAGE;
|
|
293
295
|
logger.log(chalk.bgBlue(chalk.black("\uD83D\uDCDA Atlassian-Frontend codemod library @ ".concat(_PACKAGE_VERSION_, " \uD83D\uDCDA"))));
|
|
294
296
|
if (packages && packages.length > 0) {
|
|
295
297
|
logger.log(chalk.gray("Searching for codemods for newer versions of the following packages: ".concat(packages.map(function (pkg) {
|