Skip to content

feat: add allow option for restrict-template-expressions #8556

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
Show all changes
81 commits
Select commit Hold shift + click to select a range
c035774
WIP
abrahamguo Sep 29, 2023
4a41e8f
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Feb 6, 2024
f51c879
finish logic
abrahamguo Feb 6, 2024
0116b14
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Feb 12, 2024
37cfa52
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Feb 13, 2024
b7217e7
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Feb 15, 2024
592c036
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Feb 19, 2024
fbd2f30
add doc section
abrahamguo Feb 19, 2024
4ee7087
update snapshot
abrahamguo Feb 19, 2024
035b963
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Feb 23, 2024
bf925e5
refactors and renames
abrahamguo Feb 23, 2024
f56d8e9
simplify type flag testers
abrahamguo Feb 23, 2024
8245146
rename
abrahamguo Feb 23, 2024
bf1a087
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Feb 26, 2024
a6e0c7b
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Feb 26, 2024
f4bb1e8
write tests
abrahamguo Feb 26, 2024
0a60320
simplify test
abrahamguo Feb 26, 2024
d77d075
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Feb 26, 2024
cb1f33e
ignoredtypenames
abrahamguo Feb 27, 2024
cfd521d
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Mar 16, 2024
f5396c6
restore suppression
abrahamguo Mar 16, 2024
20dc709
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Jun 6, 2024
a58a8bd
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Jun 7, 2024
fcad2cd
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Jun 8, 2024
c41785b
rename option
abrahamguo Jun 8, 2024
ca0bb6e
change option type
abrahamguo Jun 8, 2024
aba1edb
change to typematchesspecifier
abrahamguo Jun 8, 2024
b6f9be9
finish
abrahamguo Jun 8, 2024
d6a81ef
change defaults
abrahamguo Jun 9, 2024
6a0a384
add tests
abrahamguo Jun 9, 2024
ea164f5
change defaults
abrahamguo Jun 9, 2024
ecb9e27
add documentation
abrahamguo Jun 9, 2024
c03c335
removed extra quote
abrahamguo Jun 9, 2024
1b16bcb
add description
abrahamguo Jun 9, 2024
1a3b934
add language
abrahamguo Jun 9, 2024
2cb8963
fix JS error
abrahamguo Jun 9, 2024
a0dd1e7
fix types from node
abrahamguo Jun 9, 2024
dab25fe
extract repeated documentation
abrahamguo Jun 9, 2024
6551b47
update comment clarifying string array
abrahamguo Jun 9, 2024
e25e842
update import path
abrahamguo Jun 10, 2024
d964a12
update snapshot
abrahamguo Jun 10, 2024
aba6dcd
revert unnecessary formatting change
abrahamguo Jun 10, 2024
48fd991
add test for type from Node
abrahamguo Jun 10, 2024
3072622
restore comment
abrahamguo Jun 10, 2024
f9e18ad
push more into var
abrahamguo Jun 10, 2024
d3215c7
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Jun 11, 2024
aa2faf8
sync tests
abrahamguo Jun 11, 2024
98577d2
move to shared folder
abrahamguo Jun 11, 2024
899f146
add shared folder to test
abrahamguo Jun 11, 2024
5a4c9c6
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Jun 11, 2024
86cd269
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Jun 13, 2024
9049fe7
update snapshot
abrahamguo Jun 13, 2024
e7e88bc
change check for consistency
abrahamguo Jun 13, 2024
b3d052a
clarify documentation for string form
abrahamguo Jun 13, 2024
d6cb2a8
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Jul 3, 2024
03c9a67
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Jul 5, 2024
e056af8
clean up
abrahamguo Jul 5, 2024
3e58a1e
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Jul 8, 2024
3a9c50b
make docs secret, tweak tests
abrahamguo Jul 8, 2024
3c76c7f
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Jul 8, 2024
8b54864
revert
abrahamguo Jul 25, 2024
6e93bd3
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Jul 25, 2024
42d4afa
cleanup
abrahamguo Jul 26, 2024
33904bf
finish rename
abrahamguo Jul 26, 2024
f45a979
simplify tests
abrahamguo Jul 26, 2024
34c24a5
change URL to Error
abrahamguo Jul 26, 2024
53a069a
add tsconfig withdom
abrahamguo Jul 26, 2024
089809c
revert docs tsconfig change
abrahamguo Jul 27, 2024
b7ea22f
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Aug 14, 2024
712ab4b
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Aug 14, 2024
346f9f4
fix TS error
abrahamguo Aug 14, 2024
4bcf91b
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Aug 15, 2024
f9e528a
simplify docs
abrahamguo Aug 15, 2024
68fd177
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Aug 17, 2024
4a3d824
update snapshot
abrahamguo Aug 17, 2024
87854b0
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Aug 19, 2024
66a9d4c
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Sep 2, 2024
30c1121
update docs
abrahamguo Sep 2, 2024
cdfbb46
remove unused import
abrahamguo Sep 2, 2024
9842430
Merge branch 'main' of github.com:abrahamguo/typescript-eslint into r…
abrahamguo Sep 2, 2024
d8509be
simplify unit tests to only use non-DOM types
abrahamguo Sep 2, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ const msg2 = `arg = ${arg || 'not truthy'}`;

