Skip to content

Commit

Permalink
Merge branch 'main' into issue-4418
Browse files Browse the repository at this point in the history
  • Loading branch information
bradzacher committed Jan 17, 2022
2 parents 7b36d90 + ef3147c commit 6eedf23
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 51 deletions.
8 changes: 4 additions & 4 deletions packages/eslint-plugin/src/rules/no-invalid-this.ts
Expand Up @@ -64,12 +64,12 @@ export default createRule<Options, MessageIds>({
),
);
// baseRule's work
rules.FunctionDeclaration(node);
rules.FunctionDeclaration?.(node);
},
'FunctionDeclaration:exit'(node: TSESTree.FunctionDeclaration): void {
thisIsValidStack.pop();
// baseRule's work
rules['FunctionDeclaration:exit'](node);
rules['FunctionDeclaration:exit']?.(node);
},
FunctionExpression(node: TSESTree.FunctionExpression): void {
thisIsValidStack.push(
Expand All @@ -79,12 +79,12 @@ export default createRule<Options, MessageIds>({
),
);
// baseRule's work
rules.FunctionExpression(node);
rules.FunctionExpression?.(node);
},
'FunctionExpression:exit'(node: TSESTree.FunctionExpression): void {
thisIsValidStack.pop();
// baseRule's work
rules['FunctionExpression:exit'](node);
rules['FunctionExpression:exit']?.(node);
},
ThisExpression(node: TSESTree.ThisExpression): void {
const thisIsValidHere = thisIsValidStack[thisIsValidStack.length - 1];
Expand Down
20 changes: 14 additions & 6 deletions packages/eslint-plugin/typings/eslint-rules.d.ts
Expand Up @@ -701,12 +701,20 @@ declare module 'eslint/lib/rules/no-invalid-this' {
}?,
],
{
Program(node: TSESTree.Program): void;
'Program:exit'(node: TSESTree.Program): void;
FunctionDeclaration(node: TSESTree.FunctionDeclaration): void;
'FunctionDeclaration:exit'(node: TSESTree.FunctionDeclaration): void;
FunctionExpression(node: TSESTree.FunctionExpression): void;
'FunctionExpression:exit'(node: TSESTree.FunctionExpression): void;
// for ESLint < v8.7.0
Program?: (node: TSESTree.Program) => void;
'Program:exit'?: (node: TSESTree.Program) => void;
FunctionDeclaration?: (node: TSESTree.FunctionDeclaration) => void;
'FunctionDeclaration:exit'?: (node: TSESTree.FunctionDeclaration) => void;
FunctionExpression?: (node: TSESTree.FunctionExpression) => void;
'FunctionExpression:exit'?: (node: TSESTree.FunctionExpression) => void;

// for ESLint >= v8.7.0
// We don't use it and we don't have the CodePath types, so comment out it.
// onCodePathStart?: (codePath: unknown, node: TSESTree.Node) => void
// onCodePathEnd?: (codePath: unknown, node: TSESTree.Node) => void

// Common
ThisExpression(node: TSESTree.ThisExpression): void;
}
>;
Expand Down
56 changes: 40 additions & 16 deletions packages/type-utils/src/isTypeReadonly.ts
Expand Up @@ -107,9 +107,16 @@ function isTypeReadonlyObject(
function checkIndexSignature(kind: ts.IndexKind): Readonlyness {
const indexInfo = checker.getIndexInfoOfType(type, kind);
if (indexInfo) {
return indexInfo.isReadonly
? Readonlyness.Readonly
: Readonlyness.Mutable;
if (!indexInfo.isReadonly) {
return Readonlyness.Mutable;
}

return isTypeReadonlyRecurser(
checker,
indexInfo.type,
options,
seenTypes,
);
}

return Readonlyness.UnknownType;
Expand All @@ -119,20 +126,37 @@ function isTypeReadonlyObject(
if (properties.length) {
// ensure the properties are marked as readonly
for (const property of properties) {
if (
!(
isPropertyReadonlyInType(type, property.getEscapedName(), checker) ||
(options.treatMethodsAsReadonly &&
property.valueDeclaration !== undefined &&
hasSymbol(property.valueDeclaration) &&
isSymbolFlagSet(
property.valueDeclaration.symbol,
ts.SymbolFlags.Method,
))
)
) {
return Readonlyness.Mutable;
if (options.treatMethodsAsReadonly) {
if (
property.valueDeclaration !== undefined &&
hasSymbol(property.valueDeclaration) &&
isSymbolFlagSet(
property.valueDeclaration.symbol,
ts.SymbolFlags.Method,
)
) {
continue;
}

const declarations = property.getDeclarations();
const lastDeclaration =
declarations !== undefined && declarations.length > 0
? declarations[declarations.length - 1]
: undefined;
if (
lastDeclaration !== undefined &&
hasSymbol(lastDeclaration) &&
isSymbolFlagSet(lastDeclaration.symbol, ts.SymbolFlags.Method)
) {
continue;
}
}

if (isPropertyReadonlyInType(type, property.getEscapedName(), checker)) {
continue;
}

return Readonlyness.Mutable;
}

// all properties were readonly
Expand Down
45 changes: 37 additions & 8 deletions packages/type-utils/tests/isTypeReadonly.test.ts
Expand Up @@ -110,32 +110,61 @@ describe('isTypeReadonly', () => {
});
});

describe('Union', () => {
describe('IndexSignature', () => {
describe('is readonly', () => {
const runTests = runTestIsReadonly;

it.each([
['type Test = { readonly [key: string]: string };'],
[
'type Test = Readonly<{ foo: string; bar: number; }> & Readonly<{ bar: number; }>;',
'type Test = { readonly [key: string]: { readonly foo: readonly string[]; }; };',
],
['type Test = readonly string[] | readonly number[];'],
])('handles a union of 2 fully readonly types', runTests);
])(
'handles readonly PropertySignature inside a readonly IndexSignature',
runTests,
);
});

describe('is not readonly', () => {
const runTests = runTestIsNotReadonly;

it.each([
['type Test = { foo: string; bar: number; } | { bar: number; };'],
['type Test = { [key: string]: string };'],
['type Test = { readonly [key: string]: { foo: string[]; }; };'],
])(
'handles mutable PropertySignature inside a readonly IndexSignature',
runTests,
);
});
});

describe('Conditional Types', () => {
describe('is readonly', () => {
const runTests = runTestIsReadonly;

it.each([
[
'type Test = { foo: string; bar: number; } | Readonly<{ bar: number; }>;',
'type Test<T> = T extends readonly number[] ? readonly string[] : readonly number[];',
],
])('handles conditional type that are fully readonly', runTests);

it.each([
[
'type Test = Readonly<{ foo: string; bar: number; }> | { bar: number; };',
'type Test<T> = T extends number[] ? readonly string[] : readonly number[];',
],
])('handles a union of non fully readonly types', runTests);
])('should ignore mutable conditions', runTests);
});
});

describe('is not readonly', () => {
const runTests = runTestIsNotReadonly;

it.each([
['type Test<T> = T extends number[] ? string[] : number[];'],
['type Test<T> = T extends number[] ? string[] : readonly number[];'],
['type Test<T> = T extends number[] ? readonly string[] : number[];'],
])('handles non fully readonly conditional types', runTests);
});
});

