@atlaskit/codemod-cli 0.8.3 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +12 -2
  3. package/dist/cjs/main.js +3 -3
  4. package/dist/cjs/presets/index.js +4 -2
  5. package/dist/cjs/presets/theme-to-design-tokens/theme-to-design-tokens.js +181 -0
  6. package/dist/cjs/presets/theme-to-design-tokens/types.js +5 -0
  7. package/dist/cjs/presets/theme-to-design-tokens/utils/ast-meta.js +104 -0
  8. package/dist/cjs/presets/theme-to-design-tokens/utils/ast.js +19 -0
  9. package/dist/cjs/presets/theme-to-design-tokens/utils/color-difference.js +174 -0
  10. package/dist/cjs/presets/theme-to-design-tokens/utils/color-palette-tokens-map.js +129 -0
  11. package/dist/cjs/presets/theme-to-design-tokens/utils/color-to-token.js +88 -0
  12. package/dist/cjs/presets/theme-to-design-tokens/utils/color.js +59 -0
  13. package/dist/cjs/presets/theme-to-design-tokens/utils/fuzzy-search.js +348 -0
  14. package/dist/cjs/presets/theme-to-design-tokens/utils/legacy-colors.js +81 -0
  15. package/dist/cjs/presets/theme-to-design-tokens/utils/named-colors.js +8 -0
  16. package/dist/cjs/types.js +4 -2
  17. package/dist/cjs/version.json +1 -1
  18. package/dist/es2019/presets/index.js +2 -1
  19. package/dist/es2019/presets/theme-to-design-tokens/theme-to-design-tokens.js +137 -0
  20. package/dist/es2019/presets/theme-to-design-tokens/types.js +1 -0
  21. package/dist/es2019/presets/theme-to-design-tokens/utils/ast-meta.js +70 -0
  22. package/dist/es2019/presets/theme-to-design-tokens/utils/ast.js +10 -0
  23. package/dist/es2019/presets/theme-to-design-tokens/utils/color-difference.js +150 -0
  24. package/dist/es2019/presets/theme-to-design-tokens/utils/color-palette-tokens-map.js +122 -0
  25. package/dist/es2019/presets/theme-to-design-tokens/utils/color-to-token.js +75 -0
  26. package/dist/es2019/presets/theme-to-design-tokens/utils/color.js +35 -0
  27. package/dist/es2019/presets/theme-to-design-tokens/utils/fuzzy-search.js +336 -0
  28. package/dist/es2019/presets/theme-to-design-tokens/utils/legacy-colors.js +72 -0
  29. package/dist/es2019/presets/theme-to-design-tokens/utils/named-colors.js +1 -0
  30. package/dist/es2019/version.json +1 -1
  31. package/dist/esm/main.js +3 -3
  32. package/dist/esm/presets/index.js +3 -2
  33. package/dist/esm/presets/theme-to-design-tokens/theme-to-design-tokens.js +165 -0
  34. package/dist/esm/presets/theme-to-design-tokens/types.js +1 -0
  35. package/dist/esm/presets/theme-to-design-tokens/utils/ast-meta.js +88 -0
  36. package/dist/esm/presets/theme-to-design-tokens/utils/ast.js +10 -0
  37. package/dist/esm/presets/theme-to-design-tokens/utils/color-difference.js +160 -0
  38. package/dist/esm/presets/theme-to-design-tokens/utils/color-palette-tokens-map.js +122 -0
  39. package/dist/esm/presets/theme-to-design-tokens/utils/color-to-token.js +78 -0
  40. package/dist/esm/presets/theme-to-design-tokens/utils/color.js +39 -0
  41. package/dist/esm/presets/theme-to-design-tokens/utils/fuzzy-search.js +340 -0
  42. package/dist/esm/presets/theme-to-design-tokens/utils/legacy-colors.js +72 -0
  43. package/dist/esm/presets/theme-to-design-tokens/utils/named-colors.js +1 -0
  44. package/dist/esm/types.js +3 -2
  45. package/dist/esm/version.json +1 -1
  46. package/dist/types/presets/index.d.ts +1 -0
  47. package/dist/types/presets/theme-to-design-tokens/theme-to-design-tokens.d.ts +2 -0
  48. package/dist/types/presets/theme-to-design-tokens/types.d.ts +2 -0
  49. package/dist/types/presets/theme-to-design-tokens/utils/ast-meta.d.ts +4 -0
  50. package/dist/types/presets/theme-to-design-tokens/utils/ast.d.ts +3 -0
  51. package/dist/types/presets/theme-to-design-tokens/utils/color-difference.d.ts +66 -0
  52. package/dist/types/presets/theme-to-design-tokens/utils/color-palette-tokens-map.d.ts +21 -0
  53. package/dist/types/presets/theme-to-design-tokens/utils/color-to-token.d.ts +12 -0
  54. package/dist/types/presets/theme-to-design-tokens/utils/color.d.ts +4 -0
  55. package/dist/types/presets/theme-to-design-tokens/utils/fuzzy-search.d.ts +5 -0
  56. package/dist/types/presets/theme-to-design-tokens/utils/legacy-colors.d.ts +3 -0
  57. package/dist/types/presets/theme-to-design-tokens/utils/named-colors.d.ts +1 -0
  58. package/package.json +3 -1
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.namedColors = void 0;
7
+ var namedColors = ['black', 'silver', 'gray', 'white', 'maroon', 'red', 'purple', 'fuchsia', 'green', 'lime', 'olive', 'yellow', 'navy', 'blue', 'teal', 'aqua', 'orange', 'aliceblue', 'antiquewhite', 'aquamarine', 'azure', 'beige', 'bisque', 'blanchedalmond', 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse', 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgreen', 'darkgrey', 'darkkhaki', 'darkmagenta', 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred', 'darksalmon', 'darkseagreen', 'darkslateblue', 'darkslategray', 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink', 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', 'firebrick', 'floralwhite', 'forestgreen', 'gainsboro', 'ghostwhite', 'gold', 'goldenrod', 'greenyellow', 'grey', 'honeydew', 'hotpink', 'indianred', 'indigo', 'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen', 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan', 'lightgoldenrodyellow', 'lightgray', 'lightgreen', 'lightgrey', 'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue', 'lightslategray', 'lightslategrey', 'lightsteelblue', 'lightyellow', 'limegreen', 'linen', 'magenta', 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple', 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen', 'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream', 'mistyrose', 'moccasin', 'navajowhite', 'oldlace', 'olivedrab', 'orangered', 'orchid', 'palegoldenrod', 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip', 'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown', 'seagreen', 'seashell', 'sienna', 'skyblue', 'slateblue', 'slategray', 'slategrey', 'snow', 'springgreen', 'steelblue', 'tan', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'whitesmoke', 'yellowgreen', 'rebeccapurple'];
8
+ exports.namedColors = namedColors;
package/dist/cjs/types.js CHANGED
@@ -7,6 +7,8 @@ Object.defineProperty(exports, "__esModule", {
7
7
  });
8
8
  exports.ValidationError = exports.NoTransformsExistError = void 0;
9
9
 
10
+ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
11
+
10
12
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
11
13
 
12
14
  var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
@@ -34,7 +36,7 @@ var ValidationError = /*#__PURE__*/function (_Error) {
34
36
  return _super.apply(this, arguments);
35
37
  }
36
38
 
37
- return ValidationError;
39
+ return (0, _createClass2.default)(ValidationError);
38
40
  }( /*#__PURE__*/(0, _wrapNativeSuper2.default)(Error));
