Skip to content

Commit

Permalink
fix: proper replacements on this.ux
Browse files Browse the repository at this point in the history
  • Loading branch information
mshanemc committed Dec 7, 2022
1 parent 5e27211 commit 1a134ab
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 10 deletions.
21 changes: 16 additions & 5 deletions src/rules/migration/no-this-ux.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { ESLintUtils } from '@typescript-eslint/utils';
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { ancestorsContainsSfCommand, isInCommandDirectory } from '../../shared/commands';
import { MembersExpressionIsThisDotFoo } from '../../shared/expressions';
import { MemberExpressionContainsMemberExpressionThisDotFoo } from '../../shared/expressions';

const spinnerMigration = new Map([
['startSpinner', 'this.spinner.start'],
Expand All @@ -33,10 +33,18 @@ export const noThisUx = ESLintUtils.RuleCreator.withoutDocs({
return isInCommandDirectory(context)
? {
MemberExpression(node): void {
if (MembersExpressionIsThisDotFoo(node, 'ux') && ancestorsContainsSfCommand(context.getAncestors())) {
if (
MemberExpressionContainsMemberExpressionThisDotFoo(node, 'ux') &&
ancestorsContainsSfCommand(context.getAncestors())
) {
// eslint-disable-next-line no-console
// console.log(`property type is ${node.property.type}`);
// if (node.property.type === AST_NODE_TYPES.Identifier) {
// // eslint-disable-next-line no-console
// console.log(`property name is ${node.property.name}`);
// }
// spinner cases
if (node.property.type === AST_NODE_TYPES.Identifier && spinnerMigration.has(node.property.name)) {
// all other this.ux cases
const toRemove = node;
const original = node.property.name;
context.report({
Expand All @@ -49,6 +57,9 @@ export const noThisUx = ESLintUtils.RuleCreator.withoutDocs({
} else if (node.property.type === AST_NODE_TYPES.Identifier && node.property.name === 'logJson') {
// this.ux.logJson => this.styledJson
const toRemove = node;
// eslint-disable-next-line no-console
console.log(`I want to remove ${context.getSourceCode().getText(toRemove)} and replace it with 'this'`);

context.report({
node,
messageId: 'message',
Expand All @@ -58,12 +69,12 @@ export const noThisUx = ESLintUtils.RuleCreator.withoutDocs({
});
} else {
// all other this.ux cases
const toRemove = node.object;
const toRemove = node;
context.report({
node,
messageId: 'message',
fix: (fixer) => {
return fixer.replaceText(toRemove, 'this');
return fixer.replaceText(toRemove, `this.${context.getSourceCode().getText(node.property)}`);
},
});
}
Expand Down
4 changes: 2 additions & 2 deletions src/rules/migration/noThisFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { ESLintUtils } from '@typescript-eslint/utils';
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { ancestorsContainsSfCommand, getRunMethod, getSfCommand, isInCommandDirectory } from '../../shared/commands';
import { MembersExpressionIsThisDotFoo } from '../../shared/expressions';
import { MemberExpressionIsThisDotFoo } from '../../shared/expressions';

export const noThisFlags = ESLintUtils.RuleCreator.withoutDocs({
meta: {
Expand All @@ -31,7 +31,7 @@ export const noThisFlags = ESLintUtils.RuleCreator.withoutDocs({
return isInCommandDirectory(context)
? {
MemberExpression(node): void {
if (MembersExpressionIsThisDotFoo(node, 'flags') && ancestorsContainsSfCommand(context.getAncestors())) {
if (MemberExpressionIsThisDotFoo(node, 'flags') && ancestorsContainsSfCommand(context.getAncestors())) {
// it's ok if there's a this.org on the class...
const classAbove = getSfCommand(context.getAncestors());
const runMethod = getRunMethod(classAbove);
Expand Down
4 changes: 2 additions & 2 deletions src/rules/migration/noThisOrg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { ESLintUtils } from '@typescript-eslint/utils';
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { ancestorsContainsSfCommand, getRunMethod, getSfCommand, isInCommandDirectory } from '../../shared/commands';
import { MembersExpressionIsThisDotFoo } from '../../shared/expressions';
import { MemberExpressionIsThisDotFoo } from '../../shared/expressions';

export const noThisOrg = ESLintUtils.RuleCreator.withoutDocs({
meta: {
Expand All @@ -31,7 +31,7 @@ export const noThisOrg = ESLintUtils.RuleCreator.withoutDocs({
return isInCommandDirectory(context)
? {
MemberExpression(node): void {
if (MembersExpressionIsThisDotFoo(node, 'org') && ancestorsContainsSfCommand(context.getAncestors())) {
if (MemberExpressionIsThisDotFoo(node, 'org') && ancestorsContainsSfCommand(context.getAncestors())) {
// it's ok if there's a this.org on the class...
const classAbove = getSfCommand(context.getAncestors());
const runMethod = getRunMethod(classAbove);
Expand Down
9 changes: 8 additions & 1 deletion src/shared/expressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@
*/
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';

export const MembersExpressionIsThisDotFoo = (node: TSESTree.Node, name: string): boolean =>
export const MemberExpressionIsThisDotFoo = (node: TSESTree.Node, name: string): boolean =>
node.type === AST_NODE_TYPES.MemberExpression &&
node.object?.type === AST_NODE_TYPES.ThisExpression &&
node.property?.type === AST_NODE_TYPES.Identifier &&
node.property?.name === name;

export const MemberExpressionContainsMemberExpressionThisDotFoo = (node: TSESTree.Node, name: string): boolean =>
node.type === AST_NODE_TYPES.MemberExpression &&
node.object?.type === AST_NODE_TYPES.MemberExpression &&
node.object?.object.type === AST_NODE_TYPES.ThisExpression &&
node.object?.property?.type === AST_NODE_TYPES.Identifier &&
node.object?.property?.name === name;
101 changes: 101 additions & 0 deletions test/rules/migration/noThisUx.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright (c) 2020, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import path from 'path';
import { ESLintUtils } from '@typescript-eslint/utils';
import { noThisUx } from '../../../src/rules/migration/no-this-ux';

const ruleTester = new ESLintUtils.RuleTester({
parser: '@typescript-eslint/parser',
});

ruleTester.run('noThisUx', noThisUx, {
valid: [
{
name: 'Custom Type',
filename: path.normalize('src/commands/foo.ts'),
code: `
export default class EnvCreateScratch extends SfCommand<ScratchCreateResponse> {
public async run(): Promise<ScratchCreateResponse> {
this.log('hi')
}
}
`,
},
{
name: 'Not in commands dir',
filename: path.normalize('foo.ts'),
code: `
export default class EnvCreateScratch extends SfCommand<string> {
public async run(): Promise<string> {
this.ux.log('hi')
}
}
`,
},
],
invalid: [
{
name: 'basic this.ux.something',
filename: path.normalize('src/commands/foo.ts'),
errors: [{ messageId: 'message' }, { messageId: 'message' }],
code: `
export default class EnvCreateScratch extends SfCommand<Foo> {
public async run(): Promise<Bar> {
this.ux.log('ui');
this.ux.table(stuff)
}
}
`,
output: `
export default class EnvCreateScratch extends SfCommand<Foo> {
public async run(): Promise<Bar> {
this.log('ui');
this.table(stuff)
}
}
`,
},
{
name: 'spinners',
filename: path.normalize('src/commands/foo.ts'),
errors: [{ messageId: 'spinner' }, { messageId: 'spinner' }],
code: `
export default class EnvCreateScratch extends SfCommand<Bar> {
public async run(): Promise<Bar> {
this.ux.startSpinner('go');
this.ux.stopSpinner('done!');
}
}`,
output: `
export default class EnvCreateScratch extends SfCommand<Bar> {
public async run(): Promise<Bar> {
this.spinner.start('go');
this.spinner.stop('done!');
}
}`,
},
{
name: 'styled json',
filename: path.normalize('src/commands/foo.ts'),
errors: [{ messageId: 'message' }],
code: `
export default class EnvCreateScratch extends SfCommand<Bar> {
public async run(): Promise<Bar> {
this.ux.logJson('blah');
}
}`,
output: `
export default class EnvCreateScratch extends SfCommand<Bar> {
public async run(): Promise<Bar> {
this.styledJSON('blah');
}
}`,
},
],
});

0 comments on commit 1a134ab

Please sign in to comment.