@atlaskit/eslint-plugin-design-system 10.12.4 → 10.13.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/dist/cjs/rules/no-legacy-icons/checks.js +90 -44
- package/dist/cjs/rules/no-legacy-icons/helpers.js +44 -12
- package/dist/cjs/rules/no-legacy-icons/index.js +5 -3
- package/dist/cjs/rules/use-heading/config/index.js +2 -1
- package/dist/cjs/rules/use-heading/transformers/native-elements.js +61 -31
- package/dist/cjs/rules/use-primitives-text/config/index.js +2 -1
- package/dist/cjs/rules/use-primitives-text/transformers/emphasis-elements.js +48 -26
- package/dist/cjs/rules/use-primitives-text/transformers/paragraph-elements.js +62 -51
- package/dist/cjs/rules/use-primitives-text/transformers/span-elements.js +56 -32
- package/dist/cjs/rules/use-primitives-text/transformers/strong-elements.js +48 -26
- package/dist/es2019/rules/no-legacy-icons/checks.js +75 -33
- package/dist/es2019/rules/no-legacy-icons/helpers.js +43 -11
- package/dist/es2019/rules/no-legacy-icons/index.js +5 -3
- package/dist/es2019/rules/use-heading/config/index.js +2 -1
- package/dist/es2019/rules/use-heading/transformers/native-elements.js +60 -29
- package/dist/es2019/rules/use-primitives-text/config/index.js +2 -1
- package/dist/es2019/rules/use-primitives-text/transformers/emphasis-elements.js +47 -24
- package/dist/es2019/rules/use-primitives-text/transformers/paragraph-elements.js +63 -52
- package/dist/es2019/rules/use-primitives-text/transformers/span-elements.js +55 -30
- package/dist/es2019/rules/use-primitives-text/transformers/strong-elements.js +47 -24
- package/dist/esm/rules/no-legacy-icons/checks.js +91 -45
- package/dist/esm/rules/no-legacy-icons/helpers.js +43 -11
- package/dist/esm/rules/no-legacy-icons/index.js +5 -3
- package/dist/esm/rules/use-heading/config/index.js +2 -1
- package/dist/esm/rules/use-heading/transformers/native-elements.js +61 -31
- package/dist/esm/rules/use-primitives-text/config/index.js +2 -1
- package/dist/esm/rules/use-primitives-text/transformers/emphasis-elements.js +48 -26
- package/dist/esm/rules/use-primitives-text/transformers/paragraph-elements.js +62 -51
- package/dist/esm/rules/use-primitives-text/transformers/span-elements.js +56 -32
- package/dist/esm/rules/use-primitives-text/transformers/strong-elements.js +48 -26
- package/dist/types/rules/no-legacy-icons/checks.d.ts +4 -1
- package/dist/types/rules/no-legacy-icons/helpers.d.ts +21 -14
- package/dist/types/rules/use-heading/config/index.d.ts +2 -1
- package/dist/types/rules/use-heading/transformers/native-elements.d.ts +5 -1
- package/dist/types/rules/use-primitives-text/config/index.d.ts +1 -0
- package/dist/types/rules/use-primitives-text/transformers/emphasis-elements.d.ts +6 -1
- package/dist/types/rules/use-primitives-text/transformers/paragraph-elements.d.ts +1 -0
- package/dist/types/rules/use-primitives-text/transformers/span-elements.d.ts +6 -1
- package/dist/types/rules/use-primitives-text/transformers/strong-elements.d.ts +6 -1
- package/dist/types-ts4.5/rules/no-legacy-icons/checks.d.ts +4 -1
- package/dist/types-ts4.5/rules/no-legacy-icons/helpers.d.ts +21 -14
- package/dist/types-ts4.5/rules/use-heading/config/index.d.ts +2 -1
- package/dist/types-ts4.5/rules/use-heading/transformers/native-elements.d.ts +5 -1
- package/dist/types-ts4.5/rules/use-primitives-text/config/index.d.ts +1 -0
- package/dist/types-ts4.5/rules/use-primitives-text/transformers/emphasis-elements.d.ts +6 -1
- package/dist/types-ts4.5/rules/use-primitives-text/transformers/paragraph-elements.d.ts +1 -0
- package/dist/types-ts4.5/rules/use-primitives-text/transformers/span-elements.d.ts +6 -1
- package/dist/types-ts4.5/rules/use-primitives-text/transformers/strong-elements.d.ts +6 -1
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
2
|
-
import { canAutoMigrateNewIconBasedOnSize, canMigrateColor, createAutoMigrationError, createCantFindSuitableReplacementError, createCantMigrateColorError, createCantMigrateFunctionUnknownError, createCantMigrateIdentifierError, createCantMigrateReExportError, createCantMigrateSizeUnknown, createCantMigrateSpreadPropsError, createGuidance, createHelpers, getMigrationMapObject, getUpcomingIcons, isSize, locToString } from './helpers';
|
|
2
|
+
import { addToListOfRanges, canAutoMigrateNewIconBasedOnSize, canMigrateColor, createAutoMigrationError, createCantFindSuitableReplacementError, createCantMigrateColorError, createCantMigrateFunctionUnknownError, createCantMigrateIdentifierError, createCantMigrateIdentifierMapOrArrayError, createCantMigrateReExportError, createCantMigrateSizeUnknown, createCantMigrateSpreadPropsError, createGuidance, createHelpers, getMigrationMapObject, getUpcomingIcons, isInRangeList, isSize, locToString } from './helpers';
|
|
3
3
|
export const createChecks = context => {
|
|
4
4
|
//create global variables to be shared by the checks
|
|
5
5
|
const {
|
|
@@ -17,6 +17,9 @@ export const createChecks = context => {
|
|
|
17
17
|
const shouldErrorForAutoMigration = getConfigFlag('shouldErrorForAutoMigration', true);
|
|
18
18
|
const isQuietMode = getConfigFlag('quiet', false);
|
|
19
19
|
|
|
20
|
+
// Sorted list of ranges
|
|
21
|
+
let errorRanges = [];
|
|
22
|
+
|
|
20
23
|
/**
|
|
21
24
|
* Adds the legacy Icon and new button imports to the correct global arrays to be used by the other checks
|
|
22
25
|
* @param node The import node found by ESLint
|
|
@@ -56,8 +59,8 @@ export const createChecks = context => {
|
|
|
56
59
|
if (isNodeOfType(node, 'VariableDeclaration')) {
|
|
57
60
|
const isExported = node.parent && isNodeOfType(node.parent, 'ExportNamedDeclaration');
|
|
58
61
|
for (const decl of node.declarations) {
|
|
59
|
-
if (isNodeOfType(decl, 'VariableDeclarator') && 'init'
|
|
60
|
-
if (decl.init.name
|
|
62
|
+
if (isNodeOfType(decl, 'VariableDeclarator') && Object.keys(decl).includes('init') && Object.keys(decl).includes('id') && decl.init && decl.id && 'name' in decl.id && decl.id.name && isNodeOfType(decl.init, 'Identifier')) {
|
|
63
|
+
if (Object.keys(legacyIconImports).includes(decl.init.name)) {
|
|
61
64
|
legacyIconImports[decl.id.name] = {
|
|
62
65
|
packageName: legacyIconImports[decl.init.name].packageName,
|
|
63
66
|
exported: legacyIconImports[decl.init.name].exported || isExported
|
|
@@ -77,16 +80,17 @@ export const createChecks = context => {
|
|
|
77
80
|
const checkExportDefaultDeclaration = node => {
|
|
78
81
|
let exportName = '';
|
|
79
82
|
let packageName = '';
|
|
80
|
-
if ('declaration'
|
|
83
|
+
if (Object.keys(node).includes('declaration') && node.declaration && isNodeOfType(node.declaration, 'Identifier') && Object.keys(legacyIconImports).includes(node.declaration.name)) {
|
|
81
84
|
packageName = legacyIconImports[node.declaration.name].packageName;
|
|
82
85
|
exportName = 'Default export';
|
|
83
|
-
} else if ('declaration'
|
|
86
|
+
} else if (Object.keys(node).includes('declaration') && node.declaration && isNodeOfType(node.declaration, 'AssignmentExpression') && isNodeOfType(node.declaration.left, 'Identifier') && isNodeOfType(node.declaration.right, 'Identifier') && Object.keys(legacyIconImports).includes(node.declaration.right.name)) {
|
|
84
87
|
packageName = legacyIconImports[node.declaration.right.name].packageName;
|
|
85
88
|
exportName = node.declaration.left.name;
|
|
86
89
|
} else {
|
|
87
90
|
return;
|
|
88
91
|
}
|
|
89
92
|
createCantMigrateReExportError(node, packageName, exportName, errorsManual);
|
|
93
|
+
addToListOfRanges(node, errorRanges);
|
|
90
94
|
guidance[locToString(node)] = createGuidance(packageName);
|
|
91
95
|
};
|
|
92
96
|
|
|
@@ -96,19 +100,21 @@ export const createChecks = context => {
|
|
|
96
100
|
*/
|
|
97
101
|
const checkExportNamedVariables = node => {
|
|
98
102
|
// export {default as AddIcon} from '@atlaskit/icon/glyph/add';
|
|
99
|
-
if (node.source && isNodeOfType(node.source, 'Literal') &&
|
|
103
|
+
if (node.source && isNodeOfType(node.source, 'Literal') && Object.keys(node.source).includes('value')) {
|
|
100
104
|
const moduleSource = node.source.value;
|
|
101
105
|
if (typeof moduleSource === 'string' && ['@atlaskit/icon/glyph/', '@atlaskit/icon-object/glyph/'].find(val => moduleSource.startsWith(val)) && node.specifiers.length) {
|
|
102
106
|
for (const spec of node.specifiers) {
|
|
103
107
|
createCantMigrateReExportError(spec, moduleSource, spec.exported.name, errorsManual);
|
|
108
|
+
addToListOfRanges(spec, errorRanges);
|
|
104
109
|
guidance[locToString(spec)] = createGuidance(moduleSource);
|
|
105
110
|
}
|
|
106
111
|
}
|
|
107
112
|
} else if (node.declaration && isNodeOfType(node.declaration, 'VariableDeclaration')) {
|
|
108
113
|
// export const Icon = AddIcon;
|
|
109
114
|
for (const decl of node.declaration.declarations) {
|
|
110
|
-
if (isNodeOfType(decl, 'VariableDeclarator') && 'init'
|
|
115
|
+
if (isNodeOfType(decl, 'VariableDeclarator') && Object.keys(decl).includes('init') && decl.init && isNodeOfType(decl.init, 'Identifier') && Object.keys(legacyIconImports).includes(decl.init.name)) {
|
|
111
116
|
createCantMigrateReExportError(node, legacyIconImports[decl.init.name].packageName, decl.init.name, errorsManual);
|
|
117
|
+
addToListOfRanges(node, errorRanges);
|
|
112
118
|
guidance[locToString(node)] = createGuidance(legacyIconImports[decl.init.name].packageName);
|
|
113
119
|
}
|
|
114
120
|
}
|
|
@@ -120,13 +126,14 @@ export const createChecks = context => {
|
|
|
120
126
|
* export { AddIcon, CrossIcon as default }
|
|
121
127
|
*/
|
|
122
128
|
for (const spec of node.specifiers) {
|
|
123
|
-
if (spec.local.name
|
|
129
|
+
if (Object.keys(legacyIconImports).includes(spec.local.name)) {
|
|
124
130
|
//update legacy imports to be exported
|
|
125
131
|
legacyIconImports[spec.local.name] = {
|
|
126
132
|
packageName: legacyIconImports[spec.local.name].packageName,
|
|
127
133
|
exported: true
|
|
128
134
|
};
|
|
129
135
|
createCantMigrateReExportError(spec, legacyIconImports[spec.local.name].packageName, spec.exported.name, errorsManual);
|
|
136
|
+
addToListOfRanges(spec, errorRanges);
|
|
130
137
|
guidance[locToString(spec)] = createGuidance(legacyIconImports[spec.local.name].packageName);
|
|
131
138
|
}
|
|
132
139
|
}
|
|
@@ -141,8 +148,9 @@ export const createChecks = context => {
|
|
|
141
148
|
if (!isNodeOfType(node, 'Identifier')) {
|
|
142
149
|
return;
|
|
143
150
|
}
|
|
144
|
-
if (node.name && node.name
|
|
145
|
-
|
|
151
|
+
if (node.name && Object.keys(legacyIconImports).includes(node.name) && legacyIconImports[node.name].packageName) {
|
|
152
|
+
createCantMigrateIdentifierMapOrArrayError(node, legacyIconImports[node.name].packageName, node.name, errorsManual);
|
|
153
|
+
addToListOfRanges(node, errorRanges);
|
|
146
154
|
guidance[locToString(node)] = createGuidance(legacyIconImports[node.name].packageName);
|
|
147
155
|
}
|
|
148
156
|
};
|
|
@@ -161,7 +169,7 @@ export const createChecks = context => {
|
|
|
161
169
|
if (!isNodeOfType(node.parent, 'JSXExpressionContainer') || !isNodeOfType(node.parent.parent, 'JSXAttribute') || !isNodeOfType(node.parent.parent.parent, 'JSXOpeningElement')) {
|
|
162
170
|
return;
|
|
163
171
|
}
|
|
164
|
-
if (node.name
|
|
172
|
+
if (Object.keys(legacyIconImports).includes(node.name) && isNodeOfType(node.parent.parent.name, 'JSXIdentifier') && node.parent.parent.name.name !== 'LEGACY_fallbackIcon') {
|
|
165
173
|
var _migrationMapObject$s;
|
|
166
174
|
const migrationMapObject = getMigrationMapObject(legacyIconImports[node.name].packageName);
|
|
167
175
|
const upcomingIcon = getUpcomingIcons(legacyIconImports[node.name].packageName);
|
|
@@ -170,16 +178,35 @@ export const createChecks = context => {
|
|
|
170
178
|
const isInNewButton = isNodeOfType(node.parent.parent.parent.name, 'JSXIdentifier') && newButtonImports.has(node.parent.parent.parent.name.name);
|
|
171
179
|
if (newIcon && isInNewButton && isNewIconMigratable || upcomingIcon && isInNewButton && isNewIconMigratable) {
|
|
172
180
|
createAutoMigrationError(node, legacyIconImports[node.name].packageName, node.name, errorsAuto);
|
|
181
|
+
addToListOfRanges(node, errorRanges);
|
|
173
182
|
guidance[locToString(node)] = createGuidance(legacyIconImports[node.name].packageName, isInNewButton, 'medium');
|
|
174
183
|
} else if (!newIcon && !upcomingIcon || !isNewIconMigratable) {
|
|
175
184
|
createCantFindSuitableReplacementError(node, legacyIconImports[node.name].packageName, node.name, errorsManual);
|
|
185
|
+
addToListOfRanges(node, errorRanges);
|
|
176
186
|
guidance[locToString(node)] = createGuidance(legacyIconImports[node.name].packageName, isInNewButton);
|
|
177
187
|
} else if (!isInNewButton) {
|
|
178
188
|
createCantMigrateFunctionUnknownError(node, legacyIconImports[node.name].packageName, node.name, errorsManual);
|
|
189
|
+
addToListOfRanges(node, errorRanges);
|
|
179
190
|
guidance[locToString(node)] = createGuidance(legacyIconImports[node.name].packageName, isInNewButton);
|
|
180
191
|
}
|
|
181
192
|
}
|
|
182
193
|
};
|
|
194
|
+
const checkIconReference = node => {
|
|
195
|
+
//check the reference to see if it's a legacy icon, if not exit early
|
|
196
|
+
if (!Object.keys(legacyIconImports).includes(node.name)) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
//if this is an import statement then exit early
|
|
200
|
+
if (node.parent && (isNodeOfType(node.parent, 'ImportSpecifier') || isNodeOfType(node.parent, 'ImportDefaultSpecifier'))) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
//if in Fallback prop, do not error
|
|
204
|
+
if (node.parent && node.parent.parent && isNodeOfType(node.parent.parent, 'JSXAttribute') && isNodeOfType(node.parent.parent.name, 'JSXIdentifier') && node.parent.parent.name.name === 'LEGACY_fallbackIcon') {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
// manually error
|
|
208
|
+
createCantMigrateIdentifierError(node, legacyIconImports[node.name].packageName, node.name, errorsManual);
|
|
209
|
+
};
|
|
183
210
|
|
|
184
211
|
/**
|
|
185
212
|
* Checks if a legacy icon is being rendered and stores the errors in the global array
|
|
@@ -197,7 +224,7 @@ export const createChecks = context => {
|
|
|
197
224
|
}
|
|
198
225
|
const name = node.openingElement.name.name;
|
|
199
226
|
// Legacy icons rendered as JSX elements
|
|
200
|
-
if (
|
|
227
|
+
if (Object.keys(legacyIconImports).includes(name)) {
|
|
201
228
|
var _node$parent2, _node$parent2$parent, _node$parent3, _node$parent3$parent, _node$parent3$parent$, _size, _size2;
|
|
202
229
|
// Determine if inside a new button - if so:
|
|
203
230
|
// - Assume spread props are safe - still error if props explicitly set to unmigratable values
|
|
@@ -277,6 +304,7 @@ export const createChecks = context => {
|
|
|
277
304
|
} else if ((!newIcon && !upcomingIcon || !isNewIconMigratable) && size) {
|
|
278
305
|
createCantFindSuitableReplacementError(node, legacyIconImports[name].packageName, name, errorsManual, upcomingIcon ? true : migrationMapObject ? true : false);
|
|
279
306
|
}
|
|
307
|
+
addToListOfRanges(node, errorRanges);
|
|
280
308
|
guidance[locToString(node)] = createGuidance(legacyIconImports[name].packageName, insideNewButton, size && isSize(size) ? size : undefined);
|
|
281
309
|
}
|
|
282
310
|
};
|
|
@@ -286,10 +314,11 @@ export const createChecks = context => {
|
|
|
286
314
|
* @param node The function call node found by ESLint
|
|
287
315
|
*/
|
|
288
316
|
const checkCallExpression = node => {
|
|
289
|
-
if ('arguments'
|
|
317
|
+
if (Object.keys(node).includes('arguments') && node.arguments.length) {
|
|
290
318
|
for (const arg of node.arguments) {
|
|
291
|
-
if (isNodeOfType(arg, 'Identifier') && arg.name
|
|
319
|
+
if (isNodeOfType(arg, 'Identifier') && Object.keys(legacyIconImports).includes(arg.name) && legacyIconImports[arg.name].packageName) {
|
|
292
320
|
createCantMigrateFunctionUnknownError(node, legacyIconImports[arg.name].packageName, arg.name, errorsManual);
|
|
321
|
+
addToListOfRanges(node, errorRanges);
|
|
293
322
|
guidance[locToString(node)] = createGuidance(legacyIconImports[arg.name].packageName);
|
|
294
323
|
}
|
|
295
324
|
}
|
|
@@ -303,20 +332,29 @@ export const createChecks = context => {
|
|
|
303
332
|
if (shouldErrorForManualMigration) {
|
|
304
333
|
for (const [key, errorList] of Object.entries(errorsManual)) {
|
|
305
334
|
const node = 'node' in errorList.errors[0] ? errorList.errors[0].node : null;
|
|
335
|
+
const cantMigrateIdentifierError = errorList.errors.find(x => 'messageId' in x && x.messageId === 'cantMigrateIdentifier');
|
|
306
336
|
if (node) {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
337
|
+
let isInRange = false;
|
|
338
|
+
if (cantMigrateIdentifierError && isInRangeList(node, errorRanges)) {
|
|
339
|
+
isInRange = true;
|
|
340
|
+
}
|
|
341
|
+
if (isInRange && errorList.errors.length - 1 > 0 || !isInRange && errorList.errors.length > 0) {
|
|
342
|
+
const guidanceMessage = Object.keys(guidance).includes(key) ? guidance[key] : '';
|
|
343
|
+
context.report({
|
|
344
|
+
node,
|
|
345
|
+
messageId: 'noLegacyIconsManualMigration',
|
|
346
|
+
data: {
|
|
347
|
+
iconName: errorList.iconName,
|
|
348
|
+
importSource: errorList.importSource,
|
|
349
|
+
guidance: isQuietMode ? guidanceMessage : `${guidanceMessage}For more information see the below errors.\n`
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
if (!isQuietMode) {
|
|
353
|
+
for (const error of errorList.errors) {
|
|
354
|
+
if ('messageId' in error && (error.messageId !== 'cantMigrateIdentifier' || error.messageId === 'cantMigrateIdentifier' && !isInRange)) {
|
|
355
|
+
context.report(error);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
320
358
|
}
|
|
321
359
|
}
|
|
322
360
|
}
|
|
@@ -326,14 +364,17 @@ export const createChecks = context => {
|
|
|
326
364
|
for (const [key, error] of Object.entries(errorsAuto)) {
|
|
327
365
|
// If there's a manual error that exists for this same component,
|
|
328
366
|
// don't throw the auto error
|
|
329
|
-
if (
|
|
330
|
-
|
|
331
|
-
|
|
367
|
+
if (Object.keys(errorsManual).includes(key)) {
|
|
368
|
+
const cantMigrateIdentifierError = errorsManual[key].errors.find(x => 'messageId' in x && x.messageId === 'cantMigrateIdentifier');
|
|
369
|
+
if (!cantMigrateIdentifierError || cantMigrateIdentifierError && errorsManual[key].errors.length > 1) {
|
|
370
|
+
delete errorsAuto[key];
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
332
373
|
}
|
|
333
374
|
const node = 'node' in error ? error.node : null;
|
|
334
375
|
if (node) {
|
|
335
|
-
const guidanceMessage = key
|
|
336
|
-
if ('data'
|
|
376
|
+
const guidanceMessage = Object.keys(guidance).includes(key) ? guidance[key] : '';
|
|
377
|
+
if (Object.keys(error).includes('data') && error.data) {
|
|
337
378
|
error.data.guidance = guidanceMessage;
|
|
338
379
|
}
|
|
339
380
|
context.report(error);
|
|
@@ -350,6 +391,7 @@ export const createChecks = context => {
|
|
|
350
391
|
checkIconAsProp,
|
|
351
392
|
checkJSXElement,
|
|
352
393
|
checkCallExpression,
|
|
353
|
-
throwErrors
|
|
394
|
+
throwErrors,
|
|
395
|
+
checkIconReference
|
|
354
396
|
};
|
|
355
397
|
};
|
|
@@ -90,12 +90,12 @@ export const createGuidance = (iconPackage, insideNewButton = false, size) => {
|
|
|
90
90
|
} else {
|
|
91
91
|
guidance += `No equivalent icon for this size, ${size}, in new set.`;
|
|
92
92
|
}
|
|
93
|
-
guidance += `${migrationMapObject.sizeGuidance[size]
|
|
93
|
+
guidance += `${Object.keys(migrationOutcomeDescriptionMap).includes(migrationMapObject.sizeGuidance[size]) ? ` Please: ${migrationOutcomeDescriptionMap[migrationMapObject.sizeGuidance[size]]}` : ' No migration size advice given.'}\n`;
|
|
94
94
|
} else {
|
|
95
95
|
guidance = `Use ${newIcon.name} from ${newIcon.package}/${newIcon.type}/${newIcon.name} instead.\nMigration suggestions, depending on the legacy icon size:\n`;
|
|
96
96
|
Object.entries(migrationMapObject.sizeGuidance).forEach(([size, value]) => {
|
|
97
97
|
guidance += `\t- ${size}: `;
|
|
98
|
-
if (!(
|
|
98
|
+
if (!Object.keys(migrationOutcomeDescriptionMap).includes(value)) {
|
|
99
99
|
guidance += 'No migration advice given.\n';
|
|
100
100
|
} else {
|
|
101
101
|
guidance += `${migrationOutcomeDescriptionMap[value]}.\n`;
|
|
@@ -121,12 +121,12 @@ export const createGuidance = (iconPackage, insideNewButton = false, size) => {
|
|
|
121
121
|
* @returns True if the color can be migrated, false otherwise
|
|
122
122
|
*/
|
|
123
123
|
export const canMigrateColor = color => {
|
|
124
|
-
if (color.match(/^color\.
|
|
125
|
-
return true;
|
|
126
|
-
} else if (color.match(/^color\.icon/)) {
|
|
124
|
+
if (color.match(/^color\.icon/)) {
|
|
127
125
|
return true;
|
|
128
126
|
} else if (color.match(/^color\.link/)) {
|
|
129
127
|
return true;
|
|
128
|
+
} else if (color.match(/^color\.text/)) {
|
|
129
|
+
return true;
|
|
130
130
|
} else if (color === 'currentColor') {
|
|
131
131
|
return true;
|
|
132
132
|
} else {
|
|
@@ -134,8 +134,11 @@ export const canMigrateColor = color => {
|
|
|
134
134
|
}
|
|
135
135
|
};
|
|
136
136
|
export const locToString = node => {
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
if (node.range && node.range.length >= 2) {
|
|
138
|
+
return `${node.range[0]}:${node.range[1]}`;
|
|
139
|
+
} else {
|
|
140
|
+
return '';
|
|
141
|
+
}
|
|
139
142
|
};
|
|
140
143
|
export const createCantMigrateReExportError = (node, packageName, exportName, errors) => {
|
|
141
144
|
const myError = {
|
|
@@ -148,10 +151,10 @@ export const createCantMigrateReExportError = (node, packageName, exportName, er
|
|
|
148
151
|
};
|
|
149
152
|
pushManualError(locToString(node), errors, myError, packageName, exportName);
|
|
150
153
|
};
|
|
151
|
-
export const
|
|
154
|
+
export const createCantMigrateIdentifierMapOrArrayError = (node, packageName, exportName, errors) => {
|
|
152
155
|
const myError = {
|
|
153
156
|
node,
|
|
154
|
-
messageId: '
|
|
157
|
+
messageId: 'cantMigrateIdentifierMapOrArray',
|
|
155
158
|
data: {
|
|
156
159
|
packageName,
|
|
157
160
|
exportName
|
|
@@ -159,6 +162,17 @@ export const createCantMigrateIdentifierError = (node, packageName, exportName,
|
|
|
159
162
|
};
|
|
160
163
|
pushManualError(locToString(node), errors, myError, packageName, exportName);
|
|
161
164
|
};
|
|
165
|
+
export const createCantMigrateIdentifierError = (node, packageName, exportName, errors) => {
|
|
166
|
+
const myError = {
|
|
167
|
+
node,
|
|
168
|
+
messageId: 'cantMigrateIdentifier',
|
|
169
|
+
data: {
|
|
170
|
+
iconSource: packageName,
|
|
171
|
+
iconName: exportName
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
pushManualError(locToString(node), errors, myError, packageName, exportName);
|
|
175
|
+
};
|
|
162
176
|
export const createCantFindSuitableReplacementError = (node, importSource, iconName, errors, sizeIssue) => {
|
|
163
177
|
const myError = {
|
|
164
178
|
node,
|
|
@@ -221,7 +235,7 @@ export const createAutoMigrationError = (node, importSource, iconName, errors) =
|
|
|
221
235
|
errors[locToString(node)] = myError;
|
|
222
236
|
};
|
|
223
237
|
const pushManualError = (key, errors, myError, importSource, iconName) => {
|
|
224
|
-
if (
|
|
238
|
+
if (Object.keys(errors).includes(key)) {
|
|
225
239
|
errors[key].errors.push(myError);
|
|
226
240
|
} else {
|
|
227
241
|
errors[key] = {
|
|
@@ -269,7 +283,7 @@ export const createHelpers = context => {
|
|
|
269
283
|
* @returns defaultValue if the configuration flag is not set, the defaultValue of the configuration flag otherwise
|
|
270
284
|
*/
|
|
271
285
|
const getConfigFlag = (key, defaultValue) => {
|
|
272
|
-
if (context.options.length > 0 && context.options[0] &&
|
|
286
|
+
if (context.options.length > 0 && context.options[0] && Object.keys(context.options[0]).includes(key)) {
|
|
273
287
|
return context.options[0][key] === !defaultValue ? !defaultValue : defaultValue;
|
|
274
288
|
}
|
|
275
289
|
return defaultValue;
|
|
@@ -288,4 +302,22 @@ export const createHelpers = context => {
|
|
|
288
302
|
getTokenCallValue,
|
|
289
303
|
getConfigFlag
|
|
290
304
|
};
|
|
305
|
+
};
|
|
306
|
+
export const addToListOfRanges = (node, sortedListOfRangesForErrors) => {
|
|
307
|
+
if (node.range && node.range.length >= 2) {
|
|
308
|
+
sortedListOfRangesForErrors.push({
|
|
309
|
+
start: node.range[0],
|
|
310
|
+
end: node.range[1]
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
export const isInRangeList = (node, sortedListOfRangesForErrors) => {
|
|
315
|
+
const {
|
|
316
|
+
range
|
|
317
|
+
} = node;
|
|
318
|
+
if (!range || range.length < 2) {
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
const found = sortedListOfRangesForErrors.find(currRange => range[0] >= currRange.start && range[1] <= currRange.end);
|
|
322
|
+
return !!found;
|
|
291
323
|
};
|
|
@@ -35,8 +35,8 @@ const rule = createLintRule({
|
|
|
35
35
|
cantMigrateSpreadProps: `This usage of Icon uses spread props in a way that can't be automatically migrated. Please explicitly define the following props after spread: '{{missingProps}}' `,
|
|
36
36
|
cantMigrateSizeUnknown: `This usage of Icon sets the size via a variable or function that can't be determined.`,
|
|
37
37
|
cantMigrateFunctionUnknown: `'{{iconName}}' from legacy '{{importSource}}' is used in unknown function/component. Please manually migrate this icon.`,
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
cantMigrateIdentifierMapOrArray: `This icon is passed to other components via a map or array, in a way that can't be automatically migrated. Please manually migrate wherever this expression is used and use the icon components directly.`,
|
|
39
|
+
cantMigrateIdentifier: `This is a legacy icon, {{iconName}} from {{iconSource}}, being referenced. Please manually migrate.`
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
42
|
create(context) {
|
|
@@ -53,7 +53,8 @@ const rule = createLintRule({
|
|
|
53
53
|
checkIconAsProp,
|
|
54
54
|
checkJSXElement,
|
|
55
55
|
checkCallExpression,
|
|
56
|
-
throwErrors
|
|
56
|
+
throwErrors,
|
|
57
|
+
checkIconReference
|
|
57
58
|
} = createChecks(context);
|
|
58
59
|
return errorBoundary({
|
|
59
60
|
// Track imports of relevant components
|
|
@@ -70,6 +71,7 @@ const rule = createLintRule({
|
|
|
70
71
|
JSXElement: checkJSXElement,
|
|
71
72
|
// Icons called as an argument of a function (i.e. icon={DefaultIcon(AddIcon)})
|
|
72
73
|
CallExpression: checkCallExpression,
|
|
74
|
+
Identifier: checkIconReference,
|
|
73
75
|
'Program:exit': throwErrors
|
|
74
76
|
}, failSilently);
|
|
75
77
|
}
|
|
@@ -17,65 +17,96 @@ export const NativeElements = {
|
|
|
17
17
|
config
|
|
18
18
|
}) {
|
|
19
19
|
// Check whether all criteria needed to make a transformation are met
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
const fix = NativeElements._fix(node, {
|
|
20
|
+
const {
|
|
21
|
+
success,
|
|
22
|
+
autoFixable
|
|
23
|
+
} = NativeElements._check(node, {
|
|
27
24
|
context,
|
|
28
25
|
config
|
|
29
26
|
});
|
|
30
|
-
|
|
31
|
-
node,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
if (success && autoFixable) {
|
|
28
|
+
const fix = NativeElements._fix(node, {
|
|
29
|
+
context,
|
|
30
|
+
config
|
|
31
|
+
});
|
|
32
|
+
context.report({
|
|
33
|
+
node,
|
|
34
|
+
messageId: 'preferHeading',
|
|
35
|
+
...(config.enableUnsafeAutofix ? {
|
|
38
36
|
fix
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
} : {
|
|
38
|
+
suggest: [{
|
|
39
|
+
desc: `Convert to Heading`,
|
|
40
|
+
fix
|
|
41
|
+
}]
|
|
42
|
+
})
|
|
43
|
+
});
|
|
44
|
+
} else if (success && config.enableUnsafeReport) {
|
|
45
|
+
context.report({
|
|
46
|
+
node,
|
|
47
|
+
messageId: 'preferHeading'
|
|
48
|
+
});
|
|
49
|
+
}
|
|
42
50
|
},
|
|
43
51
|
_check(node, {
|
|
44
52
|
config
|
|
45
53
|
}) {
|
|
46
54
|
if (!config.patterns.includes('native-elements')) {
|
|
47
|
-
return
|
|
55
|
+
return {
|
|
56
|
+
success: false
|
|
57
|
+
};
|
|
48
58
|
}
|
|
49
59
|
if (!isNodeOfType(node, 'JSXElement')) {
|
|
50
|
-
return
|
|
60
|
+
return {
|
|
61
|
+
success: false
|
|
62
|
+
};
|
|
51
63
|
}
|
|
52
64
|
if (!node.children.length) {
|
|
53
|
-
return
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return false;
|
|
65
|
+
return {
|
|
66
|
+
success: false
|
|
67
|
+
};
|
|
57
68
|
}
|
|
58
69
|
const elementName = ast.JSXElement.getName(node);
|
|
59
70
|
if (!Object.keys(tagSizeMap).includes(elementName)) {
|
|
60
|
-
return
|
|
71
|
+
return {
|
|
72
|
+
success: false
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (!node.parent) {
|
|
76
|
+
return {
|
|
77
|
+
success: true,
|
|
78
|
+
autoFixable: false
|
|
79
|
+
};
|
|
61
80
|
}
|
|
62
81
|
|
|
63
82
|
// Element has to be first element of its siblings
|
|
64
83
|
if (!(isNodeOfType(node.parent, 'JSXElement') || isNodeOfType(node.parent, 'JSXFragment'))) {
|
|
65
|
-
return
|
|
84
|
+
return {
|
|
85
|
+
success: true,
|
|
86
|
+
autoFixable: false
|
|
87
|
+
};
|
|
66
88
|
}
|
|
67
89
|
const siblings = ast.JSXElement.getChildren(node.parent);
|
|
68
90
|
if (siblings.length > 1) {
|
|
69
91
|
var _siblings$0$range, _node$range, _siblings$0$range2, _node$range2;
|
|
70
92
|
// Only report if element is first child element
|
|
71
93
|
if (((_siblings$0$range = siblings[0].range) === null || _siblings$0$range === void 0 ? void 0 : _siblings$0$range[0]) !== ((_node$range = node.range) === null || _node$range === void 0 ? void 0 : _node$range[0]) || ((_siblings$0$range2 = siblings[0].range) === null || _siblings$0$range2 === void 0 ? void 0 : _siblings$0$range2[1]) !== ((_node$range2 = node.range) === null || _node$range2 === void 0 ? void 0 : _node$range2[1])) {
|
|
72
|
-
return
|
|
94
|
+
return {
|
|
95
|
+
success: true,
|
|
96
|
+
autoFixable: false
|
|
97
|
+
};
|
|
73
98
|
}
|
|
74
99
|
}
|
|
75
100
|
if (!ast.JSXElement.hasAllowedAttrsOnly(node, allowedAttrs)) {
|
|
76
|
-
return
|
|
101
|
+
return {
|
|
102
|
+
success: true,
|
|
103
|
+
autoFixable: false
|
|
104
|
+
};
|
|
77
105
|
}
|
|
78
|
-
return
|
|
106
|
+
return {
|
|
107
|
+
success: true,
|
|
108
|
+
autoFixable: true
|
|
109
|
+
};
|
|
79
110
|
},
|
|
80
111
|
_fix(node, {
|
|
81
112
|
context
|
|
@@ -2,7 +2,8 @@ const defaults = {
|
|
|
2
2
|
failSilently: false,
|
|
3
3
|
patterns: ['paragraph-elements', 'span-elements', 'strong-elements', 'emphasis-elements'],
|
|
4
4
|
inheritColor: false,
|
|
5
|
-
enableUnsafeAutofix: false
|
|
5
|
+
enableUnsafeAutofix: false,
|
|
6
|
+
enableUnsafeReport: false
|
|
6
7
|
};
|
|
7
8
|
export const getConfig = overrides => {
|
|
8
9
|
return Object.assign({}, defaults, overrides);
|
|
@@ -13,55 +13,78 @@ export const EmphasisElements = {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
// Check whether all criteria needed to make a transformation are met
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
const fix = EmphasisElements._fix(node, {
|
|
16
|
+
const {
|
|
17
|
+
success,
|
|
18
|
+
autoFixable
|
|
19
|
+
} = EmphasisElements._check(node, {
|
|
23
20
|
context,
|
|
24
21
|
config
|
|
25
22
|
});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
23
|
+
if (success && autoFixable) {
|
|
24
|
+
const fix = EmphasisElements._fix(node, {
|
|
25
|
+
context,
|
|
26
|
+
config
|
|
27
|
+
});
|
|
28
|
+
context.report({
|
|
29
|
+
node: node.openingElement,
|
|
30
|
+
messageId: 'preferPrimitivesText',
|
|
31
|
+
...(config.enableUnsafeAutofix ? {
|
|
34
32
|
fix
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
} : {
|
|
34
|
+
suggest: [{
|
|
35
|
+
desc: `Convert to Text`,
|
|
36
|
+
fix
|
|
37
|
+
}]
|
|
38
|
+
})
|
|
39
|
+
});
|
|
40
|
+
} else if (success && config.enableUnsafeReport) {
|
|
41
|
+
context.report({
|
|
42
|
+
node: node.openingElement,
|
|
43
|
+
messageId: 'preferPrimitivesText'
|
|
44
|
+
});
|
|
45
|
+
}
|
|
38
46
|
},
|
|
39
47
|
_check(node, {
|
|
40
48
|
context,
|
|
41
49
|
config
|
|
42
50
|
}) {
|
|
43
51
|
if (!config.patterns.includes('emphasis-elements')) {
|
|
44
|
-
return
|
|
52
|
+
return {
|
|
53
|
+
success: false
|
|
54
|
+
};
|
|
45
55
|
}
|
|
46
56
|
const elementName = ast.JSXElement.getName(node);
|
|
47
57
|
if (elementName !== 'em') {
|
|
48
|
-
return
|
|
58
|
+
return {
|
|
59
|
+
success: false
|
|
60
|
+
};
|
|
49
61
|
}
|
|
50
62
|
if (!node.children.length) {
|
|
51
|
-
return
|
|
63
|
+
return {
|
|
64
|
+
success: false
|
|
65
|
+
};
|
|
52
66
|
}
|
|
53
67
|
|
|
54
68
|
// Element has no unallowed props
|
|
55
69
|
if (!ast.JSXElement.hasAllowedAttrsOnly(node, allowedAttrs)) {
|
|
56
|
-
return
|
|
70
|
+
return {
|
|
71
|
+
success: true,
|
|
72
|
+
autoFixable: false
|
|
73
|
+
};
|
|
57
74
|
}
|
|
58
75
|
|
|
59
76
|
// If there is more than one `@atlaskit/primitives` import, then it becomes difficult to determine which import to transform
|
|
60
77
|
const importDeclaration = ast.Root.findImportsByModule(context.getSourceCode().ast.body, '@atlaskit/primitives');
|
|
61
78
|
if (importDeclaration.length > 1) {
|
|
62
|
-
return
|
|
79
|
+
return {
|
|
80
|
+
success: true,
|
|
81
|
+
autoFixable: false
|
|
82
|
+
};
|
|
63
83
|
}
|
|
64
|
-
return
|
|
84
|
+
return {
|
|
85
|
+
success: true,
|
|
86
|
+
autoFixable: true
|
|
87
|
+
};
|
|
65
88
|
},
|
|
66
89
|
_fix(node, {
|
|
67
90
|
context,
|