### `allowAny`

Whether to `any` typed values in template expressions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol

Whether to allow `any` typed values in template expressions.

Examples of additional **correct** code for this rule with `{ allowAny: true }`:

Expand Down Expand Up @@ -124,7 +124,7 @@ const msg1 = `arg = ${arg}`;

### `allowNever`

Whether to `never` typed values in template expressions.
Whether to allow `never` typed values in template expressions.

Examples of additional **correct** code for this rule with `{ allowNever: true }`:

Expand All @@ -135,7 +135,7 @@ const msg1 = typeof arg === 'string' ? arg : `arg = ${arg}`;

### `allowArray`

Whether to `Array` typed values in template expressions.
Whether to allow `Array` typed values in template expressions.

Examples of additional **correct** code for this rule with `{ allowArray: true }`:

Expand All @@ -144,6 +144,19 @@ const arg = ['foo', 'bar'];
const msg1 = `arg = ${arg}`;
```

### `allow`

Whether to allow additional types in template expressions.

This option takes the shared [`TypeOrValueSpecifier` format](/packages/type-utils/type-or-value-specifier).

Examples of additional **correct** code for this rule with the default option `{ allow: [{ from: 'lib', name: 'Error' }, { from: 'lib', name: 'URL' }, { from: 'lib', name: 'URLSearchParams' }] }`:

```ts showPlaygroundButton
const error = new Error();
const msg1 = `arg = ${error}`;
```

## When Not To Use It

If you're not worried about incorrectly stringifying non-string values in template literals, then you likely don't need this rule.
Expand Down
14 changes: 9 additions & 5 deletions packages/eslint-plugin/src/rules/no-floating-promises.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
OperatorPrecedence,
readonlynessOptionsDefaults,
readonlynessOptionsSchema,
typeMatchesSpecifier,
typeMatchesSomeSpecifier,
} from '../util';

type Options = [
Expand Down Expand Up @@ -238,8 +238,10 @@ export default createRule<Options, MessageId>({

const type = services.getTypeAtLocation(node.callee);

return allowForKnownSafeCalls.some(allowedType =>
typeMatchesSpecifier(type, allowedType, services.program),
return typeMatchesSomeSpecifier(
type,
allowForKnownSafeCalls,
services.program,
);
}

Expand Down Expand Up @@ -407,8 +409,10 @@ export default createRule<Options, MessageId>({

// The highest priority is to allow anything allowlisted
if (
allowForKnownSafePromises.some(allowedType =>
typeMatchesSpecifier(type, allowedType, services.program),
typeMatchesSomeSpecifier(
type,
allowForKnownSafePromises,
services.program,
)
) {
return false;
Expand Down
42 changes: 29 additions & 13 deletions packages/eslint-plugin/src/rules/restrict-template-expressions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import {
typeMatchesSomeSpecifier,
typeOrValueSpecifiersSchema,
} from '@typescript-eslint/type-utils';
import type { TSESTree } from '@typescript-eslint/utils';
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import type { Type, TypeChecker } from 'typescript';
import { TypeFlags } from 'typescript';

import type { TypeOrValueSpecifier } from '../util';
import {
createRule,
getConstrainedTypeAtLocation,
Expand Down Expand Up @@ -43,14 +48,16 @@ const optionTesters = (
(type, checker): boolean => getTypeName(checker, type) === 'RegExp',
],
['Never', isTypeNeverType],
] satisfies [string, OptionTester][]
] as const satisfies [string, OptionTester][]
).map(([type, tester]) => ({
type,
option: `allow${type}` as const,
tester,
}));
type Options = [
{ [Type in (typeof optionTesters)[number]['option']]?: boolean },
{ [Type in (typeof optionTesters)[number]['option']]?: boolean } & {
allow?: TypeOrValueSpecifier[];
},
];

type MessageId = 'invalidType';
Expand Down Expand Up @@ -84,15 +91,21 @@ export default createRule<Options, MessageId>({
{
type: 'object',
additionalProperties: false,
properties: Object.fromEntries(
optionTesters.map(({ option, type }) => [
option,
{
description: `Whether to allow \`${type.toLowerCase()}\` typed values in template expressions.`,
type: 'boolean',
},
]),
),
properties: {
...Object.fromEntries(
optionTesters.map(({ option, type }) => [
option,
{
description: `Whether to allow \`${type.toLowerCase()}\` typed values in template expressions.`,
type: 'boolean',
},
]),
),
allow: {
description: `Types to allow in template expressions.`,
...typeOrValueSpecifiersSchema,
},
},
},
],
},
Expand All @@ -103,11 +116,13 @@ export default createRule<Options, MessageId>({
allowNullish: true,
allowNumber: true,
allowRegExp: true,
allow: [{ from: 'lib', name: ['Error', 'URL', 'URLSearchParams'] }],
},
],
create(context, [options]) {
create(context, [{ allow, ...options }]) {
const services = getParserServices(context);
const checker = services.program.getTypeChecker();
const { program } = services;
const checker = program.getTypeChecker();
const enabledOptionTesters = optionTesters.filter(
({ option }) => options[option],
);
Expand Down Expand Up @@ -147,6 +162,7 @@ export default createRule<Options, MessageId>({

return (
isTypeFlagSet(innerType, TypeFlags.StringLike) ||
typeMatchesSomeSpecifier(innerType, allow, program) ||
enabledOptionTesters.some(({ tester }) =>
tester(innerType, checker, recursivelyCheckType),
)
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/eslint-plugin/tests/docs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ describe('Validating rule docs', () => {
const ignoredFiles = new Set([
'README.md',
'TEMPLATE.md',
'shared',
// These rule docs were left behind on purpose for legacy reasons. See the
// comments in the files for more information.
'ban-types.md',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,12 @@ ruleTester.run('restrict-template-expressions', rule, {
}
`,
},
// allow
{
options: [{ allow: [{ from: 'lib', name: 'Promise' }] }],
code: 'const msg = `arg = ${Promise.resolve()}`;',
},
'const msg = `arg = ${new Error()}`;',
'const msg = `arg = ${false}`;',
'const msg = `arg = ${null}`;',
'const msg = `arg = ${undefined}`;',
Expand Down Expand Up @@ -422,6 +428,15 @@ ruleTester.run('restrict-template-expressions', rule, {
],
options: [{ allowNullish: false, allowArray: true }],
},
{
code: 'const msg = `arg = ${Promise.resolve()}`;',
errors: [{ messageId: 'invalidType' }],
},
{
code: 'const msg = `arg = ${new Error()}`;',
options: [{ allow: [] }],
errors: [{ messageId: 'invalidType' }],
},
{
code: `
declare const arg: [number | undefined, string];
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading