Skip to content

Commit

Permalink
feat(prefer-immutable-types): allow for changing suggestion messages
Browse files Browse the repository at this point in the history
  • Loading branch information
RebeccaStevens committed May 26, 2024
1 parent b34253f commit b3dac20
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 45 deletions.
17 changes: 14 additions & 3 deletions docs/rules/prefer-immutable-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,15 @@ type Options = {
};

suggestions?: {
ReadonlyShallow?: Array<Array<{ pattern: string; replace: string }>>;
ReadonlyDeep?: Array<Array<{ pattern: string; replace: string }>>;
Immutable?: Array<Array<{ pattern: string; replace: string }>>;
ReadonlyShallow?: Array<
Array<{ pattern: string; replace: string; message?: string }>
>;
ReadonlyDeep?: Array<
Array<{ pattern: string; replace: string; message?: string }>
>;
Immutable?: Array<
Array<{ pattern: string; replace: string; message?: string }>
>;
};

overrides?: Array<{
Expand Down Expand Up @@ -297,14 +303,19 @@ const defaults = {
pattern:
"^([_$a-zA-Z\\xA0-\\uFFFF][_$a-zA-Z0-9\\xA0-\\uFFFF]*\\[\\])$",
replace: "readonly $1",
message: "Prepend with readonly.",
},
{
pattern: "^(Array|Map|Set)<(.+)>$",
replace: "Readonly$1<$2>",
message: "Use Readonly$1 instead of $1.",
},
],
[
{
pattern: "^(.+)$",
replace: "Readonly<$1>",
message: "Surround with Readonly.",
},
],
],
Expand Down
76 changes: 53 additions & 23 deletions src/rules/prefer-immutable-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ type FixerConfigRaw = {
replace: string;
};

type SuggestionsConfigRaw = Array<FixerConfigRaw & { message?: string }>;

type FixerConfigRawMap = Partial<
Record<
"ReadonlyShallow" | "ReadonlyDeep" | "Immutable",
Expand All @@ -103,7 +105,7 @@ type FixerConfigRawMap = Partial<
type SuggestionConfigRawMap = Partial<
Record<
"ReadonlyShallow" | "ReadonlyDeep" | "Immutable",
FixerConfigRaw[][] | undefined
SuggestionsConfigRaw[] | undefined
>
>;

Expand All @@ -112,7 +114,7 @@ type FixerConfig = {
replace: string;
};

type SuggestionsConfig = FixerConfig[];
type SuggestionsConfig = Array<FixerConfig & { message?: string }>;

/**
* The options this rule can take.
Expand Down Expand Up @@ -216,6 +218,7 @@ const suggestionsSchema: JSONSchema4 = {
properties: {
pattern: { type: "string" },
replace: { type: "string" },
message: { type: "string" },
},
additionalProperties: false,
},
Expand Down Expand Up @@ -286,14 +289,19 @@ const defaultOptions: RawOptions = [
pattern:
"^([_$a-zA-Z\\xA0-\\uFFFF][_$a-zA-Z0-9\\xA0-\\uFFFF]*\\[\\])$",
replace: "readonly $1",
message: "Prepend with readonly.",
},
{
pattern: "^(Array|Map|Set)<(.+)>$",
replace: "Readonly$1<$2>",
message: "Use Readonly$1 instead of $1.",
},
],
[
{
pattern: "^(.+)$",
replace: "Readonly<$1>",
message: "Surround with Readonly.",
},
],
],
Expand All @@ -314,6 +322,7 @@ const errorMessages = {
propertyImmutability:
'Property should have an immutability of at least "{{ expected }}" (actual: "{{ actual }}").',
propertyModifier: "Property should have a readonly modifier.",
userDefined: "{{ message }}",
} as const;

/**
Expand Down Expand Up @@ -342,7 +351,7 @@ type Descriptor = RuleResult<

type AllFixers = {
fix: ReportFixFunction | null;
suggestionFixers: ReportFixFunction[] | null;
suggestionFixers: Array<{ fix: ReportFixFunction; message: string }> | null;
};

/**
Expand Down Expand Up @@ -394,14 +403,27 @@ function getConfiguredSuggestionFixers(
suggestionsConfigs: ReadonlyArray<SuggestionsConfig>,
) {
return suggestionsConfigs
.map((configs): NonNullable<Descriptor["fix"]> | null => {
const config = configs.find((c) => c.pattern.test(text));
if (config === undefined) {
return null;
}
return (fixer) =>
fixer.replaceText(node, text.replace(config.pattern, config.replace));
})
.map(
(
configs,
): { fix: NonNullable<Descriptor["fix"]>; message: string } | null => {
const config = configs.find((c) => c.pattern.test(text));
if (config === undefined) {
return null;
}
return {
fix: (fixer) =>
fixer.replaceText(
node,
text.replace(config.pattern, config.replace),
),
message:
config.message === undefined
? `Replace with: ${text.replace(config.pattern, config.replace)}`
: text.replace(config.pattern, config.message),
};
},
)
.filter(isDefined);
}

Expand Down Expand Up @@ -596,9 +618,11 @@ function getParameterTypeViolations(
data,
fix,
suggest:
suggestionFixers?.map((fix) => ({
messageId,
data,
suggestionFixers?.map(({ fix, message }) => ({

Check warning on line 621 in src/rules/prefer-immutable-types.ts

View workflow job for this annotation

GitHub Actions / lint_js

'fix' is already declared in the upper scope on line 599 column 15
messageId: "userDefined",
data: {
message,
},
fix,
})) ?? null,
};
Expand Down Expand Up @@ -722,9 +746,11 @@ function getReturnTypeViolations(
data,
fix,
suggest:
suggestionFixers?.map((fix) => ({
messageId,
data,
suggestionFixers?.map(({ fix, message }) => ({

Check warning on line 749 in src/rules/prefer-immutable-types.ts

View workflow job for this annotation

GitHub Actions / lint_js

'fix' is already declared in the upper scope on line 729 column 15
messageId: "userDefined",
data: {
message,
},
fix,
})) ?? null,
},
Expand Down Expand Up @@ -795,9 +821,11 @@ function getReturnTypeViolations(
data,
fix,
suggest:
suggestionFixers?.map((fix) => ({
messageId,
data,
suggestionFixers?.map(({ fix, message }) => ({

Check warning on line 824 in src/rules/prefer-immutable-types.ts

View workflow job for this annotation

GitHub Actions / lint_js

'fix' is already declared in the upper scope on line 801 column 11
messageId: "userDefined",
data: {
message,
},
fix,
})) ?? null,
},
Expand Down Expand Up @@ -995,9 +1023,11 @@ function checkVariable(
data,
fix,
suggest:
suggestionFixers?.map((fix) => ({
messageId,
data,
suggestionFixers?.map(({ fix, message }) => ({

Check warning on line 1026 in src/rules/prefer-immutable-types.ts

View workflow job for this annotation

GitHub Actions / lint_js

'fix' is already declared in the upper scope on line 1014 column 38
messageId: "userDefined",
data: {
message,
},
fix,
})) ?? null,
};
Expand Down
46 changes: 34 additions & 12 deletions tests/rules/prefer-immutable-types/ts/parameters/invalid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ const tests: Array<
column: 14,
suggestions: [
{
messageId: "parameter",
messageId: "userDefined",
data: { message: "Surround with Readonly." },
output:
"function foo(arg1: Readonly<{ foo: string }>, arg2: { foo: number }) {}",
},
Expand All @@ -59,7 +60,8 @@ const tests: Array<
column: 37,
suggestions: [
{
messageId: "parameter",
messageId: "userDefined",
data: { message: "Surround with Readonly." },
output:
"function foo(arg1: { foo: string }, arg2: Readonly<{ foo: number }>) {}",
},
Expand Down Expand Up @@ -179,7 +181,8 @@ const tests: Array<
column: 5,
suggestions: [
{
messageId: "propertyModifier",
messageId: "userDefined",
data: { message: "Prepend with readonly." },
output: dedent`
class Klass {
constructor (
Expand All @@ -199,7 +202,8 @@ const tests: Array<
column: 5,
suggestions: [
{
messageId: "propertyModifier",
messageId: "userDefined",
data: { message: "Prepend with readonly." },
output: dedent`
class Klass {
constructor (
Expand All @@ -219,7 +223,8 @@ const tests: Array<
column: 5,
suggestions: [
{
messageId: "propertyModifier",
messageId: "userDefined",
data: { message: "Prepend with readonly." },
output: dedent`
class Klass {
constructor (
Expand All @@ -245,7 +250,8 @@ const tests: Array<
column: 46,
suggestions: [
{
messageId: "parameter",
messageId: "userDefined",
data: { message: "Surround with Readonly." },
output:
"function foo(arg0: { foo: string | number }, arg1: Readonly<{ foo: string | number }>): arg0 is { foo: number } {}",
},
Expand Down Expand Up @@ -295,7 +301,8 @@ const tests: Array<
column: 14,
suggestions: [
{
messageId: "parameter",
messageId: "userDefined",
data: { message: "Replace with: ReadonlyDeep<{ foo: string }>" },
output: "function foo(arg1: ReadonlyDeep<{ foo: string }>) {}",
},
],
Expand Down Expand Up @@ -329,7 +336,10 @@ const tests: Array<
column: 14,
suggestions: [
{
messageId: "parameter",
messageId: "userDefined",
data: {
message: "Replace with: ReadonlyDeep<{ foo: { bar: string } }>",
},
output:
"function foo(arg1: ReadonlyDeep<{ foo: { bar: string } }>) {}",
},
Expand Down Expand Up @@ -357,7 +367,10 @@ const tests: Array<
column: 14,
suggestions: [
{
messageId: "parameter",
messageId: "userDefined",
data: {
message: "Use ReadonlyArray instead of Array.",
},
output: dedent`
function foo(arg: ReadonlyArray<string>) {}
function foo(arg: string[]) {}
Expand All @@ -378,7 +391,10 @@ const tests: Array<
column: 14,
suggestions: [
{
messageId: "parameter",
messageId: "userDefined",
data: {
message: "Prepend with readonly.",
},
output: dedent`
function foo(arg: Array<string>) {}
function foo(arg: readonly string[]) {}
Expand All @@ -399,7 +415,10 @@ const tests: Array<
column: 14,
suggestions: [
{
messageId: "parameter",
messageId: "userDefined",
data: {
message: "Use ReadonlySet instead of Set.",
},
output: dedent`
function foo(arg: Array<string>) {}
function foo(arg: string[]) {}
Expand All @@ -420,7 +439,10 @@ const tests: Array<
column: 14,
suggestions: [
{
messageId: "parameter",
messageId: "userDefined",
data: {
message: "Use ReadonlyMap instead of Map.",
},
output: dedent`
function foo(arg: Array<string>) {}
function foo(arg: string[]) {}
Expand Down
10 changes: 8 additions & 2 deletions tests/rules/prefer-immutable-types/ts/return-types/invalid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ const tests: Array<
column: 26,
suggestions: [
{
messageId: "returnType",
messageId: "userDefined",
data: {
message: "Surround with Readonly.",
},
output: dedent`
function foo(arg: number): Readonly<{ foo: string }>;
function foo(arg: string): Readonly<{ foo: number }>;
Expand All @@ -85,7 +88,10 @@ const tests: Array<
column: 27,
suggestions: [
{
messageId: "returnType",
messageId: "userDefined",
data: {
message: "Surround with Readonly.",
},
output: dedent`
function foo(arg: number): { foo: string };
function foo(arg: string): Readonly<{ foo: number }>;
Expand Down
Loading

0 comments on commit b3dac20

Please sign in to comment.