Skip to content

Commit

Permalink
feat: readonly properties for static class (ex: summary)
Browse files Browse the repository at this point in the history
  • Loading branch information
mshanemc committed Dec 20, 2022
1 parent 2e39635 commit 7b60766
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { getConnectionWithVersion } from './rules/getConnectionsWithVersion';
import { noOclifFlagsCommandImport } from './rules/noOclifFlagsCommandImport';
import { noBuiltinFlags } from './rules/migration/noBuiltinFlags';
import { dashO } from './rules/dash-o';
import { readOnlyProperties } from './rules/readOnlyProperties';

const recommended = {
plugins: ['sf-plugin'],
Expand All @@ -47,6 +48,7 @@ const recommended = {
'sf-plugin/json-flag': 'error',
'sf-plugin/run-matches-class-type': 'error',
'sf-plugin/no-oclif-flags-command-import': 'error',
'sf-plugin/read-only-properties': 'warning',
},
};
export = {
Expand Down Expand Up @@ -93,5 +95,6 @@ export = {
'no-oclif-flags-command-import': noOclifFlagsCommandImport,
'no-builtin-flags': noBuiltinFlags,
'dash-o': dashO,
'read-only-properties': readOnlyProperties,
},
};
50 changes: 50 additions & 0 deletions src/rules/readOnlyProperties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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 } from '@typescript-eslint/utils';
import { extendsSfCommand, isInCommandDirectory } from '../shared/commands';

const props = ['summary', 'description', 'examples', 'flags', 'requiresProject', 'hidden'];

export const readOnlyProperties = ESLintUtils.RuleCreator.withoutDocs({
meta: {
docs: {
description: 'Class-level static properties, like flags or descriptions, should be marked read-only',
recommended: 'error',
},
messages: {
message: 'The {{prop}} property should be read-only',
},
type: 'problem',
fixable: 'code',
schema: [],
},
defaultOptions: [],
create(context) {
return isInCommandDirectory(context)
? {
PropertyDefinition(node): void {
if (
!node.readonly &&
node.static &&
node.key.type === AST_NODE_TYPES.Identifier &&
props.includes(node.key.name) &&
node.parent.type === AST_NODE_TYPES.ClassBody &&
node.parent.parent.type === AST_NODE_TYPES.ClassDeclaration &&
extendsSfCommand(node.parent.parent)
) {
context.report({
node,
messageId: 'message',
data: { prop: node.key.name },
fix: (fixer) => fixer.insertTextBefore(node.key, 'readonly '),
});
}
},
}
: {};
},
});
73 changes: 73 additions & 0 deletions test/rules/readOnlyProperties.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* 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 { readOnlyProperties } from '../../src/rules/readOnlyProperties';

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

ruleTester.run('readOnlyProperties', readOnlyProperties, {
valid: [
{
name: 'correct example for a command',
code: `
export default class EnvCreateScratch extends SfCommand<ScratchCreateResponse> {
public static readonly summary = 'foo'
public static readonly examples = 'baz'
}
`,
},
{
name: 'not an sf command',
code: `
export default class EnvCreateScratch extends somethingElse<ScratchCreateResponse> {
public static description = 'bar'
}
`,
},
{
name: 'not in the commands folder',
filename: path.normalize('foo.ts'),
code: `
export default class EnvCreateScratch extends SfCommand<ScratchCreateResponse> {
public static description = 'bar'
public static summary = 'baz'
}
`,
},
],
invalid: [
{
name: 'does not have readonly',
filename: path.normalize('src/commands/foo.ts'),
errors: [
{
messageId: 'message',
data: { prop: 'description' },
},
{
messageId: 'message',
data: { prop: 'summary' },
},
],
code: `
export default class EnvCreateScratch extends SfCommand<ScratchCreateResponse> {
public static description = 'bar'
public static summary = 'baz'
}
`,
output: `
export default class EnvCreateScratch extends SfCommand<ScratchCreateResponse> {
public static readonly description = 'bar'
public static readonly summary = 'baz'
}
`,
},
],
});

0 comments on commit 7b60766

Please sign in to comment.