Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat(eslint-plugin)!: [array-type] add "default", "readonly" options #654

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions packages/eslint-plugin/docs/rules/array-type.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,26 @@ This rule aims to standardise usage of array types within your codebase.

## Options

This rule accepts one option - a single string
```ts
type ArrayOption = 'array' | 'generic' | 'array-simple';
type Options = {
default: ArrayOption;
readonly?: ArrayOption;
};

const defaultOptions: Options = {
default: 'array',
};
```

The rule accepts an options object with the following properties:

- `default` - sets the array type expected for mutable cases.
- `readonly` - sets the array type expected for readonly arrays. If this is omitted, then the value for `default` will be used.

- `"array"` enforces use of `T[]` for all types `T`.
- `"generic"` enforces use of `Array<T>` for all types `T`.
- `"array-simple"` enforces use of `T[]` if `T` is a simple type.
Each property can be set to one of three strings: `'array' | 'generic' | 'array-simple'`.

Without providing an option, by default the rule will enforce `"array"`.
The default config will enforce that all mutable and readonly arrays use the `'array'` syntax.

### `"array"`

Expand Down
87 changes: 68 additions & 19 deletions packages/eslint-plugin/src/rules/array-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,20 @@ function typeNeedsParentheses(node: TSESTree.Node): boolean {
}

export type OptionString = 'array' | 'generic' | 'array-simple';
type Options = [OptionString];
type Options = [
{
default: OptionString;
readonly?: OptionString;
}
];
type MessageIds =
| 'errorStringGeneric'
| 'errorStringGenericSimple'
| 'errorStringArray'
| 'errorStringArraySimple';

const arrayOption = { enum: ['array', 'generic', 'array-simple'] };

export default util.createRule<Options, MessageIds>({
name: 'array-type',
meta: {
Expand All @@ -102,14 +109,32 @@ export default util.createRule<Options, MessageIds>({
},
schema: [
{
enum: ['array', 'generic', 'array-simple'],
type: 'object',
properties: {
default: arrayOption,
readonly: arrayOption,
},
},
],
},
defaultOptions: ['array'],
create(context, [option]) {
defaultOptions: [
{
default: 'array',
},
],
create(context, [options]) {
const sourceCode = context.getSourceCode();

const defaultOption = options.default;
const readonlyOption = options.readonly || defaultOption;

const isArraySimpleOption =
defaultOption === 'array-simple' && readonlyOption === 'array-simple';
const isArrayOption =
defaultOption === 'array' && readonlyOption === 'array';
const isGenericOption =
defaultOption === 'generic' && readonlyOption === 'generic';

/**
* Check if whitespace is needed before this node
* @param node the node to be evaluated.
Expand Down Expand Up @@ -143,22 +168,36 @@ export default util.createRule<Options, MessageIds>({
}

return {
TSArrayType(node) {
TSArrayType(node: TSESTree.TSArrayType) {
if (
option === 'array' ||
(option === 'array-simple' && isSimpleType(node.elementType))
isArrayOption ||
(isArraySimpleOption && isSimpleType(node.elementType))
) {
return;
}
const messageId =
option === 'generic'
? 'errorStringGeneric'
: 'errorStringGenericSimple';

const isReadonly =
node.parent &&
node.parent.type === AST_NODE_TYPES.TSTypeOperator &&
node.parent.operator === 'readonly';

const isReadonlyGeneric =
readonlyOption === 'generic' && defaultOption !== 'generic';

const isReadonlyArray =
readonlyOption !== 'generic' && defaultOption === 'generic';

if (
(isReadonlyGeneric && !isReadonly) ||
(isReadonlyArray && isReadonly)
) {
return;
}

const messageId =
defaultOption === 'generic'
? 'errorStringGeneric'
: 'errorStringGenericSimple';
const typeOpNode = isReadonly ? node.parent! : null;

context.report({
Expand Down Expand Up @@ -201,23 +240,32 @@ export default util.createRule<Options, MessageIds>({
},
});
},

TSTypeReference(node: TSESTree.TSTypeReference) {
if (
option === 'generic' ||
isGenericOption ||
node.typeName.type !== AST_NODE_TYPES.Identifier
) {
return;
}
if (!['Array', 'ReadonlyArray'].includes(node.typeName.name)) {

const isReadonlyArrayType = node.typeName.name === 'ReadonlyArray';
const isArrayType = node.typeName.name === 'Array';

if (
!(isArrayType || isReadonlyArrayType) ||
(readonlyOption === 'generic' && isReadonlyArrayType) ||
(defaultOption === 'generic' && !isReadonlyArrayType)
) {
return;
}

const messageId =
option === 'array' ? 'errorStringArray' : 'errorStringArraySimple';
const isReadonly = node.typeName.name === 'ReadonlyArray';
const readonlyPrefix = isReadonly ? 'readonly ' : '';

const readonlyPrefix = isReadonlyArrayType ? 'readonly ' : '';
const typeParams = node.typeParameters && node.typeParameters.params;
const messageId =
defaultOption === 'array'
? 'errorStringArray'
: 'errorStringArraySimple';

if (!typeParams || typeParams.length === 0) {
// Create an 'any' array
Expand All @@ -231,12 +279,13 @@ export default util.createRule<Options, MessageIds>({
return fixer.replaceText(node, `${readonlyPrefix}any[]`);
},
});

return;
}

if (
typeParams.length !== 1 ||
(option === 'array-simple' && !isSimpleType(typeParams[0]))
(defaultOption === 'array-simple' && !isSimpleType(typeParams[0]))
) {
return;
}
Expand Down
Loading