@atlaskit/eslint-plugin-design-system 11.1.0 → 11.3.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 +39 -0
- package/dist/cjs/rules/no-deprecated-apis/index.js +13 -26
- package/dist/cjs/rules/no-legacy-icons/checks.js +14 -3
- package/dist/cjs/rules/no-legacy-icons/helpers.js +3 -14
- package/dist/cjs/rules/no-legacy-icons/index.js +3 -0
- package/dist/cjs/rules/use-tokens-typography/config/index.js +2 -1
- package/dist/cjs/rules/use-tokens-typography/index.js +15 -6
- package/dist/cjs/rules/use-tokens-typography/transformers/font-weight.js +96 -0
- package/dist/cjs/rules/use-tokens-typography/transformers/style-object.js +5 -0
- package/dist/cjs/rules/use-tokens-typography/utils.js +6 -0
- package/dist/es2019/rules/no-deprecated-apis/index.js +14 -23
- package/dist/es2019/rules/no-legacy-icons/checks.js +14 -3
- package/dist/es2019/rules/no-legacy-icons/helpers.js +3 -14
- package/dist/es2019/rules/no-legacy-icons/index.js +3 -0
- package/dist/es2019/rules/use-tokens-typography/config/index.js +2 -1
- package/dist/es2019/rules/use-tokens-typography/index.js +13 -6
- package/dist/es2019/rules/use-tokens-typography/transformers/font-weight.js +92 -0
- package/dist/es2019/rules/use-tokens-typography/transformers/style-object.js +5 -0
- package/dist/es2019/rules/use-tokens-typography/utils.js +6 -0
- package/dist/esm/rules/no-deprecated-apis/index.js +14 -26
- package/dist/esm/rules/no-legacy-icons/checks.js +14 -3
- package/dist/esm/rules/no-legacy-icons/helpers.js +3 -14
- package/dist/esm/rules/no-legacy-icons/index.js +3 -0
- package/dist/esm/rules/use-tokens-typography/config/index.js +2 -1
- package/dist/esm/rules/use-tokens-typography/index.js +15 -6
- package/dist/esm/rules/use-tokens-typography/transformers/font-weight.js +90 -0
- package/dist/esm/rules/use-tokens-typography/transformers/style-object.js +5 -0
- package/dist/esm/rules/use-tokens-typography/utils.js +6 -0
- package/dist/types/index.codegen.d.ts +3 -9
- package/dist/types/rules/index.codegen.d.ts +1 -3
- package/dist/types/rules/no-deprecated-apis/index.d.ts +2 -4
- package/dist/types/rules/no-legacy-icons/helpers.d.ts +1 -0
- package/dist/types/rules/use-tokens-typography/config/index.d.ts +3 -0
- package/dist/types/rules/use-tokens-typography/transformers/font-weight.d.ts +13 -0
- package/dist/types-ts4.5/index.codegen.d.ts +3 -15
- package/dist/types-ts4.5/rules/index.codegen.d.ts +1 -5
- package/dist/types-ts4.5/rules/no-deprecated-apis/index.d.ts +2 -6
- package/dist/types-ts4.5/rules/no-legacy-icons/helpers.d.ts +1 -0
- package/dist/types-ts4.5/rules/use-tokens-typography/config/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/use-tokens-typography/transformers/font-weight.d.ts +13 -0
- package/package.json +2 -2
|
@@ -20,7 +20,8 @@ export const ruleSchema = {
|
|
|
20
20
|
const defaultConfig = {
|
|
21
21
|
failSilently: false,
|
|
22
22
|
shouldEnforceFallbacks: false,
|
|
23
|
-
enableUnsafeAutofix: false
|
|
23
|
+
enableUnsafeAutofix: false,
|
|
24
|
+
patterns: ['style-object']
|
|
24
25
|
};
|
|
25
26
|
export const getConfig = overrides => {
|
|
26
27
|
return Object.assign({}, defaultConfig, overrides);
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
import { createLintRule } from '../utils/create-rule';
|
|
2
2
|
import { errorBoundary } from '../utils/error-boundary';
|
|
3
3
|
import { getConfig, ruleSchema } from './config';
|
|
4
|
+
import { FontWeight } from './transformers/font-weight';
|
|
4
5
|
import { StyleObject } from './transformers/style-object';
|
|
5
6
|
const create = context => {
|
|
6
7
|
const config = getConfig(context.options[0]);
|
|
7
|
-
return {
|
|
8
|
-
// const styles = css({ fontSize: '14px, ... }), styled.div({ fontSize: 14, ... })
|
|
9
|
-
ObjectExpression:
|
|
8
|
+
return errorBoundary({
|
|
9
|
+
// const styles = css({ fontSize: '14px', ... }), styled.div({ fontSize: 14, ... })
|
|
10
|
+
ObjectExpression: node => StyleObject.lint(node, {
|
|
10
11
|
context,
|
|
11
12
|
config
|
|
12
|
-
}),
|
|
13
|
-
|
|
13
|
+
}),
|
|
14
|
+
// const styles = css({ fontWeight: 600, 'bold', ... })
|
|
15
|
+
'ObjectExpression > Property > Identifier[name=/fontWeight/]': node => FontWeight.lint(node, {
|
|
16
|
+
context,
|
|
17
|
+
config
|
|
18
|
+
})
|
|
19
|
+
}, config);
|
|
14
20
|
};
|
|
15
21
|
const rule = createLintRule({
|
|
16
22
|
meta: {
|
|
@@ -24,7 +30,8 @@ const rule = createLintRule({
|
|
|
24
30
|
severity: 'warn'
|
|
25
31
|
},
|
|
26
32
|
messages: {
|
|
27
|
-
noRawTypographyValues: 'Typography primitives or tokens should be used instead of hard-coded values.\n\n@meta <<{{payload}}>>.\n\nNOTE: Using tokens with the `fontSize` property is invalid. Any `font.heading` or `font.body` tokens must use the CSS `font` property.'
|
|
33
|
+
noRawTypographyValues: 'Typography primitives or tokens should be used instead of hard-coded values.\n\n@meta <<{{payload}}>>.\n\nNOTE: Using tokens with the `fontSize` property is invalid. Any `font.heading` or `font.body` tokens must use the CSS `font` property.',
|
|
34
|
+
noRawFontWeightValues: 'Font weight tokens should be used instead of hard-coded values.'
|
|
28
35
|
},
|
|
29
36
|
schema: ruleSchema
|
|
30
37
|
},
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/* eslint-disable @repo/internal/react/require-jsdoc */
|
|
2
|
+
|
|
3
|
+
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
4
|
+
import { Root } from '../../../ast-nodes';
|
|
5
|
+
import { getValueForPropertyNode } from '../../ensure-design-token-usage/utils';
|
|
6
|
+
import { isDecendantOfStyleBlock, isDecendantOfType } from '../../utils/is-node';
|
|
7
|
+
import { findFontWeightTokenForValue, insertTokensImport } from '../utils';
|
|
8
|
+
export const FontWeight = {
|
|
9
|
+
lint(node, {
|
|
10
|
+
context,
|
|
11
|
+
config
|
|
12
|
+
}) {
|
|
13
|
+
// To force the correct node type
|
|
14
|
+
if (!isNodeOfType(node, 'Identifier')) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Check whether all criteria needed to make a transformation are met
|
|
19
|
+
const success = FontWeight._check(node, {
|
|
20
|
+
context,
|
|
21
|
+
config
|
|
22
|
+
});
|
|
23
|
+
if (success) {
|
|
24
|
+
return context.report({
|
|
25
|
+
node,
|
|
26
|
+
messageId: 'noRawFontWeightValues',
|
|
27
|
+
fix: FontWeight._fix(node, context)
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
_check(node, {
|
|
32
|
+
context,
|
|
33
|
+
config
|
|
34
|
+
}) {
|
|
35
|
+
if (!config.patterns.includes('font-weight')) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
if (!isDecendantOfStyleBlock(node) && !isDecendantOfType(node, 'JSXExpressionContainer')) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
if (!isNodeOfType(node.parent, 'Property')) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
const fontWeightValue = getValueForPropertyNode(node.parent, context);
|
|
45
|
+
if (typeof fontWeightValue === 'string' && fontWeightValue.includes('font.weight.')) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
return true;
|
|
49
|
+
},
|
|
50
|
+
_fix(node, context) {
|
|
51
|
+
return fixer => {
|
|
52
|
+
var _findFontWeightTokenF;
|
|
53
|
+
const fixes = [];
|
|
54
|
+
|
|
55
|
+
// -- Type assertions to force the correct node type --
|
|
56
|
+
|
|
57
|
+
if (!isNodeOfType(node.parent, 'Property')) {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
if (!isNodeOfType(node.parent.value, 'Literal')) {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
if (!node.parent.value.raw) {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// -- Fix: Replace raw value with token --
|
|
68
|
+
|
|
69
|
+
const matchingToken = (_findFontWeightTokenF = findFontWeightTokenForValue(node.parent.value.raw)) === null || _findFontWeightTokenF === void 0 ? void 0 : _findFontWeightTokenF.tokenName;
|
|
70
|
+
if (!matchingToken) {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
const fontWeightValueFix = fixer.replaceText(node.parent.value, `token('${matchingToken}')`);
|
|
74
|
+
fixes.push(fontWeightValueFix);
|
|
75
|
+
|
|
76
|
+
// -- Fix: Add import if it doesn't exist --
|
|
77
|
+
|
|
78
|
+
const body = context.sourceCode.ast.body;
|
|
79
|
+
const tokensImportDeclarations = Root.findImportsByModule(body, '@atlaskit/tokens');
|
|
80
|
+
|
|
81
|
+
// If there is more than one `@atlaskit/tokens` import, then it becomes difficult to determine which import to transform
|
|
82
|
+
if (tokensImportDeclarations.length > 1) {
|
|
83
|
+
return fixes;
|
|
84
|
+
}
|
|
85
|
+
const tokensImportDeclaration = tokensImportDeclarations[0];
|
|
86
|
+
if (!tokensImportDeclaration) {
|
|
87
|
+
fixes.push(insertTokensImport(body, fixer));
|
|
88
|
+
}
|
|
89
|
+
return fixes;
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
};
|
|
@@ -198,6 +198,11 @@ export const StyleObject = {
|
|
|
198
198
|
context,
|
|
199
199
|
config
|
|
200
200
|
}) {
|
|
201
|
+
if (!config.patterns.includes('style-object')) {
|
|
202
|
+
return {
|
|
203
|
+
success: false
|
|
204
|
+
};
|
|
205
|
+
}
|
|
201
206
|
if (!isDecendantOfStyleBlock(node) && !isDecendantOfType(node, 'JSXExpressionContainer')) {
|
|
202
207
|
return {
|
|
203
208
|
success: false
|
|
@@ -48,6 +48,12 @@ export const fontWeightTokens = typographyTokens.filter(token => token.attribute
|
|
|
48
48
|
};
|
|
49
49
|
});
|
|
50
50
|
export function findFontWeightTokenForValue(fontWeight) {
|
|
51
|
+
if (fontWeight === "'normal'") {
|
|
52
|
+
fontWeight = '400';
|
|
53
|
+
}
|
|
54
|
+
if (fontWeight === "'bold'") {
|
|
55
|
+
fontWeight = '700';
|
|
56
|
+
}
|
|
51
57
|
return fontWeightTokens.find(token => token.tokenValue === fontWeight);
|
|
52
58
|
}
|
|
53
59
|
export const fontWeightMap = {
|
|
@@ -1,36 +1,30 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { createRule } from '../utils/create-rule';
|
|
1
|
+
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
2
|
+
import { createLintRule } from '../utils/create-rule';
|
|
4
3
|
import { getConfig } from '../utils/get-deprecated-config';
|
|
5
4
|
import { isDeprecatedJSXAttributeConfig } from '../utils/types';
|
|
6
5
|
export var noDeprecatedJSXAttributeMessageId = 'noDeprecatedJSXAttributes';
|
|
7
|
-
var isNodeOfType = function isNodeOfType(node, nodeType) {
|
|
8
|
-
return ASTUtils.isNodeOfType(nodeType)(node);
|
|
9
|
-
};
|
|
10
6
|
var isImportDeclaration = function isImportDeclaration(programStatement) {
|
|
11
7
|
return (programStatement === null || programStatement === void 0 ? void 0 : programStatement.type) === 'ImportDeclaration';
|
|
12
8
|
};
|
|
13
9
|
var findJSXElementName = function findJSXElementName(jsxAttributeNode) {
|
|
14
|
-
if (!jsxAttributeNode.parent || !isNodeOfType(jsxAttributeNode.parent,
|
|
10
|
+
if (!jsxAttributeNode.parent || !isNodeOfType(jsxAttributeNode === null || jsxAttributeNode === void 0 ? void 0 : jsxAttributeNode.parent, 'JSXOpeningElement')) {
|
|
15
11
|
return;
|
|
16
12
|
}
|
|
17
13
|
var openingElement = jsxAttributeNode.parent;
|
|
18
|
-
if (!isNodeOfType(openingElement.name,
|
|
14
|
+
if (!isNodeOfType(openingElement.name, 'JSXIdentifier')) {
|
|
19
15
|
return;
|
|
20
16
|
}
|
|
21
17
|
return openingElement.name.name;
|
|
22
18
|
};
|
|
23
19
|
export var name = 'no-deprecated-apis';
|
|
24
|
-
var rule =
|
|
25
|
-
name: name,
|
|
26
|
-
defaultOptions: [{
|
|
27
|
-
deprecatedConfig: getConfig('jsxAttributes')
|
|
28
|
-
}],
|
|
20
|
+
var rule = createLintRule({
|
|
29
21
|
meta: {
|
|
22
|
+
name: name,
|
|
30
23
|
type: 'suggestion',
|
|
31
24
|
docs: {
|
|
32
25
|
description: 'Disallow using deprecated APIs.',
|
|
33
|
-
recommended:
|
|
26
|
+
recommended: true,
|
|
27
|
+
severity: 'error'
|
|
34
28
|
},
|
|
35
29
|
messages: {
|
|
36
30
|
noDeprecatedJSXAttributes: 'The JSX attribute {{propName}} has been deprecated.'
|
|
@@ -68,24 +62,18 @@ var rule = createRule({
|
|
|
68
62
|
}
|
|
69
63
|
}]
|
|
70
64
|
},
|
|
71
|
-
create: function create(context
|
|
65
|
+
create: function create(context) {
|
|
72
66
|
var _context$options$;
|
|
73
|
-
var _ref2 = _slicedToArray(_ref, 1),
|
|
74
|
-
options = _ref2[0];
|
|
75
|
-
// Get rule configuration
|
|
76
|
-
var defaultDeprecatedConfig = options.deprecatedConfig;
|
|
77
|
-
|
|
78
67
|
// Get the rule configuration specified otherwise use default config.
|
|
79
68
|
// A bit confusing as it seems that the default options have precedence over the user specified options.
|
|
80
|
-
var deprecatedConfig = ((_context$options$ = context.options[0]) === null || _context$options$ === void 0 ? void 0 : _context$options$.deprecatedConfig) ||
|
|
69
|
+
var deprecatedConfig = ((_context$options$ = context.options[0]) === null || _context$options$ === void 0 ? void 0 : _context$options$.deprecatedConfig) || getConfig('jsxAttributes');
|
|
81
70
|
return {
|
|
82
71
|
// find JSX atribute - find name of attribute - get source and find relevant identifiers.
|
|
83
72
|
JSXAttribute: function JSXAttribute(node) {
|
|
84
|
-
|
|
85
|
-
if (!isNodeOfType(jsxAttributeIdentifier, AST_NODE_TYPES.JSXIdentifier)) {
|
|
73
|
+
if (!isNodeOfType(node, 'JSXAttribute') || !isNodeOfType(node.name, 'JSXIdentifier')) {
|
|
86
74
|
return;
|
|
87
75
|
}
|
|
88
|
-
var jsxAttributeName =
|
|
76
|
+
var jsxAttributeName = node.name.name;
|
|
89
77
|
if (!isDeprecatedJSXAttributeConfig(deprecatedConfig) || !deprecatedConfig[jsxAttributeName]) {
|
|
90
78
|
return;
|
|
91
79
|
}
|
|
@@ -93,13 +81,13 @@ var rule = createRule({
|
|
|
93
81
|
if (!jsxElementName) {
|
|
94
82
|
return;
|
|
95
83
|
}
|
|
96
|
-
var source = context.
|
|
84
|
+
var source = context.sourceCode;
|
|
97
85
|
|
|
98
86
|
// find an import for the path of the banned api
|
|
99
87
|
deprecatedConfig[jsxAttributeName].forEach(function (importItem) {
|
|
100
88
|
var _importItem$namedSpec;
|
|
101
89
|
var importNode = source.ast.body.filter(isImportDeclaration).find(function (node) {
|
|
102
|
-
return node.source.value.includes(importItem.moduleSpecifier);
|
|
90
|
+
return node && node.source.value && typeof node.source.value === 'string' && node.source.value.includes(importItem.moduleSpecifier);
|
|
103
91
|
});
|
|
104
92
|
if (!importNode) {
|
|
105
93
|
return;
|
|
@@ -4,7 +4,7 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
|
|
|
4
4
|
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
5
5
|
import { addToListOfRanges, canAutoMigrateNewIconBasedOnSize, canMigrateColor, createAutoMigrationError, createCantFindSuitableReplacementError, createCantMigrateColorError, createCantMigrateFunctionUnknownError, createCantMigrateIdentifierError, createCantMigrateIdentifierMapOrArrayError, createCantMigrateReExportError, createCantMigrateSizeUnknown, createCantMigrateSpreadPropsError, createGuidance, createHelpers, getMigrationMapObject, getUpcomingIcons, isInsideLegacyButton, isInsideNewButton, isSize, locToString, throwAutoErrors, throwManualErrors } from './helpers';
|
|
6
6
|
export var createChecks = function createChecks(context) {
|
|
7
|
-
//
|
|
7
|
+
// Create global variables to be shared by the checks
|
|
8
8
|
var _createHelpers = createHelpers(context),
|
|
9
9
|
getPrimaryColor = _createHelpers.getPrimaryColor,
|
|
10
10
|
getConfigFlag = _createHelpers.getConfigFlag;
|
|
@@ -21,6 +21,7 @@ export var createChecks = function createChecks(context) {
|
|
|
21
21
|
var shouldErrorForAutoMigration = getConfigFlag('shouldErrorForAutoMigration', true);
|
|
22
22
|
var isQuietMode = getConfigFlag('quiet', false);
|
|
23
23
|
var shouldUseMigrationPath = getConfigFlag('shouldUseMigrationPath', true);
|
|
24
|
+
var shouldUseSafeMigrationMode = getConfigFlag('shouldUseSafeMigrationMode', false);
|
|
24
25
|
|
|
25
26
|
// Sorted list of ranges
|
|
26
27
|
var errorRanges = [];
|
|
@@ -405,10 +406,11 @@ export var createChecks = function createChecks(context) {
|
|
|
405
406
|
// Find size prop on node
|
|
406
407
|
var size = 'medium';
|
|
407
408
|
var primaryColor = null;
|
|
409
|
+
var hasPrimaryColorProp = false;
|
|
410
|
+
var hasSecondaryColorProp = false;
|
|
408
411
|
var afterSpreadSet = new Set();
|
|
409
412
|
var requiredAttributesAfterSpread = new Set(['size', 'primaryColor', 'secondaryColor']);
|
|
410
413
|
var hasSpread = false;
|
|
411
|
-
var hasPrimaryColorProp = false;
|
|
412
414
|
var _iterator8 = _createForOfIteratorHelper(node.openingElement.attributes),
|
|
413
415
|
_step8;
|
|
414
416
|
try {
|
|
@@ -443,6 +445,9 @@ export var createChecks = function createChecks(context) {
|
|
|
443
445
|
primaryColor = getPrimaryColor(attr);
|
|
444
446
|
hasPrimaryColorProp = true;
|
|
445
447
|
break;
|
|
448
|
+
case 'secondaryColor':
|
|
449
|
+
hasSecondaryColorProp = true;
|
|
450
|
+
break;
|
|
446
451
|
}
|
|
447
452
|
}
|
|
448
453
|
} catch (err) {
|
|
@@ -451,6 +456,8 @@ export var createChecks = function createChecks(context) {
|
|
|
451
456
|
_iterator8.f();
|
|
452
457
|
}
|
|
453
458
|
var hasManualMigration = false;
|
|
459
|
+
|
|
460
|
+
// Flag manual migration if primary color cannot be migrated
|
|
454
461
|
if (primaryColor && !canMigrateColor(primaryColor) || hasPrimaryColorProp && !primaryColor) {
|
|
455
462
|
createCantMigrateColorError(node, primaryColor ? "the value of '".concat(primaryColor, "'") : 'a statically unknown value', errorsManual, legacyIconImports[name].packageName, name);
|
|
456
463
|
hasManualMigration = true;
|
|
@@ -462,6 +469,7 @@ export var createChecks = function createChecks(context) {
|
|
|
462
469
|
createCantMigrateSizeUnknown(node, errorsManual, legacyIconImports[name].packageName, name);
|
|
463
470
|
hasManualMigration = true;
|
|
464
471
|
}
|
|
472
|
+
|
|
465
473
|
// Do a set comparison - is requiredAttributesAfterSpread a subset of afterSpreadSet?
|
|
466
474
|
if (hasSpread === true && !Array.from(requiredAttributesAfterSpread).every(function (val) {
|
|
467
475
|
return afterSpreadSet.has(val);
|
|
@@ -472,6 +480,7 @@ export var createChecks = function createChecks(context) {
|
|
|
472
480
|
createCantMigrateSpreadPropsError(node, missingProps, errorsManual, legacyIconImports[name].packageName, name);
|
|
473
481
|
hasManualMigration = true;
|
|
474
482
|
}
|
|
483
|
+
|
|
475
484
|
// Check if it is an exported component?
|
|
476
485
|
if (legacyIconImports[name].exported) {
|
|
477
486
|
createCantMigrateReExportError(node, legacyIconImports[name].packageName, name, errorsManual);
|
|
@@ -501,7 +510,9 @@ export var createChecks = function createChecks(context) {
|
|
|
501
510
|
spacing = 'spacious';
|
|
502
511
|
}
|
|
503
512
|
}
|
|
504
|
-
if (!hasManualMigration && (newIcon
|
|
513
|
+
if (shouldUseSafeMigrationMode && !hasManualMigration && (newIcon !== null && newIcon !== void 0 && newIcon.isMigrationUnsafe || size !== 'medium' || hasSecondaryColorProp)) {
|
|
514
|
+
createCantFindSuitableReplacementError(node, legacyIconImports[name].packageName, name, errorsManual, upcomingIcon ? true : migrationMapObject ? true : false);
|
|
515
|
+
} else if (!hasManualMigration && (newIcon || upcomingIcon) && isNewIconMigratable) {
|
|
505
516
|
createAutoMigrationError({
|
|
506
517
|
node: node,
|
|
507
518
|
importSource: legacyIconImports[name].packageName,
|
|
@@ -470,8 +470,7 @@ var createPropFixes = function createPropFixes(_ref7) {
|
|
|
470
470
|
migrationImportNode = _ref7.migrationImportNode,
|
|
471
471
|
newIconName = _ref7.newIconName;
|
|
472
472
|
var fixes = [];
|
|
473
|
-
var spacing = metadata.spacing
|
|
474
|
-
insideNewButton = metadata.insideNewButton;
|
|
473
|
+
var spacing = metadata.spacing;
|
|
475
474
|
if (shouldUseMigrationPath && !legacyImportNode) {
|
|
476
475
|
return fixes;
|
|
477
476
|
}
|
|
@@ -488,16 +487,6 @@ var createPropFixes = function createPropFixes(_ref7) {
|
|
|
488
487
|
fixes.push(fixer.replaceText(primaryColor.name, 'color'));
|
|
489
488
|
}
|
|
490
489
|
|
|
491
|
-
// add color="currentColor" if
|
|
492
|
-
// 1. primaryColor prop is not set
|
|
493
|
-
// 2. icon is not imported from migration entrypoint
|
|
494
|
-
// 3. icon element is not inside a new button
|
|
495
|
-
if (legacyImportNode && !primaryColor && !migrationImportNode &&
|
|
496
|
-
// value type need to be a string in Rule.ReportDescriptor
|
|
497
|
-
insideNewButton !== 'true') {
|
|
498
|
-
fixes.push(fixer.insertTextAfter(openingElement.name, " color=\"currentColor\""));
|
|
499
|
-
}
|
|
500
|
-
|
|
501
490
|
// rename or remove size prop based on shouldUseMigrationPath,
|
|
502
491
|
// add spacing="spacious" if
|
|
503
492
|
// 1. it's in error metadata, which means size is medium
|
|
@@ -627,12 +616,12 @@ export var throwAutoErrors = function throwAutoErrors(_ref10) {
|
|
|
627
616
|
}
|
|
628
617
|
return result;
|
|
629
618
|
}, new Set());
|
|
630
|
-
//
|
|
619
|
+
// Group errors by import source and remove any unwanted errors
|
|
631
620
|
var groupedErrorList = Object.entries(errorsAuto).reduce(function (result, option) {
|
|
632
621
|
var _option2 = _slicedToArray(option, 2),
|
|
633
622
|
key = _option2[0],
|
|
634
623
|
error = _option2[1];
|
|
635
|
-
//
|
|
624
|
+
// Return early if no data
|
|
636
625
|
if (!error.data) {
|
|
637
626
|
return result;
|
|
638
627
|
}
|
|
@@ -20,7 +20,8 @@ export var ruleSchema = {
|
|
|
20
20
|
var defaultConfig = {
|
|
21
21
|
failSilently: false,
|
|
22
22
|
shouldEnforceFallbacks: false,
|
|
23
|
-
enableUnsafeAutofix: false
|
|
23
|
+
enableUnsafeAutofix: false,
|
|
24
|
+
patterns: ['style-object']
|
|
24
25
|
};
|
|
25
26
|
export var getConfig = function getConfig(overrides) {
|
|
26
27
|
return Object.assign({}, defaultConfig, overrides);
|
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
import { createLintRule } from '../utils/create-rule';
|
|
2
2
|
import { errorBoundary } from '../utils/error-boundary';
|
|
3
3
|
import { getConfig, ruleSchema } from './config';
|
|
4
|
+
import { FontWeight } from './transformers/font-weight';
|
|
4
5
|
import { StyleObject } from './transformers/style-object';
|
|
5
6
|
var create = function create(context) {
|
|
6
7
|
var config = getConfig(context.options[0]);
|
|
7
|
-
return {
|
|
8
|
-
// const styles = css({ fontSize: '14px, ... }), styled.div({ fontSize: 14, ... })
|
|
9
|
-
ObjectExpression:
|
|
8
|
+
return errorBoundary({
|
|
9
|
+
// const styles = css({ fontSize: '14px', ... }), styled.div({ fontSize: 14, ... })
|
|
10
|
+
ObjectExpression: function ObjectExpression(node) {
|
|
10
11
|
return StyleObject.lint(node, {
|
|
11
12
|
context: context,
|
|
12
13
|
config: config
|
|
13
14
|
});
|
|
14
|
-
},
|
|
15
|
-
|
|
15
|
+
},
|
|
16
|
+
// const styles = css({ fontWeight: 600, 'bold', ... })
|
|
17
|
+
'ObjectExpression > Property > Identifier[name=/fontWeight/]': function ObjectExpressionPropertyIdentifierNameFontWeight(node) {
|
|
18
|
+
return FontWeight.lint(node, {
|
|
19
|
+
context: context,
|
|
20
|
+
config: config
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}, config);
|
|
16
24
|
};
|
|
17
25
|
var rule = createLintRule({
|
|
18
26
|
meta: {
|
|
@@ -26,7 +34,8 @@ var rule = createLintRule({
|
|
|
26
34
|
severity: 'warn'
|
|
27
35
|
},
|
|
28
36
|
messages: {
|
|
29
|
-
noRawTypographyValues: 'Typography primitives or tokens should be used instead of hard-coded values.\n\n@meta <<{{payload}}>>.\n\nNOTE: Using tokens with the `fontSize` property is invalid. Any `font.heading` or `font.body` tokens must use the CSS `font` property.'
|
|
37
|
+
noRawTypographyValues: 'Typography primitives or tokens should be used instead of hard-coded values.\n\n@meta <<{{payload}}>>.\n\nNOTE: Using tokens with the `fontSize` property is invalid. Any `font.heading` or `font.body` tokens must use the CSS `font` property.',
|
|
38
|
+
noRawFontWeightValues: 'Font weight tokens should be used instead of hard-coded values.'
|
|
30
39
|
},
|
|
31
40
|
schema: ruleSchema
|
|
32
41
|
},
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/* eslint-disable @repo/internal/react/require-jsdoc */
|
|
2
|
+
|
|
3
|
+
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
4
|
+
import { Root } from '../../../ast-nodes';
|
|
5
|
+
import { getValueForPropertyNode } from '../../ensure-design-token-usage/utils';
|
|
6
|
+
import { isDecendantOfStyleBlock, isDecendantOfType } from '../../utils/is-node';
|
|
7
|
+
import { findFontWeightTokenForValue, insertTokensImport } from '../utils';
|
|
8
|
+
export var FontWeight = {
|
|
9
|
+
lint: function lint(node, _ref) {
|
|
10
|
+
var context = _ref.context,
|
|
11
|
+
config = _ref.config;
|
|
12
|
+
// To force the correct node type
|
|
13
|
+
if (!isNodeOfType(node, 'Identifier')) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Check whether all criteria needed to make a transformation are met
|
|
18
|
+
var success = FontWeight._check(node, {
|
|
19
|
+
context: context,
|
|
20
|
+
config: config
|
|
21
|
+
});
|
|
22
|
+
if (success) {
|
|
23
|
+
return context.report({
|
|
24
|
+
node: node,
|
|
25
|
+
messageId: 'noRawFontWeightValues',
|
|
26
|
+
fix: FontWeight._fix(node, context)
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
_check: function _check(node, _ref2) {
|
|
31
|
+
var context = _ref2.context,
|
|
32
|
+
config = _ref2.config;
|
|
33
|
+
if (!config.patterns.includes('font-weight')) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
if (!isDecendantOfStyleBlock(node) && !isDecendantOfType(node, 'JSXExpressionContainer')) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
if (!isNodeOfType(node.parent, 'Property')) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
var fontWeightValue = getValueForPropertyNode(node.parent, context);
|
|
43
|
+
if (typeof fontWeightValue === 'string' && fontWeightValue.includes('font.weight.')) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
},
|
|
48
|
+
_fix: function _fix(node, context) {
|
|
49
|
+
return function (fixer) {
|
|
50
|
+
var _findFontWeightTokenF;
|
|
51
|
+
var fixes = [];
|
|
52
|
+
|
|
53
|
+
// -- Type assertions to force the correct node type --
|
|
54
|
+
|
|
55
|
+
if (!isNodeOfType(node.parent, 'Property')) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
if (!isNodeOfType(node.parent.value, 'Literal')) {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
if (!node.parent.value.raw) {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// -- Fix: Replace raw value with token --
|
|
66
|
+
|
|
67
|
+
var matchingToken = (_findFontWeightTokenF = findFontWeightTokenForValue(node.parent.value.raw)) === null || _findFontWeightTokenF === void 0 ? void 0 : _findFontWeightTokenF.tokenName;
|
|
68
|
+
if (!matchingToken) {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
var fontWeightValueFix = fixer.replaceText(node.parent.value, "token('".concat(matchingToken, "')"));
|
|
72
|
+
fixes.push(fontWeightValueFix);
|
|
73
|
+
|
|
74
|
+
// -- Fix: Add import if it doesn't exist --
|
|
75
|
+
|
|
76
|
+
var body = context.sourceCode.ast.body;
|
|
77
|
+
var tokensImportDeclarations = Root.findImportsByModule(body, '@atlaskit/tokens');
|
|
78
|
+
|
|
79
|
+
// If there is more than one `@atlaskit/tokens` import, then it becomes difficult to determine which import to transform
|
|
80
|
+
if (tokensImportDeclarations.length > 1) {
|
|
81
|
+
return fixes;
|
|
82
|
+
}
|
|
83
|
+
var tokensImportDeclaration = tokensImportDeclarations[0];
|
|
84
|
+
if (!tokensImportDeclaration) {
|
|
85
|
+
fixes.push(insertTokensImport(body, fixer));
|
|
86
|
+
}
|
|
87
|
+
return fixes;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
};
|
|
@@ -199,6 +199,11 @@ export var StyleObject = {
|
|
|
199
199
|
_check: function _check(node, _ref2) {
|
|
200
200
|
var context = _ref2.context,
|
|
201
201
|
config = _ref2.config;
|
|
202
|
+
if (!config.patterns.includes('style-object')) {
|
|
203
|
+
return {
|
|
204
|
+
success: false
|
|
205
|
+
};
|
|
206
|
+
}
|
|
202
207
|
if (!isDecendantOfStyleBlock(node) && !isDecendantOfType(node, 'JSXExpressionContainer')) {
|
|
203
208
|
return {
|
|
204
209
|
success: false
|
|
@@ -78,6 +78,12 @@ export var fontWeightTokens = typographyTokens.filter(function (token) {
|
|
|
78
78
|
};
|
|
79
79
|
});
|
|
80
80
|
export function findFontWeightTokenForValue(fontWeight) {
|
|
81
|
+
if (fontWeight === "'normal'") {
|
|
82
|
+
fontWeight = '400';
|
|
83
|
+
}
|
|
84
|
+
if (fontWeight === "'bold'") {
|
|
85
|
+
fontWeight = '700';
|
|
86
|
+
}
|
|
81
87
|
return fontWeightTokens.find(function (token) {
|
|
82
88
|
return token.tokenValue === fontWeight;
|
|
83
89
|
});
|
|
@@ -13,9 +13,7 @@ export declare const plugin: {
|
|
|
13
13
|
'no-css-tagged-template-expression': import("eslint").Rule.RuleModule;
|
|
14
14
|
'no-custom-icons': import("eslint").Rule.RuleModule;
|
|
15
15
|
'no-dark-theme-vr-tests': import("eslint").Rule.RuleModule;
|
|
16
|
-
'no-deprecated-apis': import("
|
|
17
|
-
deprecatedConfig: import("./rules/utils/types").DeprecatedConfig;
|
|
18
|
-
}], import("@typescript-eslint/utils/dist/ts-eslint").RuleListener>;
|
|
16
|
+
'no-deprecated-apis': import("eslint").Rule.RuleModule;
|
|
19
17
|
'no-deprecated-design-token-usage': import("eslint").Rule.RuleModule;
|
|
20
18
|
'no-deprecated-imports': import("eslint").Rule.RuleModule;
|
|
21
19
|
'no-direct-use-of-web-platform-drag-and-drop': import("eslint").Rule.RuleModule;
|
|
@@ -303,9 +301,7 @@ export declare const configs: {
|
|
|
303
301
|
'no-css-tagged-template-expression': import("eslint").Rule.RuleModule;
|
|
304
302
|
'no-custom-icons': import("eslint").Rule.RuleModule;
|
|
305
303
|
'no-dark-theme-vr-tests': import("eslint").Rule.RuleModule;
|
|
306
|
-
'no-deprecated-apis': import("
|
|
307
|
-
deprecatedConfig: import("./rules/utils/types").DeprecatedConfig;
|
|
308
|
-
}], import("@typescript-eslint/utils/dist/ts-eslint").RuleListener>;
|
|
304
|
+
'no-deprecated-apis': import("eslint").Rule.RuleModule;
|
|
309
305
|
'no-deprecated-design-token-usage': import("eslint").Rule.RuleModule;
|
|
310
306
|
'no-deprecated-imports': import("eslint").Rule.RuleModule;
|
|
311
307
|
'no-direct-use-of-web-platform-drag-and-drop': import("eslint").Rule.RuleModule;
|
|
@@ -448,9 +444,7 @@ export declare const configs: {
|
|
|
448
444
|
'no-css-tagged-template-expression': import("eslint").Rule.RuleModule;
|
|
449
445
|
'no-custom-icons': import("eslint").Rule.RuleModule;
|
|
450
446
|
'no-dark-theme-vr-tests': import("eslint").Rule.RuleModule;
|
|
451
|
-
'no-deprecated-apis': import("
|
|
452
|
-
deprecatedConfig: import("./rules/utils/types").DeprecatedConfig;
|
|
453
|
-
}], import("@typescript-eslint/utils/dist/ts-eslint").RuleListener>;
|
|
447
|
+
'no-deprecated-apis': import("eslint").Rule.RuleModule;
|
|
454
448
|
'no-deprecated-design-token-usage': import("eslint").Rule.RuleModule;
|
|
455
449
|
'no-deprecated-imports': import("eslint").Rule.RuleModule;
|
|
456
450
|
'no-direct-use-of-web-platform-drag-and-drop': import("eslint").Rule.RuleModule;
|
|
@@ -8,9 +8,7 @@ export declare const rules: {
|
|
|
8
8
|
'no-css-tagged-template-expression': import("eslint").Rule.RuleModule;
|
|
9
9
|
'no-custom-icons': import("eslint").Rule.RuleModule;
|
|
10
10
|
'no-dark-theme-vr-tests': import("eslint").Rule.RuleModule;
|
|
11
|
-
'no-deprecated-apis': import("
|
|
12
|
-
deprecatedConfig: import("./utils/types").DeprecatedConfig;
|
|
13
|
-
}], import("@typescript-eslint/utils/dist/ts-eslint").RuleListener>;
|
|
11
|
+
'no-deprecated-apis': import("eslint").Rule.RuleModule;
|
|
14
12
|
'no-deprecated-design-token-usage': import("eslint").Rule.RuleModule;
|
|
15
13
|
'no-deprecated-imports': import("eslint").Rule.RuleModule;
|
|
16
14
|
'no-direct-use-of-web-platform-drag-and-drop': import("eslint").Rule.RuleModule;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Rule } from 'eslint';
|
|
2
2
|
export declare const noDeprecatedJSXAttributeMessageId = "noDeprecatedJSXAttributes";
|
|
3
3
|
export declare const name = "no-deprecated-apis";
|
|
4
|
-
declare const rule:
|
|
5
|
-
deprecatedConfig: DeprecatedConfig;
|
|
6
|
-
}], import("@typescript-eslint/utils/dist/ts-eslint").RuleListener>;
|
|
4
|
+
declare const rule: Rule.RuleModule;
|
|
7
5
|
export default rule;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { type JSONSchema4 } from '@typescript-eslint/utils/dist/json-schema';
|
|
2
|
+
type Pattern = 'style-object' | 'font-weight';
|
|
2
3
|
export type RuleConfig = {
|
|
3
4
|
failSilently: boolean;
|
|
4
5
|
shouldEnforceFallbacks: boolean;
|
|
5
6
|
enableUnsafeAutofix: boolean;
|
|
7
|
+
patterns: Pattern[];
|
|
6
8
|
};
|
|
7
9
|
export declare const ruleSchema: JSONSchema4;
|
|
8
10
|
export declare const getConfig: (overrides: Partial<RuleConfig>) => RuleConfig;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Rule } from 'eslint';
|
|
2
|
+
import { Identifier } from 'eslint-codemod-utils';
|
|
3
|
+
import { type RuleConfig } from '../config';
|
|
4
|
+
interface MetaData {
|
|
5
|
+
context: Rule.RuleContext;
|
|
6
|
+
config: RuleConfig;
|
|
7
|
+
}
|
|
8
|
+
export declare const FontWeight: {
|
|
9
|
+
lint(node: Rule.Node, { context, config }: MetaData): void;
|
|
10
|
+
_check(node: Identifier & Rule.NodeParentExtension, { context, config }: MetaData): boolean;
|
|
11
|
+
_fix(node: Identifier & Rule.NodeParentExtension, context: Rule.RuleContext): (fixer: Rule.RuleFixer) => Rule.Fix[];
|
|
12
|
+
};
|
|
13
|
+
export {};
|