Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keep typeAnnotation when replacing identifier #608

Merged
merged 16 commits into from
Mar 17, 2020
65 changes: 4 additions & 61 deletions rules/prevent-abbreviations.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ const {defaultsDeep, upperFirst, lowerFirst} = require('lodash');
const getDocumentationUrl = require('./utils/get-documentation-url');
const avoidCapture = require('./utils/avoid-capture');
const cartesianProductSamples = require('./utils/cartesian-product-samples');
const isSameNode = require('./utils/is-same-node');
const isShorthandPropertyIdentifier = require('./utils/is-shorthand-property-identifier');
const isShorthandImportIdentifier = require('./utils/is-shorthand-import-identifier');
const renameIdentifier = require('./utils/rename-identifier');

const isUpperCase = string => string === string.toUpperCase();
const isUpperFirst = string => isUpperCase(string[0]);
Expand Down Expand Up @@ -398,65 +400,6 @@ const shouldFix = variable => {
return !variableIdentifiers(variable).some(isExportedIdentifier);
};

const isShorthandPropertyIdentifier = identifier => {
return (
identifier.parent.type === 'Property' &&
identifier.parent.shorthand &&
isSameNode(identifier, identifier.parent.key)
);
};

const isAssignmentPatternShorthandPropertyIdentifier = identifier => {
return (
identifier.parent.type === 'AssignmentPattern' &&
identifier.parent.left === identifier &&
identifier.parent.parent.type === 'Property' &&
isSameNode(identifier, identifier.parent.parent.key) &&
identifier.parent.parent.value === identifier.parent &&
identifier.parent.parent.shorthand
);
};

const isShorthandImportIdentifier = identifier => {
return (
identifier.parent.type === 'ImportSpecifier' &&
identifier.parent.imported.name === identifier.name &&
identifier.parent.local.name === identifier.name
);
};

const isShorthandExportIdentifier = identifier => {
return (
identifier.parent.type === 'ExportSpecifier' &&
identifier.parent.exported.name === identifier.name &&
identifier.parent.local.name === identifier.name
);
};

const fixIdentifier = (fixer, replacement, sourceCode) => identifier => {
if (
isShorthandPropertyIdentifier(identifier) ||
isAssignmentPatternShorthandPropertyIdentifier(identifier)
) {
return fixer.replaceText(identifier, `${identifier.name}: ${replacement}`);
}

if (isShorthandImportIdentifier(identifier)) {
return fixer.replaceText(identifier, `${identifier.name} as ${replacement}`);
}

if (isShorthandExportIdentifier(identifier)) {
return fixer.replaceText(identifier, `${replacement} as ${identifier.name}`);
}

// `TypeParameter` default value
if (identifier.default) {
return fixer.replaceText(identifier, `${replacement} = ${sourceCode.getText(identifier.default)}`);
}

return fixer.replaceText(identifier, replacement);
};

