@atlaskit/eslint-plugin-design-system 13.41.2 → 13.42.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 +24 -0
- package/README.md +0 -1
- package/dist/cjs/presets/all-flat.codegen.js +1 -2
- package/dist/cjs/presets/all.codegen.js +1 -2
- package/dist/cjs/rules/index.codegen.js +1 -3
- package/dist/cjs/rules/use-primitives/utils/is-valid-css-properties-to-transform.js +5 -4
- package/dist/es2019/presets/all-flat.codegen.js +1 -2
- package/dist/es2019/presets/all.codegen.js +1 -2
- package/dist/es2019/rules/index.codegen.js +1 -3
- package/dist/es2019/rules/use-primitives/utils/is-valid-css-properties-to-transform.js +5 -4
- package/dist/esm/presets/all-flat.codegen.js +1 -2
- package/dist/esm/presets/all.codegen.js +1 -2
- package/dist/esm/rules/index.codegen.js +1 -3
- package/dist/esm/rules/use-primitives/utils/is-valid-css-properties-to-transform.js +5 -4
- package/dist/types/presets/all-flat.codegen.d.ts +1 -1
- package/dist/types/presets/all.codegen.d.ts +1 -1
- package/dist/types/rules/ensure-design-token-usage/index.d.ts +1 -1
- package/dist/types/rules/ensure-design-token-usage/rule-meta.d.ts +1 -1
- package/dist/types/rules/ensure-design-token-usage/utils.d.ts +1 -1
- package/dist/types/rules/index.codegen.d.ts +1 -1
- package/dist/types/rules/no-deprecated-imports/handlers/icon.d.ts +1 -1
- package/dist/types/rules/use-heading/transformers/common.d.ts +2 -2
- package/dist/types/rules/use-latest-xcss-syntax-typography/linters/common.d.ts +1 -1
- package/dist/types/rules/use-latest-xcss-syntax-typography/linters/wrapped-token-value.d.ts +1 -1
- package/dist/types/rules/use-primitives/transformers/compiled-styled/index.d.ts +1 -1
- package/dist/types/rules/use-primitives/transformers/emotion-css/index.d.ts +1 -1
- package/dist/types/rules/use-primitives/utils/is-valid-css-properties-to-transform.d.ts +1 -1
- package/dist/types/rules/use-primitives/utils/validate-styles.d.ts +1 -1
- package/dist/types/rules/use-primitives-text/transformers/common.d.ts +1 -1
- package/dist/types/rules/use-primitives-text/transformers/unsafe-small-text.d.ts +1 -1
- package/dist/types/rules/use-tokens-typography/config/index.d.ts +1 -1
- package/dist/types/rules/use-tokens-typography/transformers/banned-properties.d.ts +1 -1
- package/dist/types/rules/use-tokens-typography/transformers/font-family.d.ts +1 -1
- package/dist/types/rules/use-tokens-typography/transformers/font-weight.d.ts +1 -1
- package/dist/types/rules/use-tokens-typography/transformers/restricted-capitalisation.d.ts +1 -1
- package/dist/types/rules/use-tokens-typography/transformers/style-object.d.ts +1 -1
- package/dist/types/rules/use-tokens-typography/transformers/untokenized-properties.d.ts +1 -1
- package/dist/types/rules/utils/create-no-exported-rule/check-if-supported-export.d.ts +1 -1
- package/dist/types/rules/utils/get-first-supported-import.d.ts +1 -1
- package/dist/types-ts4.5/presets/all-flat.codegen.d.ts +1 -1
- package/dist/types-ts4.5/presets/all.codegen.d.ts +1 -1
- package/dist/types-ts4.5/rules/ensure-design-token-usage/index.d.ts +1 -1
- package/dist/types-ts4.5/rules/ensure-design-token-usage/rule-meta.d.ts +1 -1
- package/dist/types-ts4.5/rules/ensure-design-token-usage/utils.d.ts +1 -1
- package/dist/types-ts4.5/rules/index.codegen.d.ts +1 -1
- package/dist/types-ts4.5/rules/no-deprecated-imports/handlers/icon.d.ts +1 -1
- package/dist/types-ts4.5/rules/use-heading/transformers/common.d.ts +2 -2
- package/dist/types-ts4.5/rules/use-latest-xcss-syntax-typography/linters/common.d.ts +1 -1
- package/dist/types-ts4.5/rules/use-latest-xcss-syntax-typography/linters/wrapped-token-value.d.ts +1 -1
- package/dist/types-ts4.5/rules/use-primitives/transformers/compiled-styled/index.d.ts +1 -1
- package/dist/types-ts4.5/rules/use-primitives/transformers/emotion-css/index.d.ts +1 -1
- package/dist/types-ts4.5/rules/use-primitives/utils/is-valid-css-properties-to-transform.d.ts +1 -1
- package/dist/types-ts4.5/rules/use-primitives/utils/validate-styles.d.ts +1 -1
- package/dist/types-ts4.5/rules/use-primitives-text/transformers/common.d.ts +1 -1
- package/dist/types-ts4.5/rules/use-primitives-text/transformers/unsafe-small-text.d.ts +1 -1
- package/dist/types-ts4.5/rules/use-tokens-typography/config/index.d.ts +1 -1
- package/dist/types-ts4.5/rules/use-tokens-typography/transformers/banned-properties.d.ts +1 -1
- package/dist/types-ts4.5/rules/use-tokens-typography/transformers/font-family.d.ts +1 -1
- package/dist/types-ts4.5/rules/use-tokens-typography/transformers/font-weight.d.ts +1 -1
- package/dist/types-ts4.5/rules/use-tokens-typography/transformers/restricted-capitalisation.d.ts +1 -1
- package/dist/types-ts4.5/rules/use-tokens-typography/transformers/style-object.d.ts +1 -1
- package/dist/types-ts4.5/rules/use-tokens-typography/transformers/untokenized-properties.d.ts +1 -1
- package/dist/types-ts4.5/rules/utils/create-no-exported-rule/check-if-supported-export.d.ts +1 -1
- package/dist/types-ts4.5/rules/utils/get-first-supported-import.d.ts +1 -1
- package/package.json +4 -4
- package/dist/cjs/rules/no-legacy-icons/checks.js +0 -619
- package/dist/cjs/rules/no-legacy-icons/helpers.js +0 -900
- package/dist/cjs/rules/no-legacy-icons/index.js +0 -91
- package/dist/cjs/rules/no-legacy-icons/upcoming-icons.js +0 -7
- package/dist/es2019/rules/no-legacy-icons/checks.js +0 -520
- package/dist/es2019/rules/no-legacy-icons/helpers.js +0 -853
- package/dist/es2019/rules/no-legacy-icons/index.js +0 -87
- package/dist/es2019/rules/no-legacy-icons/upcoming-icons.js +0 -1
- package/dist/esm/rules/no-legacy-icons/checks.js +0 -613
- package/dist/esm/rules/no-legacy-icons/helpers.js +0 -891
- package/dist/esm/rules/no-legacy-icons/index.js +0 -85
- package/dist/esm/rules/no-legacy-icons/upcoming-icons.js +0 -1
- package/dist/types/rules/no-legacy-icons/checks.d.ts +0 -16
- package/dist/types/rules/no-legacy-icons/helpers.d.ts +0 -151
- package/dist/types/rules/no-legacy-icons/index.d.ts +0 -2
- package/dist/types/rules/no-legacy-icons/upcoming-icons.d.ts +0 -1
- package/dist/types-ts4.5/rules/no-legacy-icons/checks.d.ts +0 -16
- package/dist/types-ts4.5/rules/no-legacy-icons/helpers.d.ts +0 -156
- package/dist/types-ts4.5/rules/no-legacy-icons/index.d.ts +0 -2
- package/dist/types-ts4.5/rules/no-legacy-icons/upcoming-icons.d.ts +0 -1
|
@@ -1,853 +0,0 @@
|
|
|
1
|
-
import { isNodeOfType, literal } from 'eslint-codemod-utils';
|
|
2
|
-
import baseMigrationMap, { migrationOutcomeDescriptionMap } from '@atlaskit/icon/migration-map';
|
|
3
|
-
import { upcomingIcons } from './upcoming-icons';
|
|
4
|
-
const sizes = ['small', 'medium', 'large', 'xlarge'];
|
|
5
|
-
export const isSize = size => sizes.includes(size);
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Returns the migration map object for a legacy icon or null if not found
|
|
9
|
-
* @param iconPackage The name of the legacy icon package
|
|
10
|
-
* @returns The migration map object for the legacy icon or null if not found
|
|
11
|
-
*/
|
|
12
|
-
export const getMigrationMapObject = iconPackage => {
|
|
13
|
-
const key = getIconKey(iconPackage);
|
|
14
|
-
if (Object.keys(baseMigrationMap).includes(key)) {
|
|
15
|
-
return baseMigrationMap[key];
|
|
16
|
-
}
|
|
17
|
-
return null;
|
|
18
|
-
};
|
|
19
|
-
export const getUpcomingIcons = iconPackage => {
|
|
20
|
-
const key = getIconKey(iconPackage);
|
|
21
|
-
if (upcomingIcons.includes(key)) {
|
|
22
|
-
const retval = {
|
|
23
|
-
sizeGuidance: {
|
|
24
|
-
small: 'swap',
|
|
25
|
-
medium: 'swap',
|
|
26
|
-
large: 'icon-tile',
|
|
27
|
-
xlarge: 'icon-tile'
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
return retval;
|
|
31
|
-
}
|
|
32
|
-
return null;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Returns the key of a legacy icon
|
|
37
|
-
* @param iconPackage The name of the legacy icon package
|
|
38
|
-
* @returns The unique identifier for the icon (the part after "@atlaskit/icon/glyph")
|
|
39
|
-
*/
|
|
40
|
-
const getIconKey = iconPackage => {
|
|
41
|
-
const key = iconPackage.replace(/^@atlaskit\/icon\/glyph\//, '');
|
|
42
|
-
return key;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Checks if a new icon can be auto-migrated based on guidance from the migration map
|
|
47
|
-
*/
|
|
48
|
-
export const canAutoMigrateNewIconBasedOnSize = guidance => {
|
|
49
|
-
return guidance ? ['swap', 'swap-slight-visual-change', 'swap-visual-change'].includes(guidance) : false;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
*
|
|
54
|
-
* @param iconPackage string
|
|
55
|
-
* @returns object of new icon name and import path
|
|
56
|
-
*/
|
|
57
|
-
const getNewIconNameAndImportPath = (iconPackage, shouldUseMigrationPath) => {
|
|
58
|
-
const legacyIconName = getIconKey(iconPackage);
|
|
59
|
-
const migrationMapObject = getMigrationMapObject(iconPackage);
|
|
60
|
-
if (!migrationMapObject || !migrationMapObject.newIcon) {
|
|
61
|
-
return {};
|
|
62
|
-
}
|
|
63
|
-
const {
|
|
64
|
-
newIcon
|
|
65
|
-
} = migrationMapObject;
|
|
66
|
-
const migrationPath = newIcon.name === legacyIconName ? `${newIcon.package}/core/migration/${newIcon.name}` : `${newIcon.package}/core/migration/${newIcon.name}--${legacyIconName.replaceAll('/', '-')}`;
|
|
67
|
-
return {
|
|
68
|
-
iconName: newIcon.name,
|
|
69
|
-
importPath: shouldUseMigrationPath ? migrationPath : `${newIcon.package}/core/${newIcon.name}`
|
|
70
|
-
};
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Creates the written guidance for migrating a legacy icon to a new icon
|
|
75
|
-
*/
|
|
76
|
-
export const createGuidance = ({
|
|
77
|
-
iconPackage,
|
|
78
|
-
insideNewButton,
|
|
79
|
-
size: initialSize,
|
|
80
|
-
shouldUseMigrationPath,
|
|
81
|
-
shouldForceSmallIcon
|
|
82
|
-
}) => {
|
|
83
|
-
const size = shouldForceSmallIcon ? 'small' : initialSize;
|
|
84
|
-
const migrationMapObject = getMigrationMapObject(iconPackage);
|
|
85
|
-
const upcomingIcon = getUpcomingIcons(iconPackage);
|
|
86
|
-
if (upcomingIcon) {
|
|
87
|
-
let guidance = '';
|
|
88
|
-
if (size) {
|
|
89
|
-
if (upcomingIcon.sizeGuidance[size] && canAutoMigrateNewIconBasedOnSize(upcomingIcon.sizeGuidance[size])) {
|
|
90
|
-
guidance += `Fix: An upcoming icon release is planned to migrate this legacy icon.`;
|
|
91
|
-
} else {
|
|
92
|
-
guidance += `No equivalent icon for this size, ${size}, in the current or upcoming set of icons.`;
|
|
93
|
-
}
|
|
94
|
-
guidance += `${Object.keys(migrationOutcomeDescriptionMap).includes(upcomingIcon.sizeGuidance[size]) ? ` Once the upcoming icons are released, please: ${migrationOutcomeDescriptionMap[upcomingIcon.sizeGuidance[size]]}` : ' No migration size advice given.'}\n`;
|
|
95
|
-
} else {
|
|
96
|
-
guidance = `Please wait for the upcoming icons released, as it will contain an alternative for this legacy icon.\nMigration suggestions, depending on the legacy icon size:\n`;
|
|
97
|
-
for (const [size, value] of Object.entries(upcomingIcon.sizeGuidance)) {
|
|
98
|
-
guidance += `\t- ${size}: `;
|
|
99
|
-
if (!Object.keys(migrationOutcomeDescriptionMap).includes(value)) {
|
|
100
|
-
guidance += 'No migration advice given.\n';
|
|
101
|
-
} else {
|
|
102
|
-
guidance += `${migrationOutcomeDescriptionMap[value]}.\n`;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return guidance;
|
|
107
|
-
} else if (migrationMapObject) {
|
|
108
|
-
const newIcon = migrationMapObject.newIcon;
|
|
109
|
-
if (!newIcon) {
|
|
110
|
-
return 'No equivalent icon in new set. An option is to contribute a custom icon into icon-labs package instead.\n';
|
|
111
|
-
}
|
|
112
|
-
const {
|
|
113
|
-
iconName,
|
|
114
|
-
importPath
|
|
115
|
-
} = getNewIconNameAndImportPath(iconPackage, shouldUseMigrationPath);
|
|
116
|
-
const buttonGuidanceStr = "Please set 'spacing' property of the new icon to 'none', to ensure appropriate spacing inside `@atlaskit/button`.\n";
|
|
117
|
-
let guidance = '';
|
|
118
|
-
if (size) {
|
|
119
|
-
if (migrationMapObject.sizeGuidance[size] && canAutoMigrateNewIconBasedOnSize(migrationMapObject.sizeGuidance[size])) {
|
|
120
|
-
guidance += `Fix: Use ${iconName} from ${importPath} instead.`;
|
|
121
|
-
} else {
|
|
122
|
-
guidance += `No equivalent icon for this size, ${size}, in new set.`;
|
|
123
|
-
}
|
|
124
|
-
guidance += `${Object.keys(migrationOutcomeDescriptionMap).includes(migrationMapObject.sizeGuidance[size]) ? ` Please: ${migrationOutcomeDescriptionMap[migrationMapObject.sizeGuidance[size]]}` : ' No migration size advice given.'}\n`;
|
|
125
|
-
} else {
|
|
126
|
-
guidance = `Use ${iconName} from ${importPath} instead.\nMigration suggestions, depending on the legacy icon size:\n`;
|
|
127
|
-
Object.entries(migrationMapObject.sizeGuidance).forEach(([size, value]) => {
|
|
128
|
-
guidance += `\t- ${size}: `;
|
|
129
|
-
if (!Object.keys(migrationOutcomeDescriptionMap).includes(value)) {
|
|
130
|
-
guidance += 'No migration advice given.\n';
|
|
131
|
-
} else {
|
|
132
|
-
guidance += `${migrationOutcomeDescriptionMap[value]}.\n`;
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
if (insideNewButton) {
|
|
137
|
-
guidance += buttonGuidanceStr;
|
|
138
|
-
} else if (size === 'medium') {
|
|
139
|
-
guidance += "Setting the spacing='spacious' will maintain the icon's box dimensions - but consider setting spacing='none' as it allows for easier control of spacing by parent elements.\n";
|
|
140
|
-
} else if (size === 'small') {
|
|
141
|
-
if (initialSize !== 'small' && shouldForceSmallIcon) {
|
|
142
|
-
guidance += "For this icon, it's recommended to use a smaller size using size='small'. Alternatively, for special cases where a larger version is needed size='medium' can be used, but it is generally discouraged for this icon.\n";
|
|
143
|
-
} else if (initialSize === 'small') {
|
|
144
|
-
if (shouldForceSmallIcon) {
|
|
145
|
-
guidance += "Setting spacing='compact' will maintain the icon's box dimensions - but consider setting spacing='none' as it allows for easier control of spacing by parent elements.\n";
|
|
146
|
-
} else {
|
|
147
|
-
guidance += "It's recommended to upscale to a medium icon with no spacing. Alternatively for special cases where smaller icons are required, the original icon size and dimensions can be maintained by using size='small' and spacing='compact'.\n";
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
} else if (size) {
|
|
151
|
-
guidance += "In the new icon, please use spacing='none'.\n";
|
|
152
|
-
}
|
|
153
|
-
return guidance;
|
|
154
|
-
} else {
|
|
155
|
-
return `Migration suggestions not found for "${iconPackage}".\n`;
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Checks if the color can be migrated
|
|
161
|
-
* @param color String representing the color to check
|
|
162
|
-
* @returns True if the color can be migrated, false otherwise
|
|
163
|
-
*/
|
|
164
|
-
export const canMigrateColor = color => {
|
|
165
|
-
if (color.match(/^color\.icon/)) {
|
|
166
|
-
return true;
|
|
167
|
-
} else if (color.match(/^color\.link/)) {
|
|
168
|
-
return true;
|
|
169
|
-
} else if (color.match(/^color\.text/)) {
|
|
170
|
-
return true;
|
|
171
|
-
} else if (color === 'currentColor') {
|
|
172
|
-
return true;
|
|
173
|
-
} else {
|
|
174
|
-
return false;
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
export const locToString = node => {
|
|
178
|
-
if (node.range && node.range.length >= 2) {
|
|
179
|
-
return `${node.range[0]}:${node.range[1]}`;
|
|
180
|
-
} else {
|
|
181
|
-
return '';
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
export const createCantMigrateReExportError = (node, packageName, exportName, errors) => {
|
|
185
|
-
const myError = {
|
|
186
|
-
node,
|
|
187
|
-
messageId: 'cantMigrateReExport',
|
|
188
|
-
data: {
|
|
189
|
-
packageName,
|
|
190
|
-
exportName
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
pushManualError(locToString(node), errors, myError, packageName, exportName);
|
|
194
|
-
};
|
|
195
|
-
export const createCantMigrateIdentifierMapOrArrayError = (node, packageName, exportName, errors) => {
|
|
196
|
-
const myError = {
|
|
197
|
-
node,
|
|
198
|
-
messageId: 'cantMigrateIdentifierMapOrArray',
|
|
199
|
-
data: {
|
|
200
|
-
packageName,
|
|
201
|
-
exportName
|
|
202
|
-
}
|
|
203
|
-
};
|
|
204
|
-
pushManualError(locToString(node), errors, myError, packageName, exportName);
|
|
205
|
-
};
|
|
206
|
-
export const createCantMigrateIdentifierError = (node, packageName, exportName, errors) => {
|
|
207
|
-
const myError = {
|
|
208
|
-
node,
|
|
209
|
-
messageId: 'cantMigrateIdentifier',
|
|
210
|
-
data: {
|
|
211
|
-
iconSource: packageName,
|
|
212
|
-
iconName: exportName
|
|
213
|
-
}
|
|
214
|
-
};
|
|
215
|
-
pushManualError(locToString(node), errors, myError, packageName, exportName);
|
|
216
|
-
};
|
|
217
|
-
export const createCantFindSuitableReplacementError = (node, importSource, iconName, errors, sizeIssue) => {
|
|
218
|
-
const myError = {
|
|
219
|
-
node,
|
|
220
|
-
messageId: 'cantFindSuitableReplacement',
|
|
221
|
-
data: {
|
|
222
|
-
importSource,
|
|
223
|
-
iconName,
|
|
224
|
-
sizeGuidance: sizeIssue ? ' at the current size' : ''
|
|
225
|
-
}
|
|
226
|
-
};
|
|
227
|
-
pushManualError(locToString(node), errors, myError, importSource, iconName);
|
|
228
|
-
};
|
|
229
|
-
export const createCantMigrateFunctionUnknownError = (node, importSource, iconName, errors) => {
|
|
230
|
-
const myError = {
|
|
231
|
-
node,
|
|
232
|
-
messageId: 'cantMigrateFunctionUnknown',
|
|
233
|
-
data: {
|
|
234
|
-
importSource,
|
|
235
|
-
iconName
|
|
236
|
-
}
|
|
237
|
-
};
|
|
238
|
-
pushManualError(locToString(node), errors, myError, importSource, iconName);
|
|
239
|
-
};
|
|
240
|
-
export const createCantMigrateColorError = (node, colorValue, errors, importSource, iconName) => {
|
|
241
|
-
const myError = {
|
|
242
|
-
node,
|
|
243
|
-
messageId: 'cantMigrateColor',
|
|
244
|
-
data: {
|
|
245
|
-
colorValue
|
|
246
|
-
}
|
|
247
|
-
};
|
|
248
|
-
pushManualError(locToString(node), errors, myError, importSource, iconName);
|
|
249
|
-
};
|
|
250
|
-
export const createCantMigrateSpreadPropsError = (node, missingProps, errors, importSource, iconName) => {
|
|
251
|
-
const myError = {
|
|
252
|
-
node,
|
|
253
|
-
messageId: 'cantMigrateSpreadProps',
|
|
254
|
-
data: {
|
|
255
|
-
missingProps: missingProps.join(', ')
|
|
256
|
-
}
|
|
257
|
-
};
|
|
258
|
-
pushManualError(locToString(node), errors, myError, importSource, iconName);
|
|
259
|
-
};
|
|
260
|
-
export const createCantMigrateSizeUnknown = (node, errors, importSource, iconName) => {
|
|
261
|
-
const myError = {
|
|
262
|
-
node,
|
|
263
|
-
messageId: 'cantMigrateSizeUnknown'
|
|
264
|
-
};
|
|
265
|
-
pushManualError(locToString(node), errors, myError, importSource, iconName);
|
|
266
|
-
};
|
|
267
|
-
export const createAutoMigrationError = ({
|
|
268
|
-
node,
|
|
269
|
-
importSource,
|
|
270
|
-
iconName,
|
|
271
|
-
errors,
|
|
272
|
-
spacing,
|
|
273
|
-
insideNewButton,
|
|
274
|
-
shouldForceSmallIcon
|
|
275
|
-
}) => {
|
|
276
|
-
const myError = {
|
|
277
|
-
node,
|
|
278
|
-
messageId: 'noLegacyIconsAutoMigration',
|
|
279
|
-
data: {
|
|
280
|
-
importSource,
|
|
281
|
-
iconName,
|
|
282
|
-
spacing: spacing !== null && spacing !== void 0 ? spacing : '',
|
|
283
|
-
// value type need to be a string in Rule.ReportDescriptor
|
|
284
|
-
insideNewButton: String(insideNewButton),
|
|
285
|
-
shouldForceSmallIcon: String(shouldForceSmallIcon)
|
|
286
|
-
}
|
|
287
|
-
};
|
|
288
|
-
errors[locToString(node)] = myError;
|
|
289
|
-
};
|
|
290
|
-
const pushManualError = (key, errors, myError, importSource, iconName) => {
|
|
291
|
-
if (Object.keys(errors).includes(key)) {
|
|
292
|
-
errors[key].errors.push(myError);
|
|
293
|
-
} else {
|
|
294
|
-
errors[key] = {
|
|
295
|
-
errors: [myError],
|
|
296
|
-
importSource,
|
|
297
|
-
iconName
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
};
|
|
301
|
-
const getLiteralStringValue = value => {
|
|
302
|
-
if (!value) {
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// propName="value"
|
|
307
|
-
if (isNodeOfType(value, 'Literal') && typeof value.value === 'string') {
|
|
308
|
-
return value.value;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// propName={"value"}
|
|
312
|
-
if (isNodeOfType(value, 'JSXExpressionContainer') && isNodeOfType(value.expression, 'Literal') && typeof value.expression.value === 'string') {
|
|
313
|
-
return value.expression.value;
|
|
314
|
-
}
|
|
315
|
-
return;
|
|
316
|
-
};
|
|
317
|
-
export const createHelpers = ctx => {
|
|
318
|
-
// TODO: JFP-2823 - this type cast was added due to Jira's ESLint v9 migration
|
|
319
|
-
const context = ctx;
|
|
320
|
-
/**
|
|
321
|
-
* Extracts the token name of a token() call from a JSXExpressionContainer
|
|
322
|
-
* @param value The JSXExpressionContainer to extract the token call from
|
|
323
|
-
* @returns The value of the token call, or null if it could not be extracted
|
|
324
|
-
*/
|
|
325
|
-
const getTokenCallValue = value => {
|
|
326
|
-
/**
|
|
327
|
-
* Previously, we used getImportName() to extract the token name from a token() call.
|
|
328
|
-
* However, this was failing in the Issue Automat so we are now using a simpler approach.
|
|
329
|
-
*/
|
|
330
|
-
|
|
331
|
-
if (isNodeOfType(value, 'JSXExpressionContainer') && isNodeOfType(value.expression, 'CallExpression') && 'name' in value.expression.callee && value.expression.callee.name === 'token') {
|
|
332
|
-
// propName={token("color...."}
|
|
333
|
-
return getLiteralStringValue(value.expression.arguments[0]);
|
|
334
|
-
}
|
|
335
|
-
return;
|
|
336
|
-
};
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* Gets the value of a boolean configuration flag
|
|
340
|
-
* @param key the key of the configuration flag
|
|
341
|
-
* @param defaultValue The default value of the configuration flag
|
|
342
|
-
* @returns defaultValue if the configuration flag is not set, the defaultValue of the configuration flag otherwise
|
|
343
|
-
*/
|
|
344
|
-
const getConfigFlag = (key, defaultValue) => {
|
|
345
|
-
if (context.options.length > 0 && context.options[0] && Object.keys(context.options[0]).includes(key)) {
|
|
346
|
-
return context.options[0][key] === !defaultValue ? !defaultValue : defaultValue;
|
|
347
|
-
}
|
|
348
|
-
return defaultValue;
|
|
349
|
-
};
|
|
350
|
-
return {
|
|
351
|
-
/**
|
|
352
|
-
* Extracts the primaryColor value from a JSXAttribute
|
|
353
|
-
*/
|
|
354
|
-
getPrimaryColor(attr) {
|
|
355
|
-
var _ref, _getLiteralStringValu;
|
|
356
|
-
const {
|
|
357
|
-
value
|
|
358
|
-
} = attr;
|
|
359
|
-
return (_ref = (_getLiteralStringValu = getLiteralStringValue(value)) !== null && _getLiteralStringValu !== void 0 ? _getLiteralStringValu : getTokenCallValue(value)) !== null && _ref !== void 0 ? _ref : null;
|
|
360
|
-
},
|
|
361
|
-
getTokenCallValue,
|
|
362
|
-
getConfigFlag
|
|
363
|
-
};
|
|
364
|
-
};
|
|
365
|
-
export const addToListOfRanges = (node, sortedListOfRangesForErrors) => {
|
|
366
|
-
if (node.range && node.range.length >= 2) {
|
|
367
|
-
sortedListOfRangesForErrors.push({
|
|
368
|
-
start: node.range[0],
|
|
369
|
-
end: node.range[1]
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
};
|
|
373
|
-
const isInRangeList = (node, sortedListOfRangesForErrors) => {
|
|
374
|
-
const {
|
|
375
|
-
range
|
|
376
|
-
} = node;
|
|
377
|
-
if (!range || range.length < 2) {
|
|
378
|
-
return false;
|
|
379
|
-
}
|
|
380
|
-
const found = sortedListOfRangesForErrors.find(currRange => range[0] >= currRange.start && range[1] <= currRange.end);
|
|
381
|
-
return !!found;
|
|
382
|
-
};
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
*
|
|
386
|
-
* @param node Icon JSXelement
|
|
387
|
-
* @param newButtonImports list of new button import specifiers
|
|
388
|
-
* @returns if Icon is inside a new button
|
|
389
|
-
*/
|
|
390
|
-
export const isInsideNewButton = (node, newButtonImports) => {
|
|
391
|
-
var _node$parent, _node$parent$parent, _node$parent2, _node$parent2$parent, _node$parent2$parent$;
|
|
392
|
-
let insideNewButton = false;
|
|
393
|
-
if (node.parent && isNodeOfType(node.parent, 'ArrowFunctionExpression') && (_node$parent = node.parent) !== null && _node$parent !== void 0 && (_node$parent$parent = _node$parent.parent) !== null && _node$parent$parent !== void 0 && _node$parent$parent.parent && isNodeOfType(node.parent.parent.parent, 'JSXAttribute') && isNodeOfType(node.parent.parent.parent.name, 'JSXIdentifier') && (_node$parent2 = node.parent) !== null && _node$parent2 !== void 0 && (_node$parent2$parent = _node$parent2.parent) !== null && _node$parent2$parent !== void 0 && (_node$parent2$parent$ = _node$parent2$parent.parent) !== null && _node$parent2$parent$ !== void 0 && _node$parent2$parent$.parent && isNodeOfType(node.parent.parent.parent.parent, 'JSXOpeningElement') && isNodeOfType(node.parent.parent.parent.parent.name, 'JSXIdentifier') && newButtonImports.has(node.parent.parent.parent.parent.name.name)) {
|
|
394
|
-
insideNewButton = true;
|
|
395
|
-
}
|
|
396
|
-
return insideNewButton;
|
|
397
|
-
};
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
*
|
|
401
|
-
* @param node Icon JSXelement
|
|
402
|
-
* @param newButtonImports list of legacy button import specifiers
|
|
403
|
-
* @returns if Icon is inside a legacy button
|
|
404
|
-
*/
|
|
405
|
-
export const isInsideLegacyButton = (node, legacyButtonImports) => {
|
|
406
|
-
var _node$parent3, _node$parent4, _node$parent4$parent, _node$parent5, _node$parent5$parent, _node$parent6, _node$parent6$parent;
|
|
407
|
-
return node.parent && isNodeOfType(node.parent, 'JSXExpressionContainer') && ((_node$parent3 = node.parent) === null || _node$parent3 === void 0 ? void 0 : _node$parent3.parent) && isNodeOfType(node.parent.parent, 'JSXAttribute') && (node.parent.parent.name.name === 'iconBefore' || node.parent.parent.name.name === 'iconAfter') && isNodeOfType((_node$parent4 = node.parent) === null || _node$parent4 === void 0 ? void 0 : (_node$parent4$parent = _node$parent4.parent) === null || _node$parent4$parent === void 0 ? void 0 : _node$parent4$parent.parent, 'JSXOpeningElement') && isNodeOfType((_node$parent5 = node.parent) === null || _node$parent5 === void 0 ? void 0 : (_node$parent5$parent = _node$parent5.parent) === null || _node$parent5$parent === void 0 ? void 0 : _node$parent5$parent.parent.name, 'JSXIdentifier') && legacyButtonImports.has((_node$parent6 = node.parent) === null || _node$parent6 === void 0 ? void 0 : (_node$parent6$parent = _node$parent6.parent) === null || _node$parent6$parent === void 0 ? void 0 : _node$parent6$parent.parent.name.name);
|
|
408
|
-
};
|
|
409
|
-
|
|
410
|
-
/**
|
|
411
|
-
*
|
|
412
|
-
* @param node Icon JSXelement
|
|
413
|
-
* @param newButtonImports list of legacy button import specifiers
|
|
414
|
-
* @returns if Icon is inside a legacy button
|
|
415
|
-
*/
|
|
416
|
-
export const isInsideIconOnlyLegacyButton = (node, legacyButtonImports) => {
|
|
417
|
-
let insideIconOnlyLegacyButton = false;
|
|
418
|
-
if (isInsideLegacyButton(node, legacyButtonImports)) {
|
|
419
|
-
var _node$parent7, _node$parent8, _node$parent8$parent, _node$parent9, _node$parent9$parent, _node$parent0, _node$parent0$parent, _node$parent0$parent$, _node$parent1, _node$parent1$parent, _node$parent1$parent$, _node$parent10, _node$parent10$parent, _node$parent10$parent2;
|
|
420
|
-
const legacyButtonAttributes = node.parent && isNodeOfType(node.parent, 'JSXExpressionContainer') && (_node$parent7 = node.parent) !== null && _node$parent7 !== void 0 && _node$parent7.parent && isNodeOfType(node.parent.parent, 'JSXAttribute') && node.parent.parent.parent && isNodeOfType((_node$parent8 = node.parent) === null || _node$parent8 === void 0 ? void 0 : (_node$parent8$parent = _node$parent8.parent) === null || _node$parent8$parent === void 0 ? void 0 : _node$parent8$parent.parent, 'JSXOpeningElement') ? (_node$parent9 = node.parent) === null || _node$parent9 === void 0 ? void 0 : (_node$parent9$parent = _node$parent9.parent) === null || _node$parent9$parent === void 0 ? void 0 : _node$parent9$parent.parent.attributes.map(attribute => {
|
|
421
|
-
var _attribute$name;
|
|
422
|
-
return isNodeOfType(attribute, 'JSXAttribute') && isNodeOfType(attribute.name, 'JSXIdentifier') && (attribute === null || attribute === void 0 ? void 0 : (_attribute$name = attribute.name) === null || _attribute$name === void 0 ? void 0 : _attribute$name.name);
|
|
423
|
-
}).filter(Boolean) : [];
|
|
424
|
-
const hasIconBefore = legacyButtonAttributes.includes('iconBefore');
|
|
425
|
-
const hasIconAfter = legacyButtonAttributes.includes('iconAfter');
|
|
426
|
-
const hasChildren = ((_node$parent0 = node.parent) === null || _node$parent0 === void 0 ? void 0 : (_node$parent0$parent = _node$parent0.parent) === null || _node$parent0$parent === void 0 ? void 0 : (_node$parent0$parent$ = _node$parent0$parent.parent) === null || _node$parent0$parent$ === void 0 ? void 0 : _node$parent0$parent$.parent) && isNodeOfType((_node$parent1 = node.parent) === null || _node$parent1 === void 0 ? void 0 : (_node$parent1$parent = _node$parent1.parent) === null || _node$parent1$parent === void 0 ? void 0 : (_node$parent1$parent$ = _node$parent1$parent.parent) === null || _node$parent1$parent$ === void 0 ? void 0 : _node$parent1$parent$.parent, 'JSXElement') && ((_node$parent10 = node.parent) === null || _node$parent10 === void 0 ? void 0 : (_node$parent10$parent = _node$parent10.parent) === null || _node$parent10$parent === void 0 ? void 0 : (_node$parent10$parent2 = _node$parent10$parent.parent) === null || _node$parent10$parent2 === void 0 ? void 0 : _node$parent10$parent2.parent.children.length) > 0;
|
|
427
|
-
if (hasIconBefore && !hasIconAfter && !hasChildren || !hasIconBefore && hasIconAfter && !hasChildren || !hasIconBefore && !hasIconAfter && hasChildren) {
|
|
428
|
-
insideIconOnlyLegacyButton = true;
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
return insideIconOnlyLegacyButton;
|
|
432
|
-
};
|
|
433
|
-
const findProp = (attributes, propName) => attributes.find(attr => attr.type === 'JSXAttribute' && attr.name.name === propName);
|
|
434
|
-
const getNewIconNameForRenaming = (isInManualArray, importSource, importSpecifier) => {
|
|
435
|
-
let newIconName;
|
|
436
|
-
if (isInManualArray) {
|
|
437
|
-
newIconName = getNewIconNameAndImportPath(importSource).iconName;
|
|
438
|
-
const keyToName = newIconName ? getComponentName(newIconName) : undefined;
|
|
439
|
-
newIconName = keyToName;
|
|
440
|
-
if (newIconName === undefined || importSpecifier === keyToName) {
|
|
441
|
-
newIconName = `${keyToName}New`;
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
return newIconName;
|
|
445
|
-
};
|
|
446
|
-
export const getComponentName = name => {
|
|
447
|
-
return name.split(/\W/).map(part => `${part[0].toUpperCase()}${part.slice(1)}`).join('').concat('Icon');
|
|
448
|
-
};
|
|
449
|
-
|
|
450
|
-
/**
|
|
451
|
-
*
|
|
452
|
-
* Creates a list of fixers to update the icon import path
|
|
453
|
-
* @param metadata Metadata including the import source and spacing
|
|
454
|
-
* @param fixer The original fix function
|
|
455
|
-
* @param legacyImportNode The import declaration node to replace
|
|
456
|
-
* @param shouldUseMigrationPath The eslint rule config, whether to use migration entrypoint or not
|
|
457
|
-
* @param migrationImportNode The migration import declaration node to replace, only present if shouldUseMigrationPath is false
|
|
458
|
-
* @returns A list of fixers to migrate the icon
|
|
459
|
-
*/
|
|
460
|
-
const createImportFix = ({
|
|
461
|
-
fixer,
|
|
462
|
-
legacyImportNode,
|
|
463
|
-
metadata,
|
|
464
|
-
shouldUseMigrationPath,
|
|
465
|
-
migrationImportNode,
|
|
466
|
-
newIconName
|
|
467
|
-
}) => {
|
|
468
|
-
const fixes = [];
|
|
469
|
-
const {
|
|
470
|
-
importSource
|
|
471
|
-
} = metadata;
|
|
472
|
-
const importPath = migrationImportNode ? importSource.replace('/migration', '').split('--')[0] : getNewIconNameAndImportPath(importSource, shouldUseMigrationPath).importPath;
|
|
473
|
-
const useMigrationPath = legacyImportNode && importPath;
|
|
474
|
-
const useFinalPath = migrationImportNode && !shouldUseMigrationPath && importPath;
|
|
475
|
-
const programNode = legacyImportNode && findProgramNode(legacyImportNode);
|
|
476
|
-
if (useMigrationPath) {
|
|
477
|
-
if (newIconName) {
|
|
478
|
-
const isExisting = programNode ? alreadyHasImportedLocalName(programNode, newIconName, importPath) : false;
|
|
479
|
-
if (!isExisting) {
|
|
480
|
-
fixes.push(fixer.insertTextBefore(legacyImportNode, `import ${newIconName} from '${importPath}';\n`));
|
|
481
|
-
}
|
|
482
|
-
} else {
|
|
483
|
-
fixes.push(fixer.replaceText(legacyImportNode.source, `'${literal(importPath)}'`));
|
|
484
|
-
}
|
|
485
|
-
} else if (useFinalPath) {
|
|
486
|
-
if (newIconName) {
|
|
487
|
-
const isExisting = programNode ? alreadyHasImportedLocalName(programNode, newIconName, importPath) : false;
|
|
488
|
-
if (!isExisting) {
|
|
489
|
-
fixes.push(fixer.insertTextBefore(migrationImportNode, `import ${newIconName} from '${importPath}';\n`));
|
|
490
|
-
}
|
|
491
|
-
} else {
|
|
492
|
-
fixes.push(fixer.replaceText(migrationImportNode.source, `'${literal(importPath)}'`));
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
return fixes;
|
|
496
|
-
};
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* Creates a list of fixers to update the icon props
|
|
500
|
-
* @param node The Icon element to migrate
|
|
501
|
-
* @param metadata Metadata including the import source and spacing
|
|
502
|
-
* @param fixer The original fix function
|
|
503
|
-
* @param legacyImportNode The import declaration node to replace
|
|
504
|
-
* @param shouldUseMigrationPath The eslint rule config, whether to use migration entrypoint or not
|
|
505
|
-
* @param migrationImportNode The migration import declaration node to replace, only present if shouldUseMigrationPath is false
|
|
506
|
-
* @returns A list of fixers to migrate the icon
|
|
507
|
-
*/
|
|
508
|
-
const createPropFixes = ({
|
|
509
|
-
node,
|
|
510
|
-
fixer,
|
|
511
|
-
legacyImportNode,
|
|
512
|
-
metadata,
|
|
513
|
-
shouldUseMigrationPath,
|
|
514
|
-
migrationImportNode,
|
|
515
|
-
newIconName
|
|
516
|
-
}) => {
|
|
517
|
-
const fixes = [];
|
|
518
|
-
const {
|
|
519
|
-
spacing,
|
|
520
|
-
size,
|
|
521
|
-
importSource
|
|
522
|
-
} = metadata;
|
|
523
|
-
if (shouldUseMigrationPath && !legacyImportNode) {
|
|
524
|
-
return fixes;
|
|
525
|
-
}
|
|
526
|
-
if (node.type === 'JSXElement') {
|
|
527
|
-
const {
|
|
528
|
-
openingElement
|
|
529
|
-
} = node;
|
|
530
|
-
if (newIconName) {
|
|
531
|
-
fixes.push(fixer.replaceText(openingElement.name, newIconName));
|
|
532
|
-
}
|
|
533
|
-
const {
|
|
534
|
-
attributes
|
|
535
|
-
} = openingElement;
|
|
536
|
-
|
|
537
|
-
// replace primaryColor prop with color
|
|
538
|
-
const primaryColor = findProp(attributes, 'primaryColor');
|
|
539
|
-
if (primaryColor && primaryColor.type === 'JSXAttribute') {
|
|
540
|
-
fixes.push(fixer.replaceText(primaryColor.name, 'color'));
|
|
541
|
-
}
|
|
542
|
-
const sizeProp = findProp(attributes, 'size');
|
|
543
|
-
const spacingProp = findProp(attributes, 'spacing');
|
|
544
|
-
if (sizeProp && sizeProp.type === 'JSXAttribute') {
|
|
545
|
-
if (shouldUseMigrationPath) {
|
|
546
|
-
// Rename existing size prop to LEGACY_size and add new size prop if applicable
|
|
547
|
-
fixes.push(fixer.replaceText(sizeProp.name, 'LEGACY_size'));
|
|
548
|
-
if (size) {
|
|
549
|
-
fixes.push(fixer.insertTextAfter(sizeProp, ` size="${size}"`));
|
|
550
|
-
}
|
|
551
|
-
} else {
|
|
552
|
-
if (size && sizeProp.value) {
|
|
553
|
-
// update size prop with new replacement size
|
|
554
|
-
fixes.push(fixer.replaceText(sizeProp.value, `"${size}"`));
|
|
555
|
-
} else if (importSource.startsWith('@atlaskit/icon/glyph/')) {
|
|
556
|
-
// only remove size prop for glyph entry points if no new replacement size is specified
|
|
557
|
-
fixes.push(fixer.remove(sizeProp));
|
|
558
|
-
} else if (sizeProp.value && sizeProp.value.type === 'Literal' && typeof sizeProp.value.value === 'string' && sizeProp.value.value === 'medium') {
|
|
559
|
-
// if size is medium, we can remove it as it is the default size
|
|
560
|
-
fixes.push(fixer.remove(sizeProp));
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
} else if (size) {
|
|
564
|
-
fixes.push(fixer.insertTextAfter(openingElement.name, ` size="${size}"`));
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
// Add spacing prop if no existing spacing prop and icon is not imported from migration entrypoint
|
|
568
|
-
if (spacing && spacing !== 'none' && !spacingProp && !migrationImportNode) {
|
|
569
|
-
fixes.push(fixer.insertTextAfter(sizeProp || openingElement.name, ` spacing="${spacing}"`));
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
// rename or remove secondaryColor prop based on shouldUseMigrationPath
|
|
573
|
-
const secondaryColorProp = findProp(attributes, 'secondaryColor');
|
|
574
|
-
if (secondaryColorProp && secondaryColorProp.type === 'JSXAttribute') {
|
|
575
|
-
fixes.push(shouldUseMigrationPath ?
|
|
576
|
-
// replace secondaryColor prop with LEGACY_secondaryColor
|
|
577
|
-
fixer.replaceText(secondaryColorProp.name, 'LEGACY_secondaryColor') :
|
|
578
|
-
// remove secondaryColor prop if shouldUseMigrationPath is false
|
|
579
|
-
fixer.remove(secondaryColorProp));
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
// remove LEGACY props
|
|
583
|
-
if (!shouldUseMigrationPath) {
|
|
584
|
-
['LEGACY_size', 'LEGACY_margin', 'LEGACY_fallbackIcon', 'LEGACY_secondaryColor'].forEach(propName => {
|
|
585
|
-
const legacyProp = findProp(attributes, propName);
|
|
586
|
-
if (legacyProp && legacyProp.type === 'JSXAttribute') {
|
|
587
|
-
fixes.push(fixer.remove(legacyProp));
|
|
588
|
-
}
|
|
589
|
-
});
|
|
590
|
-
}
|
|
591
|
-
} else if (node.type === 'Identifier' && newIconName) {
|
|
592
|
-
fixes.push(fixer.replaceText(node, newIconName));
|
|
593
|
-
}
|
|
594
|
-
return fixes;
|
|
595
|
-
};
|
|
596
|
-
|
|
597
|
-
/**
|
|
598
|
-
* Check if the new icon exists in the migration map
|
|
599
|
-
*/
|
|
600
|
-
const checkIfNewIconExist = error => {
|
|
601
|
-
var _error$data;
|
|
602
|
-
if (!((_error$data = error.data) !== null && _error$data !== void 0 && _error$data.importSource)) {
|
|
603
|
-
return false;
|
|
604
|
-
}
|
|
605
|
-
const iconKey = getIconKey(error.data.importSource);
|
|
606
|
-
const {
|
|
607
|
-
newIcon
|
|
608
|
-
} = baseMigrationMap[iconKey] || {};
|
|
609
|
-
return Boolean(newIcon);
|
|
610
|
-
};
|
|
611
|
-
export const throwManualErrors = ({
|
|
612
|
-
errorsManual,
|
|
613
|
-
errorRanges,
|
|
614
|
-
guidance,
|
|
615
|
-
context,
|
|
616
|
-
isQuietMode
|
|
617
|
-
}) => {
|
|
618
|
-
for (const [key, errorList] of Object.entries(errorsManual)) {
|
|
619
|
-
const node = 'node' in errorList.errors[0] ? errorList.errors[0].node : null;
|
|
620
|
-
if (!node) {
|
|
621
|
-
return;
|
|
622
|
-
}
|
|
623
|
-
const cantMigrateIdentifierError = errorList.errors.find(x => 'messageId' in x && x.messageId === 'cantMigrateIdentifier');
|
|
624
|
-
let isInRange = false;
|
|
625
|
-
if (cantMigrateIdentifierError && isInRangeList(node, errorRanges)) {
|
|
626
|
-
isInRange = true;
|
|
627
|
-
}
|
|
628
|
-
if (isInRange && errorList.errors.length - 1 > 0 || !isInRange && errorList.errors.length > 0) {
|
|
629
|
-
const guidanceMessage = Object.keys(guidance).includes(key) ? guidance[key] : '';
|
|
630
|
-
context.report({
|
|
631
|
-
node,
|
|
632
|
-
messageId: 'noLegacyIconsManualMigration',
|
|
633
|
-
data: {
|
|
634
|
-
iconName: errorList.iconName,
|
|
635
|
-
importSource: errorList.importSource,
|
|
636
|
-
guidance: isQuietMode ? guidanceMessage : `${guidanceMessage}For more information see the below errors.\n`
|
|
637
|
-
}
|
|
638
|
-
});
|
|
639
|
-
if (!isQuietMode) {
|
|
640
|
-
for (const error of errorList.errors) {
|
|
641
|
-
if ('messageId' in error && (error.messageId !== 'cantMigrateIdentifier' || error.messageId === 'cantMigrateIdentifier' && !isInRange)) {
|
|
642
|
-
context.report(error);
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
};
|
|
649
|
-
|
|
650
|
-
// Loops through automatic errors and them after adding the required suggestion/fix
|
|
651
|
-
export const throwAutoErrors = ({
|
|
652
|
-
errorsManual,
|
|
653
|
-
errorsAuto,
|
|
654
|
-
iconSizesInfo,
|
|
655
|
-
legacyIconImports,
|
|
656
|
-
guidance,
|
|
657
|
-
migrationIconImports,
|
|
658
|
-
shouldUseMigrationPath,
|
|
659
|
-
context
|
|
660
|
-
}) => {
|
|
661
|
-
// Set of all the import sources that have manual errors (required later to check if a source has both manual and auto
|
|
662
|
-
// errors in one file making it impossible to just remove the legacy import)
|
|
663
|
-
const allManualErrorSources = Object.entries(errorsManual).reduce((result, option) => {
|
|
664
|
-
const [key, errorInfo] = option;
|
|
665
|
-
if (!errorsAuto.hasOwnProperty(key)) {
|
|
666
|
-
result.add(errorInfo.importSource);
|
|
667
|
-
}
|
|
668
|
-
return result;
|
|
669
|
-
}, new Set());
|
|
670
|
-
// Group errors by import source and remove any unwanted errors
|
|
671
|
-
const groupedErrorList = Object.entries(errorsAuto).reduce((result, option) => {
|
|
672
|
-
const [key, error] = option;
|
|
673
|
-
// Return early if no data
|
|
674
|
-
if (!error.data) {
|
|
675
|
-
return result;
|
|
676
|
-
}
|
|
677
|
-
if (Object.keys(errorsManual).includes(key)) {
|
|
678
|
-
const cantMigrateIdentifierError = errorsManual[key].errors.find(x => 'messageId' in x && x.messageId === 'cantMigrateIdentifier');
|
|
679
|
-
// If cantMigrateIdentifier is the only manual error found we still want to throw the auto error
|
|
680
|
-
if (!(cantMigrateIdentifierError && errorsManual[key].errors.length === 1)) {
|
|
681
|
-
return result;
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
const importSource = error.data.importSource;
|
|
685
|
-
if (!result.hasOwnProperty(importSource)) {
|
|
686
|
-
result[importSource] = [];
|
|
687
|
-
}
|
|
688
|
-
result[importSource].push({
|
|
689
|
-
key,
|
|
690
|
-
...error
|
|
691
|
-
});
|
|
692
|
-
return result;
|
|
693
|
-
}, {});
|
|
694
|
-
for (const [importSource, errorList] of Object.entries(groupedErrorList)) {
|
|
695
|
-
const autoFixers = [];
|
|
696
|
-
// appliedErrorsForImport will contain all the errors FOR A SINGLE IMPORT and will be merged into errorListForReport
|
|
697
|
-
const appliedErrorsForImport = [];
|
|
698
|
-
// Loop over auto errors for a single import source
|
|
699
|
-
for (const [_, error] of errorList.entries()) {
|
|
700
|
-
var _iconSizesInfo$import, _iconSizesInfo$import2, _iconSizesInfo$import3, _legacyIconImports$er, _error$data2, _legacyIconImports$er2, _migrationIconImports;
|
|
701
|
-
const {
|
|
702
|
-
key
|
|
703
|
-
} = error;
|
|
704
|
-
const node = 'node' in error ? error.node : null;
|
|
705
|
-
// Check if there is a manual error for the same import source somewhere else in the same file
|
|
706
|
-
// If that is the case we'll need to provide a suggestion instead of auto-fixing as the suggestion will
|
|
707
|
-
// add another import without removing the old import and this needs to be validated
|
|
708
|
-
const isInManualArray = allManualErrorSources.has(importSource);
|
|
709
|
-
|
|
710
|
-
// Check if the icon has size of small, if so it cannot be automatically migrated. Two suggestions will be provided
|
|
711
|
-
// 1. Use core icon with no spacing
|
|
712
|
-
// 2. Use utility icon with compact spacing
|
|
713
|
-
const isSizeSmall = (_iconSizesInfo$import = iconSizesInfo[importSource]) === null || _iconSizesInfo$import === void 0 ? void 0 : _iconSizesInfo$import.small.includes(key);
|
|
714
|
-
const isMixedSizeUsage = ((_iconSizesInfo$import2 = iconSizesInfo[importSource]) === null || _iconSizesInfo$import2 === void 0 ? void 0 : _iconSizesInfo$import2.small.length) > 0 && ((_iconSizesInfo$import3 = iconSizesInfo[importSource]) === null || _iconSizesInfo$import3 === void 0 ? void 0 : _iconSizesInfo$import3.small.length) < iconSizesInfo[importSource].usageCount;
|
|
715
|
-
|
|
716
|
-
// Icon should be renamed
|
|
717
|
-
// 1. If the icon is in the manual array OR
|
|
718
|
-
// 2. If there is mixed size usages of this icon with size small
|
|
719
|
-
const shouldRenameIcon = isInManualArray || isMixedSizeUsage;
|
|
720
|
-
|
|
721
|
-
// New icon name for renaming if the icon is in the manual array
|
|
722
|
-
const newIconName = getNewIconNameForRenaming(shouldRenameIcon, importSource, errorList[0].data ? (_legacyIconImports$er = legacyIconImports[errorList[0].data.iconName]) === null || _legacyIconImports$er === void 0 ? void 0 : _legacyIconImports$er.importSpecifier : undefined);
|
|
723
|
-
if (!node) {
|
|
724
|
-
continue;
|
|
725
|
-
}
|
|
726
|
-
const guidanceMessage = guidance.hasOwnProperty(key) ? guidance[key] : '';
|
|
727
|
-
if (Object.keys(error).includes('data') && error.data) {
|
|
728
|
-
error.data.guidance = guidanceMessage;
|
|
729
|
-
}
|
|
730
|
-
const shouldForceSmallIcon = ((_error$data2 = error.data) === null || _error$data2 === void 0 ? void 0 : _error$data2.shouldForceSmallIcon) === 'true';
|
|
731
|
-
const fixArguments = error.data ? {
|
|
732
|
-
metadata: {
|
|
733
|
-
...error.data,
|
|
734
|
-
spacing: error.data.isInNewButton ? 'none' : error.data.spacing,
|
|
735
|
-
size: shouldForceSmallIcon ? 'small' : error.data.size
|
|
736
|
-
},
|
|
737
|
-
legacyImportNode: (_legacyIconImports$er2 = legacyIconImports[error.data.iconName]) === null || _legacyIconImports$er2 === void 0 ? void 0 : _legacyIconImports$er2.importNode,
|
|
738
|
-
migrationImportNode: (_migrationIconImports = migrationIconImports[error.data.iconName]) === null || _migrationIconImports === void 0 ? void 0 : _migrationIconImports.importNode,
|
|
739
|
-
shouldUseMigrationPath,
|
|
740
|
-
newIconName: shouldRenameIcon ? newIconName : undefined
|
|
741
|
-
} : null;
|
|
742
|
-
if (!error.data || shouldUseMigrationPath && !checkIfNewIconExist(error) || !fixArguments) {
|
|
743
|
-
continue;
|
|
744
|
-
}
|
|
745
|
-
const isInNewButton = fixArguments.metadata.insideNewButton === 'true';
|
|
746
|
-
if (isSizeSmall && !shouldForceSmallIcon) {
|
|
747
|
-
error.suggest = [{
|
|
748
|
-
desc: isInNewButton ? 'Replace with medium core icon (Recommended)' : 'Replace with medium core icon and no spacing (Recommended)',
|
|
749
|
-
fix: fixer => {
|
|
750
|
-
return [...createPropFixes({
|
|
751
|
-
...fixArguments,
|
|
752
|
-
metadata: {
|
|
753
|
-
...fixArguments.metadata,
|
|
754
|
-
spacing: 'none'
|
|
755
|
-
},
|
|
756
|
-
node,
|
|
757
|
-
fixer
|
|
758
|
-
}), ...createImportFix({
|
|
759
|
-
...fixArguments,
|
|
760
|
-
fixer
|
|
761
|
-
})];
|
|
762
|
-
}
|
|
763
|
-
}, {
|
|
764
|
-
desc: isInNewButton ? 'Replace with small core icon' : 'Replace with small core icon and compact spacing',
|
|
765
|
-
fix: fixer => {
|
|
766
|
-
return [...createPropFixes({
|
|
767
|
-
...fixArguments,
|
|
768
|
-
metadata: {
|
|
769
|
-
...fixArguments.metadata,
|
|
770
|
-
spacing: 'compact',
|
|
771
|
-
size: 'small'
|
|
772
|
-
},
|
|
773
|
-
node,
|
|
774
|
-
fixer
|
|
775
|
-
}), ...createImportFix({
|
|
776
|
-
...fixArguments,
|
|
777
|
-
fixer
|
|
778
|
-
})];
|
|
779
|
-
}
|
|
780
|
-
}];
|
|
781
|
-
} else {
|
|
782
|
-
if (isInManualArray) {
|
|
783
|
-
// provide suggestion if there is a manual error for the same import source and thus the legacy import can't be removed
|
|
784
|
-
error.suggest = [{
|
|
785
|
-
desc: 'Rename icon import, import from the new package, and update props.',
|
|
786
|
-
fix: fixer => {
|
|
787
|
-
return [...createPropFixes({
|
|
788
|
-
...fixArguments,
|
|
789
|
-
node,
|
|
790
|
-
fixer
|
|
791
|
-
}), ...createImportFix({
|
|
792
|
-
...fixArguments,
|
|
793
|
-
fixer
|
|
794
|
-
})];
|
|
795
|
-
}
|
|
796
|
-
}];
|
|
797
|
-
} else {
|
|
798
|
-
// Update Guidance message for auto-fixing
|
|
799
|
-
if (error.data) {
|
|
800
|
-
error.data.guidance = error.data.guidance + `\nTo automatically fix this icon, run the auto-fixer attached to the first use of ${importSource} in this file - either manually, or by saving this file.`;
|
|
801
|
-
}
|
|
802
|
-
// There should only be 1 import fix for each import source and thus only add this at the start of the list
|
|
803
|
-
if (autoFixers.length === 0) {
|
|
804
|
-
autoFixers.push(fixer => createImportFix({
|
|
805
|
-
...fixArguments,
|
|
806
|
-
fixer
|
|
807
|
-
}));
|
|
808
|
-
}
|
|
809
|
-
// Push the prop fix regardless
|
|
810
|
-
autoFixers.push(fixer => createPropFixes({
|
|
811
|
-
...fixArguments,
|
|
812
|
-
node,
|
|
813
|
-
fixer
|
|
814
|
-
}));
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
// Add the error to the appliedErrorsForImport, ready to be thrown later
|
|
818
|
-
appliedErrorsForImport.push(error);
|
|
819
|
-
}
|
|
820
|
-
// We want to have only 1 fix for each import source that is not in the manual array
|
|
821
|
-
// NOTE: If in the manual array, suggestions have been applied above and autoFixers.length will be 0 which will mean no fix is added
|
|
822
|
-
if (autoFixers.length > 0) {
|
|
823
|
-
// Add the fix to only one of the errors in the list of errors from the current import source
|
|
824
|
-
appliedErrorsForImport[0].fix = fixer => {
|
|
825
|
-
return autoFixers.flatMap(autoFixer => autoFixer(fixer));
|
|
826
|
-
};
|
|
827
|
-
}
|
|
828
|
-
// throw errors
|
|
829
|
-
appliedErrorsForImport.forEach(error => {
|
|
830
|
-
context.report(error);
|
|
831
|
-
});
|
|
832
|
-
}
|
|
833
|
-
};
|
|
834
|
-
function findProgramNode(node) {
|
|
835
|
-
while (node && node.parent) {
|
|
836
|
-
if (node.parent.type === 'Program') {
|
|
837
|
-
return node.parent;
|
|
838
|
-
}
|
|
839
|
-
node = node.parent;
|
|
840
|
-
}
|
|
841
|
-
return null;
|
|
842
|
-
}
|
|
843
|
-
function alreadyHasImportedLocalName(programNode, localName, importPath) {
|
|
844
|
-
if (!(programNode !== null && programNode !== void 0 && programNode.body)) {
|
|
845
|
-
return false;
|
|
846
|
-
}
|
|
847
|
-
return programNode.body.some(stmt => {
|
|
848
|
-
if (stmt.type === 'ImportDeclaration' && stmt.source.value === importPath) {
|
|
849
|
-
return stmt.specifiers.some(s => s.local.name === localName);
|
|
850
|
-
}
|
|
851
|
-
return false;
|
|
852
|
-
});
|
|
853
|
-
}
|