39
41
 
40
42
  exports.ValidationError = ValidationError;
@@ -49,7 +51,7 @@ var NoTransformsExistError = /*#__PURE__*/function (_Error2) {
49
51
  return _super2.apply(this, arguments);
50
52
  }
51
53
 
52
- return NoTransformsExistError;
54
+ return (0, _createClass2.default)(NoTransformsExistError);
53
55
  }( /*#__PURE__*/(0, _wrapNativeSuper2.default)(Error));
54
56
 
55
57
  exports.NoTransformsExistError = NoTransformsExistError;
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "name": "@atlaskit/codemod-cli",
3
- "version": "0.8.3"
3
+ "version": "0.8.4"
4
4
  }
@@ -5,5 +5,6 @@ import path from 'path';
5
5
  */
6
6
 
7
7
  import './styled-to-emotion/styled-to-emotion';
8
- const presets = ['styled-to-emotion'].map(preset => path.join(__dirname, preset, `${preset}.@(ts|js)`));
8
+ import './theme-to-design-tokens/theme-to-design-tokens';
9
+ const presets = ['styled-to-emotion', 'theme-to-design-tokens'].map(preset => path.join(__dirname, preset, `${preset}.@(ts|js|tsx)`));
9
10
  export default presets;
@@ -0,0 +1,137 @@
1
+ /* eslint-disable no-console */
2
+ import colorToToken from './utils/color-to-token';
3
+ import { isDecendantOfToken, isDecendantOfType } from './utils/ast';
4
+ import { cleanMeta, getMetaFromAncestors } from './utils/ast-meta';
5
+ import { includesHardCodedColor, isHardCodedColor, isLegacyColor, isLegacyNamedColor } from './utils/color';
6
+ import Search from './utils/fuzzy-search';
7
+ import { legacyColorMetaMap } from './utils/legacy-colors';
8
+ import designTokens from '@atlaskit/tokens/token-names';
9
+ const tokens = Object.keys(designTokens);
10
+ const search = Search(tokens, false);
11
+
12
+ function hasImportDeclaration(j, source, sourcePath) {
13
+ return !!source.find(j.ImportDeclaration).filter(path => path.node.source.value === sourcePath).length;
14
+ }
15
+
16
+ function hasImportSpecifier(j, source, specifier, sourcePath) {
17
+ return !!source.find(j.ImportDeclaration).filter(path => path.node.source.value === sourcePath).find(j.ImportSpecifier, {
18
+ local: {
19
+ name: specifier
20
+ }
21
+ }).length;
22
+ }
23
+
24
+ function insertTokenImport(j, source) {
25
+ if (hasImportDeclaration(j, source, '@atlaskit/tokens')) {
26
+ return;
27
+ }
28
+
29
+ const newImport = j.importDeclaration([j.importSpecifier(j.identifier('token'))], j.stringLiteral('@atlaskit/tokens'));
30
+ source.get().node.program.body.unshift(newImport);
31
+ }
32
+
33
+ function buildToken(j, tokenResult, node) {
34
+ const callExpr = j.callExpression(j.identifier('token'), [j.stringLiteral(tokenResult.suggestion[0] || 'util.UNSAFE_MISSING_TOKEN'), tokenResult.fallbackNeeded && node].filter(Boolean));
35
+ callExpr.comments = [j.commentBlock(` [token-confidence: ${tokenResult.confidence}] `)];
36
+ return callExpr;
37
+ }
38
+
39
+ function getTokenFromNode(j, path, debug, paletteColor, baseMeta = []) {
40
+ const foundMeta = getMetaFromAncestors(j, path);
41
+ const propertyName = foundMeta.find(name => {
42
+ if (!name) {
43
+ return false;
44
+ }
45
+
46
+ return name.toLowerCase().match(/(.*color|image|fill|stroke|shadow|border(?!-)|background(?!-)|outline(?!-)|column-rule-color)/);
47
+ });
48
+ let state = 'resting';
49
+ foundMeta.find(name => {
50
+ if (!name) {
51
+ return false;
52
+ }
53
+
54
+ const result = /(hover|active|disabled)/.exec(name.toLowerCase());
55
+
56
+ if (result) {
57
+ if (result[0] === 'active') {
58
+ state = 'pressed';
59
+ } else {
60
+ state = result[0];
61
+ }
62
+
63
+ return true;
64
+ }
65
+
66
+ return false;
67
+ });
68
+ const tokenResult = colorToToken(paletteColor || '', {
69
+ state,
70
+ propertyName
71
+ }, () => {
72
+ const searchTerm = cleanMeta([...foundMeta, ...baseMeta]).join(' ');
73
+ const results = search.get(searchTerm);
74
+
75
+ if (results) {
76
+ return results.map(result => result[1]);
77
+ }
78
+
79
+ return [];
80
+ });
81
+ return tokenResult;
82
+ }
83
+
84
+ export default function transformer(file, api, debug = false) {
85
+ const j = api.jscodeshift;
86
+ const source = j(file.source);
87
+ let transformed = false;
88
+ source // Handle colors.N100
89
+ .find(j.MemberExpression).filter(path => {
90
+ return path.value.object.type === 'Identifier' && path.value.object.name === 'colors' && path.value.property.type === 'Identifier' && isLegacyColor(path.value.property.name);
91
+ }).filter(path => !isDecendantOfToken(j, path)).forEach(path => {
92
+ debug && console.log('file:', file.path);
93
+ insertTokenImport(j, source);
94
+ const key = path.value.property.type === 'Identifier' ? path.value.property.name : undefined;
95
+ const colorMeta = legacyColorMetaMap[key] || [];
96
+ const tokenId = getTokenFromNode(j, path, debug, key, colorMeta);
97
+ j(path).replaceWith(buildToken(j, tokenId, path.value));
98
+ transformed = true;
99
+ });
100
+ source.find(j.ObjectProperty).filter(path => {
101
+ return path.value.value.type === 'Identifier' && (isLegacyColor(path.value.value.name) || isLegacyNamedColor(path.value.value.name));
102
+ }).filter(path => hasImportSpecifier(j, source, path.value.value.type === 'Identifier' ? path.value.value.name : '', '@atlaskit/theme') || hasImportSpecifier(j, source, path.value.value.type === 'Identifier' ? path.value.value.name : '', '@atlaskit/theme/colors')).filter(path => !isDecendantOfToken(j, path.value.value)).forEach(path => {
103
+ const valuePath = path.get('value');
104
+ debug && console.log('file:', file.path);
105
+ insertTokenImport(j, source);
106
+ const colorMeta = legacyColorMetaMap[valuePath.name] || [];
107
+ const tokenId = getTokenFromNode(j, valuePath, debug, valuePath.name, colorMeta);
108
+ j(path).replaceWith(j.objectProperty(path.value.key, buildToken(j, tokenId, valuePath.value)));
109
+ transformed = true;
110
+ });
111
+ source.find(j.Identifier).filter(path => isLegacyColor(path.value.name) || isLegacyNamedColor(path.value.name)).filter(path => hasImportSpecifier(j, source, path.value.name, '@atlaskit/theme') || hasImportSpecifier(j, source, path.value.name, '@atlaskit/theme/colors')).filter(path => !['ImportSpecifier', 'MemberExpression', 'ObjectProperty'].includes(path.parentPath.value.type)).filter(path => !isDecendantOfToken(j, path)).forEach(path => {
112
+ debug && console.log('file:', file.path);
113
+ insertTokenImport(j, source);
114
+ const colorMeta = legacyColorMetaMap[path.value.name] || [];
115
+ const tokenId = getTokenFromNode(j, path, debug, path.value.name, colorMeta);
116
+ j(path).replaceWith(buildToken(j, tokenId, path.value));
117
+ transformed = true;
118
+ });
119
+ source.find(j.Literal).filter(path => typeof path.value.value === 'string' && (includesHardCodedColor(path.value.value) || isHardCodedColor(path.value.value))).filter(path => !isDecendantOfToken(j, path)).forEach(path => {
120
+ var _path$value, _path$value$value;
121
+
122
+ debug && console.log('file:', file.path);
123
+ insertTokenImport(j, source);
124
+ const value = path === null || path === void 0 ? void 0 : (_path$value = path.value) === null || _path$value === void 0 ? void 0 : (_path$value$value = _path$value.value) === null || _path$value$value === void 0 ? void 0 : _path$value$value.toString();
125
+ const colorMeta = legacyColorMetaMap[value] || [];
126
+ const tokenId = getTokenFromNode(j, path, debug, value, colorMeta);
127
+ const tokenNode = buildToken(j, tokenId, path.value);
128
+ j(path).replaceWith(isDecendantOfType(j, path, j.JSXAttribute) ? j.jsxExpressionContainer(tokenNode) : tokenNode);
129
+ transformed = true;
130
+ });
131
+
132
+ if (transformed) {
133
+ return source.toSource();
134
+ }
135
+
136
+ return file.source;
137
+ }
@@ -0,0 +1,70 @@
1
+ import designTokens from '@atlaskit/tokens/token-names';
2
+ const tokens = Object.keys(designTokens);
3
+ export const getUniqueWordsFromTokens = tokens.reduce((accum, val) => [...accum, ...val.split('.')], []).reduce((accum, val) => [...accum, ...val.split(/(?=[A-Z])/g).map(e => e.toLowerCase())], []).reduce((accum, val) => {
4
+ if (!accum.includes(val)) {
5
+ accum.push(val);
6
+ }
7
+
8
+ return accum;
9
+ }, []);
10
+ export function getMetaFromAncestors(j, path, meta = []) {
11
+ const parent = path.parentPath;
12
+ const grandParent = parent && parent.parentPath;
13
+
14
+ if (parent && parent.value.type === 'ObjectProperty') {
15
+ let value = '';
16
+
17
+ if (parent.value.key.type === 'Literal' || parent.value.key.type === 'StringLiteral' || parent.value.key.type === 'NumericLiteral') {
18
+ value = parent.value.key.value.toString();
19
+ } else {
20
+ value = parent.value.key.name;
21
+ }
22
+
23
+ meta.push(value);
24
+ }
25
+
26
+ if (parent && grandParent && grandParent.value.type === 'TemplateLiteral') {
27
+ const expressionIndex = grandParent.value.expressions.findIndex(exp => exp.name === path.value.name);
28
+ const quasi = grandParent.value.quasis[expressionIndex];
29
+ const propertyName = (quasi.value.cooked || quasi.value.raw || '').replace(/\n/g, '').split(/;|{|}/).filter(el => !el.match(/\.|\@|\(|\)/)).pop().replace(/:/g, '').trim();
30
+ grandParent.value.quasis.slice(0, expressionIndex + 1).map(q => q.value.cooked) // We reverse so the most nested one is first which we're more likely than not interested in
31
+ .reverse().forEach(str => {
32
+ const result = /(hover|active|disabled|focus)/.exec(str.toLowerCase());
33
+
34
+ if (result) {
35
+ meta.push(result[0]);
36
+ }
37
+ });
38
+ meta.push(propertyName);
39
+ }
40
+
41
+ if (parent && parent.value.type === 'JSXAttribute') {
42
+ if (!['css', 'styles', 'style'].includes(parent.value.name.name)) {
43
+ meta.push(parent.value.name.name);
44
+ }
45
+ }
46
+
47
+ if (parent && parent.value.type === 'VariableDeclarator') {
48
+ meta.push(parent.value.id.name);
49
+ }
50
+
51
+ if (parent) {
52
+ return getMetaFromAncestors(j, parent, meta);
53
+ }
54
+
55
+ return meta;
56
+ }
57
+ export function cleanMeta(meta) {
58
+ return meta.reduce((accum, val) => [...accum, ...(typeof val === 'string' ? val.split(/(?=[A-Z])/g).map(e => e.toLowerCase()) : [])], []).reduce((accum, val) => {
59
+ accum.push(val.replace(/:/g, '').replace(/,/g, '').replace('grey', 'neutral').replace('texts', 'text').replace('error', 'danger').replace('invalid', 'danger').replace('removed', 'danger').replace('removal', 'danger').replace('remove', 'danger').replace('valid', 'success').replace('successful', 'success').replace('risk', 'warning').replace('primary', 'bold').replace('info', 'bold').replace('secondary', 'subtle').replace('hyperlink', 'link').replace('focused', 'focus').replace('active', 'pressed').replace('hovered', 'hover').replace('background-color', 'background').replace('color', 'text').replace('stroke', 'border').replace('border-left', 'border').replace('border-right', 'border').replace('box-shadow', 'shadow'));
60
+ return accum;
61
+ }, []).filter(val => {
62
+ return getUniqueWordsFromTokens.includes(val);
63
+ }).reduce((accum, val) => {
64
+ if (!accum.includes(val)) {
65
+ accum.push(val);
66
+ }
67
+
68
+ return accum;
69
+ }, []);
70
+ }
@@ -0,0 +1,10 @@
1
+ export function isDecendantOfToken(j, path) {
2
+ return j(path).closest(j.CallExpression, {
3
+ callee: {
4
+ name: 'token'
5
+ }
6
+ }).length > 0;
7
+ }
8
+ export function isDecendantOfType(j, path, type) {
9
+ return j(path).closest(type).length > 0;
10
+ }
@@ -0,0 +1,150 @@
1
+ /* eslint-disable @atlassian/tangerine/import/entry-points */
2
+ import { convert } from 'chromatism'; // Design token values are not currently exposed from @atlaskit/tokens
3
+ // In a follow up ticket we will expose them again via another entrypoint.
4
+
5
+ import defaultTokenValues from '@atlaskit/tokens/token-names';
6
+ export const legacyColorPalette = {
7
+ R50: '#FFEBE6',
8
+ R75: '#FFBDAD',
9
+ R100: '#FF8F73',
10
+ R200: '#FF7452',
11
+ R300: '#FF5630',
12
+ R400: '#DE350B',
13
+ R500: '#BF2600',
14
+ Y50: '#FFFAE6',
15
+ Y75: '#FFF0B3',
16
+ Y100: '#FFE380',
17
+ Y200: '#FFC400',
18
+ Y300: '#FFAB00',
19
+ Y400: '#FF991F',
20
+ Y500: '#FF8B00',
21
+ G50: '#E3FCEF',
22
+ G75: '#ABF5D1',
23
+ G100: '#79F2C0',
24
+ G200: '#57D9A3',
25
+ G300: '#36B37E',
26
+ G400: '#00875A',
27
+ G500: '#006644',
28
+ B50: '#DEEBFF',
29
+ B75: '#B3D4FF',
30
+ B100: '#4C9AFF',
31
+ B200: '#2684FF',
32
+ B300: '#0065FF',
33
+ B400: '#0052CC',
34
+ B500: '#0747A6',
35
+ P50: '#EAE6FF',
36
+ P75: '#C0B6F2',
37
+ P100: '#998DD9',
38
+ P200: '#8777D9',
39
+ P300: '#6554C0',
40
+ P400: '#5243AA',
41
+ P500: '#403294',
42
+ T50: '#E6FCFF',
43
+ T75: '#B3F5FF',
44
+ T100: '#79E2F2',
45
+ T200: '#00C7E6',
46
+ T300: '#00B8D9',
47
+ T400: '#00A3BF',
48
+ T500: '#008DA6',
49
+ N0: '#FFFFFF',
50
+ N10: '#FAFBFC',
51
+ N20: '#F4F5F7',
52
+ N30: '#EBECF0',
53
+ N40: '#DFE1E6',
54
+ N50: '#C1C7D0',
55
+ N60: '#B3BAC5',
56
+ N70: '#A5ADBA',
57
+ N80: '#97A0AF',
58
+ N90: '#8993A4',
59
+ N100: '#7A869A',
60
+ N200: '#6B778C',
61
+ N300: '#5E6C84',
62
+ N400: '#505F79',
63
+ N500: '#42526E',
64
+ N600: '#344563',
65
+ N700: '#253858',
66
+ N800: '#172B4D',
67
+ N900: '#091E42'
68
+ };
69
+ export function findClosetMatchingToken(paletteName) {
70
+ const paletteColor = legacyColorPalette[paletteName];
71
+
72
+ if (!paletteColor) {
73
+ return undefined;
74
+ }
75
+
76
+ const tokens = Object.entries(defaultTokenValues).map(([key, value]) => {
77
+ try {
78
+ const diff = deltaE(paletteColor, value);
79
+ return [key, diff];
80
+ } catch (e) {
81
+ return [key, 99999];
82
+ }
83
+ }).sort((a, b) => {
84
+ const left = a[1];
85
+ const right = b[1];
86
+ return left - right;
87
+ });
88
+ const [token, diff] = tokens[0];
89
+
90
+ if (diff < 10) {
91
+ return token;
92
+ }
93
+
94
+ return undefined;
95
+ }
96
+
97
+ function toRgbArray(color) {
98
+ const colr = convert(color);
99
+ return [colr.rgb.r, colr.rgb.g, colr.rgb.b];
100
+ }
101
+ /**
102
+ * Color difference function ripped from https://stackoverflow.com/a/52453462
103
+ *
104
+ * **Color difference**
105
+ * - <= 1.0 not perceptible by human eyes
106
+ * - 1-2 Perceptible through close observation
107
+ * - 2-10 Perceptible at a glance
108
+ * - 11-49 Colors are more similar than opposite
109
+ * - 100 Colors are opposite
110
+ */
111
+
112
+
113
+ function deltaE(rgbA, rgbB) {
114
+ let labA = rgb2lab(toRgbArray(rgbA));
115
+ let labB = rgb2lab(toRgbArray(rgbB));
116
+ let deltaL = labA[0] - labB[0];
117
+ let deltaA = labA[1] - labB[1];
118
+ let deltaB = labA[2] - labB[2];
119
+ let c1 = Math.sqrt(labA[1] * labA[1] + labA[2] * labA[2]);
120
+ let c2 = Math.sqrt(labB[1] * labB[1] + labB[2] * labB[2]);
121
+ let deltaC = c1 - c2;
122
+ let deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC;
123
+ deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH);
124
+ let sc = 1.0 + 0.045 * c1;
125
+ let sh = 1.0 + 0.015 * c1;
126
+ let deltaLKlsl = deltaL / 1.0;
127
+ let deltaCkcsc = deltaC / sc;
128
+ let deltaHkhsh = deltaH / sh;
129
+ let i = deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc + deltaHkhsh * deltaHkhsh;
130
+ return i < 0 ? 0 : Math.sqrt(i);
131
+ }
132
+
133
+ function rgb2lab(rgb) {
134
+ let r = rgb[0] / 255,
135
+ g = rgb[1] / 255,
136
+ b = rgb[2] / 255,
137
+ x,
138
+ y,
139
+ z;
140
+ r = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
141
+ g = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
142
+ b = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
143
+ x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
144
+ y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.0;
145
+ z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
146
+ x = x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787 * x + 16 / 116;
147
+ y = y > 0.008856 ? Math.pow(y, 1 / 3) : 7.787 * y + 16 / 116;
148
+ z = z > 0.008856 ? Math.pow(z, 1 / 3) : 7.787 * z + 16 / 116;
149
+ return [116 * y - 16, 500 * (x - y), 200 * (y - z)];
150
+ }
@@ -0,0 +1,122 @@
1
+ const colorMap = {
2
+ resting: {
3
+ text: {
4
+ B300: ['color.text.selected', 'color.text.link.resting', 'color.iconBorder.brand'],
5
+ B400: ['color.text.selected', 'color.text.link.resting', 'color.iconBorder.brand'],
6
+ R300: ['color.text.danger', 'color.iconBorder.danger'],
7
+ R400: ['color.text.danger', 'color.iconBorder.danger'],
8
+ Y300: ['color.text.warning', 'color.iconBorder.warning'],
9
+ Y400: ['color.text.warning', 'color.iconBorder.warning'],
10
+ P300: ['color.text.discovery', 'color.iconBorder.discovery'],
11
+ P400: ['color.text.discovery', 'color.iconBorder.discovery'],
12
+ G300: ['color.text.success', 'color.iconBorder.success'],
13
+ G400: ['color.text.success', 'color.iconBorder.success'],
14
+ N0: ['color.text.onBold'],
15
+ N70: ['color.text.lowEmphasis'],
16
+ N80: ['color.text.lowEmphasis'],
17
+ N90: ['color.text.lowEmphasis'],
18
+ N100: ['color.text.lowEmphasis'],
19
+ N200: ['color.text.lowEmphasis'],
20
+ N300: ['color.text.lowEmphasis'],
21
+ N400: ['color.text.mediumEmphasis'],
22
+ N500: ['color.text.mediumEmphasis'],
23
+ N600: ['color.text.mediumEmphasis'],
24
+ N700: ['color.text.highEmphasis'],
25
+ N800: ['color.text.highEmphasis'],
26
+ N900: ['color.text.highEmphasis']
27
+ },
28
+ background: {
29
+ B75: ['color.background.selected.resting'],
30
+ N40: ['color.background.subtleNeutral.resting', 'color.background.sunken'],
31
+ B50: ['color.background.subtleBrand.resting', 'color.background.selected.resting'],
32
+ Y75: ['color.background.subtleWarning.resting'],
33
+ P50: ['color.background.subtleDiscovery.resting'],
34
+ R50: ['color.background.subtleDanger.resting'],
35
+ G50: ['color.background.subtleSuccess.resting'],
36
+ P300: ['color.background.boldDiscovery.resting'],
37
+ P400: ['color.background.boldDiscovery.resting'],
38
+ G300: ['color.background.boldSuccess.resting'],
39
+ Y300: ['color.background.boldWarning.resting'],
40
+ Y500: ['color.background.boldWarning.resting'],
41
+ R400: ['color.background.boldDanger.resting'],
42
+ B400: ['color.background.boldBrand.resting'],
43
+ N0: ['color.background.default', 'color.background.overlay', 'color.background.card']
44
+ },
45
+ border: {
46
+ N10: ['color.border.neutral'],
47
+ N20: ['color.border.neutral'],
48
+ N30: ['color.border.neutral'],
49
+ N40: ['color.border.neutral'],
50
+ N50: ['color.border.neutral'],
51
+ N60: ['color.border.neutral'],
52
+ N70: ['color.border.neutral'],
53
+ B100: ['color.border.focus'],
54
+ B300: ['color.iconBorder.brand', 'color.text.selected'],
55
+ B400: ['color.iconBorder.brand', 'color.text.selected'],
56
+ R300: ['color.iconBorder.danger'],
57
+ R400: ['color.iconBorder.danger'],
58
+ Y300: ['color.iconBorder.warning'],
59
+ Y400: ['color.iconBorder.warning'],
60
+ P300: ['color.iconBorder.discovery'],
61
+ P400: ['color.iconBorder.discovery'],
62
+ G300: ['color.iconBorder.success'],
63
+ G400: ['color.iconBorder.success']
64
+ }
65
+ },
66
+ hover: {
67
+ text: {
68
+ B300: ['color.text.link.resting'],
69
+ B400: ['color.text.link.resting']
70
+ },
71
+ background: {
72
+ B50: ['color.background.selected.hover'],
73
+ B75: ['color.background.selected.hover'],
74
+ P200: ['color.background.boldDiscovery.hover'],
75
+ P300: ['color.background.boldDiscovery.hover'],
76
+ G200: ['color.background.boldSuccess.hover'],
77
+ R300: ['color.background.boldDanger.hover'],
78
+ Y200: ['color.background.boldWarning.hover'],
79
+ B300: ['color.background.boldBrand.hover']
80
+ },
81
+ border: {}
82
+ },
83
+ pressed: {
84
+ text: {
85
+ B300: ['color.text.link.pressed'],
86
+ B400: ['color.text.link.pressed']
87
+ },
88
+ background: {
89
+ B50: ['color.background.selected.pressed'],
90
+ B75: ['color.background.selected.pressed'],
91
+ P400: ['color.background.boldDiscovery.pressed'],
92
+ P500: ['color.background.boldDiscovery.pressed'],
93
+ G400: ['color.background.boldSuccess.pressed'],
94
+ R500: ['color.background.boldDanger.pressed'],
95
+ Y400: ['color.background.boldWarning.pressed'],
96
+ B500: ['color.background.boldBrand.pressed']
97
+ },
98
+ border: {}
99
+ },
100
+ disabled: {
101
+ text: {
102
+ N60: ['color.text.disabled'],
103
+ N70: ['color.text.disabled'],
104
+ N80: ['color.text.disabled'],
105
+ N90: ['color.text.disabled'],
106
+ N100: ['color.text.disabled']
107
+ },
108
+ background: {
109
+ N10: ['color.background.disabled'],
110
+ N20: ['color.background.disabled'],
111
+ N30: ['color.background.disabled'],
112
+ N40: ['color.background.disabled']
113
+ },
114
+ border: {
115
+ N10: ['color.background.disabled'],
116
+ N20: ['color.background.disabled'],
117
+ N30: ['color.background.disabled'],
118
+ N40: ['color.background.disabled']
119
+ }
120
+ }
121
+ };
122
+ export default colorMap;
@@ -0,0 +1,75 @@
1
+ import { findClosetMatchingToken } from './color-difference';
2
+ import colorTokensMap from './color-palette-tokens-map';
3
+
4
+ function normalizeName(name) {
5
+ if (!name) {
6
+ return 'unknown';
7
+ }
8
+
9
+ if (name.startsWith('background')) {
10
+ return 'background';
11
+ }
12
+
13
+ if (name.toLowerCase().includes('color') || name === 'color' || name === 'fill' || name === 'stroke') {
14
+ return 'text';
15
+ }
16
+
17
+ if (name.startsWith('border') || name.toLowerCase().replace('-', '') === 'boxshadow') {
18
+ return 'border';
19
+ }
20
+
21
+ return 'unknown';
22
+ }
23
+
24
+ export default function colorToToken(paletteName, {
25
+ state = 'resting',
26
+ propertyName
27
+ }, getLowConfidenceFuzzyResult = () => []) {
28
+ const normalizedPropertyName = normalizeName(propertyName);
29
+ const value = paletteName.toUpperCase();
30
+ const tokenSuggestionProperties = colorTokensMap[state];
31
+ const tokenSuggestionProperty = tokenSuggestionProperties && normalizedPropertyName !== 'unknown' && tokenSuggestionProperties[normalizedPropertyName];
32
+ const tokenSuggestionValue = tokenSuggestionProperty && tokenSuggestionProperty[value];
33
+
34
+ if (tokenSuggestionValue && tokenSuggestionValue.length === 1) {
35
+ return {
36
+ confidence: 'high',
37
+ suggestion: tokenSuggestionValue,
38
+ fallbackNeeded: true
39
+ };
40
+ }
41
+
42
+ if (tokenSuggestionValue && tokenSuggestionValue.length > 2) {
43
+ return {
44
+ confidence: 'medium',
45
+ suggestion: tokenSuggestionValue,
46
+ fallbackNeeded: true
47
+ };
48
+ }
49
+
50
+ const closestTokenName = findClosetMatchingToken(value);
51
+
52
+ if (closestTokenName) {
53
+ return {
54
+ confidence: 'low',
55
+ suggestion: [closestTokenName],
56
+ fallbackNeeded: true
57
+ };
58
+ }
59
+
60
+ const fuzzyResult = getLowConfidenceFuzzyResult();
61
+
62
+ if (fuzzyResult.length) {
63
+ return {
64
+ confidence: 'low',
65
+ suggestion: fuzzyResult,
66
+ fallbackNeeded: true
67
+ };
68
+ }
69
+
70
+ return {
71
+ confidence: 'unknown',
72
+ suggestion: [],
73
+ fallbackNeeded: true
74
+ };
75
+ }
@@ -0,0 +1,35 @@
1
+ import { legacyColorMixins, legacyColors } from './legacy-colors';
2
+ import { namedColors } from './named-colors';
3
+ export const isLegacyColor = value => legacyColors.includes(value);
4
+ export const isLegacyNamedColor = value => legacyColorMixins.includes(value);
5
+ export const includesHardCodedColor = raw => {
6
+ const value = raw.toLowerCase();
7
+
8
+ if (/#(?:[a-f0-9]{3}|[a-f0-9]{6}|[a-f0-9]{8})\b|(?:rgb|hsl)a?\([^\)]*\)/.exec(value.toLowerCase())) {
9
+ return true;
10
+ }
11
+
12
+ for (let i = 0; i < namedColors.length; i++) {
13
+ if (value.includes(`${namedColors[i]};`)) {
14
+ return true;
15
+ }
16
+ }
17
+
18
+ return false;
19
+ };
20
+ export const isHardCodedColor = value => {
21
+ if (namedColors.includes(value.toLowerCase())) {
22
+ return true;
23
+ }
24
+
25
+ if (value.startsWith('rgb(') || value.startsWith('rgba(') || value.startsWith('hsl(') || value.startsWith('hsla(') || value.startsWith('lch(') || value.startsWith('lab(') || value.startsWith('color(')) {
26
+ return true;
27
+ }
28
+
29
+ if (value.startsWith('#') && ( // short hex, hex, or hex with alpha
30
+ value.length === 4 || value.length === 7 || value.length === 9)) {
31
+ return true;
32
+ }
33
+
34
+ return false;
35
+ };