const isDefaultOrNamespaceImportName = identifier => {
if (
identifier.parent.type === 'ImportDefaultSpecifier' &&
Expand Down Expand Up @@ -689,7 +632,7 @@ const create = context => {

problem.fix = fixer => {
return variableIdentifiers(variable)
.map(fixIdentifier(fixer, replacement, sourceCode));
.map(identifier => renameIdentifier(identifier, replacement, fixer, sourceCode));
};
}

Expand Down
11 changes: 11 additions & 0 deletions rules/utils/is-assignment-pattern-shorthand-property-identifier.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'use strict';

const isSameNode = require('./is-same-node');

module.exports = identifier =>
identifier.parent.type === 'AssignmentPattern' &&
identifier.parent.left === identifier &&
identifier.parent.parent.type === 'Property' &&
isSameNode(identifier, identifier.parent.parent.key) &&
identifier.parent.parent.value === identifier.parent &&
identifier.parent.parent.shorthand;
6 changes: 6 additions & 0 deletions rules/utils/is-shorthand-export-identifier.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
'use strict';

module.exports = identifier =>
identifier.parent.type === 'ExportSpecifier' &&
identifier.parent.exported.name === identifier.name &&
identifier.parent.local.name === identifier.name;
6 changes: 6 additions & 0 deletions rules/utils/is-shorthand-import-identifier.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
'use strict';

module.exports = identifier =>
identifier.parent.type === 'ImportSpecifier' &&
identifier.parent.imported.name === identifier.name &&
identifier.parent.local.name === identifier.name;
8 changes: 8 additions & 0 deletions rules/utils/is-shorthand-property-identifier.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use strict';

const isSameNode = require('./is-same-node');

module.exports = identifier =>
identifier.parent.type === 'Property' &&
identifier.parent.shorthand &&
isSameNode(identifier, identifier.parent.key);
37 changes: 37 additions & 0 deletions rules/utils/rename-identifier.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use strict';

const isShorthandPropertyIdentifier = require('./is-shorthand-property-identifier');
const isAssignmentPatternShorthandPropertyIdentifier = require('./is-assignment-pattern-shorthand-property-identifier');
const isShorthandImportIdentifier = require('./is-shorthand-import-identifier');
const isShorthandExportIdentifier = require('./is-shorthand-export-identifier');

function renameIdentifier(identifier, name, fixer, sourceCode) {
if (
isShorthandPropertyIdentifier(identifier) ||
isAssignmentPatternShorthandPropertyIdentifier(identifier)
) {
return fixer.replaceText(identifier, `${identifier.name}: ${name}`);
}

if (isShorthandImportIdentifier(identifier)) {
return fixer.replaceText(identifier, `${identifier.name} as ${name}`);
}

if (isShorthandExportIdentifier(identifier)) {
return fixer.replaceText(identifier, `${name} as ${identifier.name}`);
}

// `TypeParameter` default value
if (identifier.default) {
return fixer.replaceText(identifier, `${name} = ${sourceCode.getText(identifier.default)}`);
}

// `typeAnnotation`
if (identifier.typeAnnotation) {
return fixer.replaceText(identifier, `${name}${sourceCode.getText(identifier.typeAnnotation)}`);
}

return fixer.replaceText(identifier, name);
}

module.exports = renameIdentifier;
48 changes: 48 additions & 0 deletions test/prevent-abbreviations.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ const babelRuleTester = avaRuleTester(test, {
parser: require.resolve('babel-eslint')
});

const typescriptRuleTester = avaRuleTester(test, {
parser: require.resolve('@typescript-eslint/parser')
});

const noFixingTestCase = test => ({...test, output: test.code});

const createErrors = message => {
Expand Down Expand Up @@ -1641,6 +1645,31 @@ babelRuleTester.run('prevent-abbreviations', rule, {
errors: createErrors()
},

// #347
{
code: outdent`
function onKeyDown(e: KeyboardEvent) {
if (e.keyCode) {}
}
`,
output: outdent`
function onKeyDown(event: KeyboardEvent) {
if (event.keyCode) {}
}
`,
options: [
{
extendDefaultReplacements: false,
replacements: {
e: {
event: true
}
}
}
],
errors: createErrors()
},

// https://github.com/facebook/relay/blob/597d2a17aa29d401830407b6814a5f8d148f632d/packages/relay-experimental/EntryPointTypes.flow.js#L138
{
code: outdent`
Expand Down Expand Up @@ -1673,3 +1702,22 @@ babelRuleTester.run('prevent-abbreviations', rule, {
})
]
});

typescriptRuleTester.run('prevent-abbreviations', rule, {
valid: [],
invalid: [
// Types
...[
'declare const prop: string;',
'declare const prop: string;',
'declare var prop: number;',
'declare let prop: any;',
'declare class prop {}',
'const prop: SomeThing<boolean> = func();'
].map(code => ({
code,
output: code.replace('prop', 'property'),
errors: createErrors()
}))
]
});