Skip to content

Commit

Permalink
feat: prevent use of h as short char
Browse files Browse the repository at this point in the history
  • Loading branch information
mshanemc committed Aug 9, 2022
1 parent 49d58f6 commit 46e2764
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 6 deletions.
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { commandSummary } from './rules/commandSummary';
import { commandExamples } from './rules/commandExamples';
import { extractMessageCommand } from './rules/extractMessageCommand';
import { jsonFlag } from './rules/jsonFlag';
import { dashH } from './rules/dash-h';

export = {
configs: {
Expand All @@ -23,6 +24,7 @@ export = {
'sf-plugin/command-summary': 'error',
'sf-plugin/command-example': 'warn',
'sf-plugin/no-duplicate-short-characters': 'error',
'sf-plugin/no-h-short-char': 'error',
'sf-plugin/flag-case': 'error',
'sf-plugin/flag-summary': 'error',
'sf-plugin/no-hardcoded-messages-flags': 'warn',
Expand All @@ -34,6 +36,7 @@ export = {
},
},
rules: {
'no-h-short-char': dashH,
'no-duplicate-short-characters': noDuplicateShortCharacters,
'flag-case': flagCasing,
'flag-summary': flagSummary,
Expand Down
49 changes: 49 additions & 0 deletions src/rules/dash-h.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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 { ESLintUtils, AST_NODE_TYPES } from '@typescript-eslint/utils';
import { ancestorsContainsSfCommand, isInCommandDirectory } from '../shared/commands';
import { flagPropertyIsNamed, isFlag } from '../shared/flags';

export const dashH = ESLintUtils.RuleCreator.withoutDocs({
meta: {
docs: {
description: 'do not allow creation of a flag with short char -h',
recommended: 'error',
},
messages: {
message: '-h is reserved for help. Choose a different short character',
},
type: 'problem',
schema: [],
},
defaultOptions: [],
create(context) {
return {
Property(node): void {
// is a flag
if (isInCommandDirectory(context) && isFlag(node) && ancestorsContainsSfCommand(context.getAncestors())) {
if (
node.value?.type === 'CallExpression' &&
node.value.arguments?.[0]?.type === 'ObjectExpression' &&
node.value.arguments[0].properties.find(
(property) =>
property.type === 'Property' &&
flagPropertyIsNamed(property, 'char') &&
property.value.type === AST_NODE_TYPES.Literal &&
property.value.value === 'h'
)
) {
context.report({
node,
messageId: 'message',
});
}
}
},
};
},
});
2 changes: 1 addition & 1 deletion src/rules/jsonFlag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/
import { ESLintUtils } from '@typescript-eslint/utils';
import { ancestorsContainsSfCommand, isInCommandDirectory } from '../shared/commands';
import { flagPropertyIsNamed, isFlag } from '../shared/flags';
import { isFlag } from '../shared/flags';

export const jsonFlag = ESLintUtils.RuleCreator.withoutDocs({
meta: {
Expand Down
8 changes: 3 additions & 5 deletions src/rules/noDuplicateShortCharacters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/
import { ESLintUtils, AST_NODE_TYPES } from '@typescript-eslint/utils';
import { ancestorsContainsSfCommand, isInCommandDirectory } from '../shared/commands';
import { isFlagsStaticProperty, resolveFlagName } from '../shared/flags';
import { isFlagsStaticProperty, resolveFlagName, flagPropertyIsNamed } from '../shared/flags';

export const noDuplicateShortCharacters = ESLintUtils.RuleCreator.withoutDocs({
meta: {
Expand Down Expand Up @@ -38,12 +38,10 @@ export const noDuplicateShortCharacters = ESLintUtils.RuleCreator.withoutDocs({
flag.type === 'Property' &&
flag.value.type === 'CallExpression' &&
flag.value.arguments?.[0]?.type === AST_NODE_TYPES.ObjectExpression &&
flag.value.arguments?.[0]?.properties.some(
(p) => p.type === 'Property' && p.key.type === AST_NODE_TYPES.Identifier && p.key.name === 'char'
)
flag.value.arguments?.[0]?.properties.some((p) => p.type === 'Property' && flagPropertyIsNamed(p, 'char'))
) {
const charNode = flag.value.arguments[0].properties.find(
(p) => p.type === 'Property' && p.key.type === AST_NODE_TYPES.Identifier && p.key.name === 'char'
(p) => p.type === 'Property' && flagPropertyIsNamed(p, 'char')
);
if (charNode.type === 'Property' && charNode.value.type === AST_NODE_TYPES.Literal) {
const char = charNode.value.raw;
Expand Down
60 changes: 60 additions & 0 deletions test/rules/dash-h.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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 { dashH } from '../../src/rules/dash-h';

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

ruleTester.run('dashH', dashH, {
valid: [
{
filename: path.normalize('src/commands/foo.ts'),
code: `
export default class EnvCreateScratch extends SfCommand<ScratchCreateResponse> {
public static flags = {
alias: Flags.string({
summary: 'foo',
char: 'a'
}),
}
}
`,
},
{
filename: path.normalize('foo.ts'),
code: `
export default class EnvCreateScratch extends SfCommand<ScratchCreateResponse> {
public static flags = {
json: Flags.boolean({
char: 'h'
}),
}
}
`,
},
],
invalid: [
{
filename: path.normalize('src/commands/foo.ts'),
errors: [{ messageId: 'message' }],
code: `
export default class EnvCreateScratch extends SfCommand<Foo> {
public static flags = {
json: Flags.boolean({
char: 'h'
}),
}
}
`,
},
],
});

0 comments on commit 46e2764

Please sign in to comment.