Skip to content

Commit

Permalink
feat: strict-false checks, docs catchup
Browse files Browse the repository at this point in the history
  • Loading branch information
mshanemc committed Jan 23, 2023
1 parent 526e318 commit 3c56c59
Show file tree
Hide file tree
Showing 8 changed files with 242 additions and 33 deletions.
71 changes: 38 additions & 33 deletions README.md

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions docs/rules/encourage-alias-deprecation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Commands and flags aliases probably want to deprecate their old names to provide more warnings to users (`sf-plugin/encourage-alias-deprecation`)

⚠️ This rule _warns_ in the ✈️ `migration` config.

🔧💡 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).

<!-- end auto-generated rule header -->
7 changes: 7 additions & 0 deletions docs/rules/no-args-parse-without-strict-false.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# If you parse args/argv, the class should have strict set to false (`sf-plugin/no-args-parse-without-strict-false`)

💼 This rule is enabled in the following configs: ✈️ `migration`, ✅ `recommended`.

🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).

<!-- end auto-generated rule header -->
7 changes: 7 additions & 0 deletions docs/rules/no-unnecessary-aliases.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Mark when an alias is unnecessary because its only an order permutation, not really a different name (`sf-plugin/no-unnecessary-aliases`)

💼 This rule is enabled in the following configs: ✈️ `migration`, ✅ `recommended`.

🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).

<!-- end auto-generated rule header -->
7 changes: 7 additions & 0 deletions docs/rules/no-unnecessary-properties.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Boolean properties are false by default, so they should not be set to false (`sf-plugin/no-unnecessary-properties`)

⚠️ This rule _warns_ in the following configs: ✈️ `migration`, ✅ `recommended`.

🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).

<!-- end auto-generated rule header -->
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { noUsernameProperties } from './rules/migration/no-username-properties';
import { noUnnecessaryProperties } from './rules/no-unnecessary-properties';
import { encourageAliasDeprecation } from './rules/migration/encourage-alias-deprecation';
import { noUnnecessaryAliases } from './rules/no-unnecessary-aliases';
import { noArgsParseWithoutStrictFalse } from './rules/no-args-parse-without-strict-false';

const recommended = {
plugins: ['sf-plugin'],
Expand All @@ -63,6 +64,7 @@ const recommended = {
'sf-plugin/no-split-examples': 'error',
'sf-plugin/no-unnecessary-properties': 'warn',
'sf-plugin/no-unnecessary-aliases': 'error',
'sf-plugin/no-args-parse-without-strict-false': 'error',
},
};
export = {
Expand Down Expand Up @@ -124,5 +126,6 @@ export = {
'no-unnecessary-properties': noUnnecessaryProperties,
'encourage-alias-deprecation': encourageAliasDeprecation,
'no-unnecessary-aliases': noUnnecessaryAliases,
'no-args-parse-without-strict-false': noArgsParseWithoutStrictFalse,
},
};
79 changes: 79 additions & 0 deletions src/rules/no-args-parse-without-strict-false.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* 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 { AST_NODE_TYPES, ESLintUtils, ASTUtils } from '@typescript-eslint/utils';
import { isInCommandDirectory, getSfCommand } from '../shared/commands';

export const noArgsParseWithoutStrictFalse = ESLintUtils.RuleCreator.withoutDocs({
meta: {
docs: {
description: 'If you parse args/argv, the class should have strict set to false',
recommended: 'error',
},
messages: {
summary: 'If you parse args/argv, the class should have strict set to false',
},
type: 'problem',
schema: [],
fixable: 'code',
},
defaultOptions: [],
create(context) {
return isInCommandDirectory(context)
? {
// eslint-disable-next-line complexity
VariableDeclarator(node): void {
if (
ASTUtils.isAwaitExpression(node.init) &&
node.init.argument.type === AST_NODE_TYPES.CallExpression &&
node.init.argument.callee.type === AST_NODE_TYPES.MemberExpression &&
node.init.argument.callee.object.type === AST_NODE_TYPES.ThisExpression &&
node.init.argument.callee.property.type === AST_NODE_TYPES.Identifier &&
node.init.argument.callee.property.name === 'parse' &&
node.id.type === AST_NODE_TYPES.ObjectPattern &&
node.id.properties.some(
(p) =>
p.type === AST_NODE_TYPES.Property &&
p.key.type === AST_NODE_TYPES.Identifier &&
(p.key.name === 'args' || p.key.name === 'argv')
)
) {
// Verify that the class has strict = false
const ancestors = context.getAncestors();
const sfCommand = getSfCommand(ancestors);
const strictProperty = sfCommand.body.body.find(
(p) =>
p.type === AST_NODE_TYPES.PropertyDefinition &&
ASTUtils.isIdentifier(p.key) &&
p.key.name === 'strict'
);
if (
strictProperty?.type === AST_NODE_TYPES.PropertyDefinition &&
strictProperty.value.type === AST_NODE_TYPES.Literal &&
strictProperty.value.value === true
) {
context.report({
node: strictProperty,
messageId: 'summary',
fix: (fixer) => {
return fixer.replaceText(strictProperty.value, 'false');
},
});
} else if (!strictProperty) {
context.report({
node: node.id,
messageId: 'summary',
fix: (fixer) => {
return fixer.insertTextBefore(sfCommand.body.body[0], 'public static readonly strict = false;');
},
});
}
}
},
}
: {};
},
});
94 changes: 94 additions & 0 deletions test/rules/no-args-parse-without-strict-false.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* 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 { noArgsParseWithoutStrictFalse } from '../../src/rules/no-args-parse-without-strict-false';

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

ruleTester.run('noArgsParseWithoutStrictFalse', noArgsParseWithoutStrictFalse, {
valid: [
{
name: 'Parses as expected',
filename: path.normalize('src/commands/foo.ts'),
code: `
export default class EnvCreateScratch extends SfCommand<ScratchCreateResponse> {
public static readonly strict = false;
public async run(): Promise<ScratchCreateResponse> {
const {flags, args, argv} = await this.parse(EnvCreateScratch);
}
}
`,
},
{
name: 'No args parsed',
filename: path.normalize('src/commands/foo.ts'),
code: `
export default class EnvCreateScratch extends SfCommand<ScratchCreateResponse> {
public async run(): Promise<ScratchCreateResponse> {
const {flags} = await this.parse(EnvCreateScratch);
}
}
`,
},
{
name: 'Not in commands dir',
filename: path.normalize('foo.ts'),
code: `
export default class EnvCreateScratch extends SfCommand<ScratchCreateResponse> {
public async run(): Promise<ScratchCreateResponse> {
const {flags, args, argv} = await this.parse(EnvCreateScratch);
}
}
`,
},
],
invalid: [
{
name: 'parses args/var without strict=false',
filename: path.normalize('src/commands/foo.ts'),
errors: [{ messageId: 'summary' }],
code: `
export default class EnvCreateScratch extends SfCommand<ScratchCreateResponse> {
public async run(): Promise<ScratchCreateResponse> {
const {flags, args, argv} = await this.parse(EnvCreateScratch);
}
}
`,
output: `
export default class EnvCreateScratch extends SfCommand<ScratchCreateResponse> {
public static readonly strict = false;public async run(): Promise<ScratchCreateResponse> {
const {flags, args, argv} = await this.parse(EnvCreateScratch);
}
}
`,
},
{
name: 'parses args/var and strict=true',
filename: path.normalize('src/commands/foo.ts'),
errors: [{ messageId: 'summary' }],
code: `
export default class EnvCreateScratch extends SfCommand<ScratchCreateResponse> {
public static readonly strict = true;
public async run(): Promise<ScratchCreateResponse> {
const {flags, args, argv} = await this.parse(EnvCreateScratch);
}
}
`,
output: `
export default class EnvCreateScratch extends SfCommand<ScratchCreateResponse> {
public static readonly strict = false;
public async run(): Promise<ScratchCreateResponse> {
const {flags, args, argv} = await this.parse(EnvCreateScratch);
}
}
`,
},
],
});

0 comments on commit 3c56c59

Please sign in to comment.