describe('treatMethodsAsReadonly', () => {
Expand Down
34 changes: 17 additions & 17 deletions yarn.lock
Expand Up @@ -1309,9 +1309,9 @@
globals "^11.1.0"

"@babel/types@*", "@babel/types@^7.0.0", "@babel/types@^7.12.7", "@babel/types@^7.15.6", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.7.tgz#4ed19d51f840ed4bd5645be6ce40775fecf03159"
integrity sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg==
version "7.16.8"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.8.tgz#0ba5da91dd71e0a4e7781a30f22770831062e3c1"
integrity sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==
dependencies:
"@babel/helper-validator-identifier" "^7.16.7"
to-fast-properties "^2.0.0"
Expand Down Expand Up @@ -6872,9 +6872,9 @@ eslint-plugin-import@^2.25.2:
tsconfig-paths "^3.12.0"

eslint-plugin-jest@^25.0.5:
version "25.3.4"
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-25.3.4.tgz#2031dfe495be1463330f8b80096ddc91f8e6387f"
integrity sha512-CCnwG71wvabmwq/qkz0HWIqBHQxw6pXB1uqt24dxqJ9WB34pVg49bL1sjXphlJHgTMWGhBjN1PicdyxDxrfP5A==
version "25.7.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz#ff4ac97520b53a96187bad9c9814e7d00de09a6a"
integrity sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==
dependencies:
"@typescript-eslint/experimental-utils" "^5.0.0"

Expand Down Expand Up @@ -7939,10 +7939,10 @@ got@^9.6.0:
to-readable-stream "^1.0.0"
url-parse-lax "^3.0.0"

graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.6:
version "4.2.8"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a"
integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==
graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
version "4.2.9"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96"
integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==

gray-matter@^4.0.3:
version "4.0.3"
Expand Down Expand Up @@ -14300,9 +14300,9 @@ ts-essentials@^2.0.3:
integrity sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==

ts-jest@^27.0.5:
version "27.1.2"
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.1.2.tgz#5991d6eb3fd8e1a8d4b8f6de3ec0a3cc567f3151"
integrity sha512-eSOiJOWq6Hhs6Khzk5wKC5sgWIXgXqOCiIl1+3lfnearu58Hj4QpE5tUhQcA3xtZrELbcvAGCsd6HB8OsaVaTA==
version "27.1.3"
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.1.3.tgz#1f723e7e74027c4da92c0ffbd73287e8af2b2957"
integrity sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA==
dependencies:
bs-logger "0.x"
fast-json-stable-stringify "2.x"
Expand Down Expand Up @@ -15021,9 +15021,9 @@ webpack-sources@^3.2.2:
integrity sha512-cp5qdmHnu5T8wRg2G3vZZHoJPN14aqQ89SyQ11NpGH5zEMDCclt49rzo+MaRazk7/UeILhAI+/sEtcM+7Fr0nw==

webpack@^5.61.0, webpack@^5.64.0:
version "5.65.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.65.0.tgz#ed2891d9145ba1f0d318e4ea4f89c3fa18e6f9be"
integrity sha512-Q5or2o6EKs7+oKmJo7LaqZaMOlDWQse9Tm5l1WAfU/ujLGN5Pb0SqGeVkN/4bpPmEqEP5RnVhiqsOtWtUVwGRw==
version "5.66.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.66.0.tgz#789bf36287f407fc92b3e2d6f978ddff1bfc2dbb"
integrity sha512-NJNtGT7IKpGzdW7Iwpn/09OXz9inIkeIQ/ibY6B+MdV1x6+uReqz/5z1L89ezWnpPDWpXF0TY5PCYKQdWVn8Vg==
dependencies:
"@types/eslint-scope" "^3.7.0"
"@types/estree" "^0.0.50"
Expand All @@ -15039,7 +15039,7 @@ webpack@^5.61.0, webpack@^5.64.0:
eslint-scope "5.1.1"
events "^3.2.0"
glob-to-regexp "^0.4.1"
graceful-fs "^4.2.4"
graceful-fs "^4.2.9"
json-parse-better-errors "^1.0.2"
loader-runner "^4.2.0"
mime-types "^2.1.27"
Expand Down

0 comments on commit 6eedf23

Please sign in to comment.