Skip to content

Commit 0bfd477

Browse files
author
Rebecca Stevens
committed
style: no-use-before-define is now more harsh.
1 parent 7e74e79 commit 0bfd477

File tree

6 files changed

+151
-151
lines changed

6 files changed

+151
-151
lines changed

.eslintrc

+3-3
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,10 @@
7676
"@typescript-eslint/no-use-before-define": [
7777
"error",
7878
{
79-
"functions": false,
80-
"classes": false,
79+
"functions": true,
80+
"classes": true,
8181
"variables": true,
82-
"typedefs": false
82+
"typedefs": true
8383
}
8484
],
8585

src/common/ignore-options.ts

+61-61
Original file line numberDiff line numberDiff line change
@@ -125,45 +125,18 @@ export const ignoreNewArrayOptionSchema: JSONSchema4 = {
125125
additionalProperties: false
126126
};
127127

128-
/**
129-
* Should the given node be ignored?
130-
*/
131-
export function shouldIgnore(
132-
node: TSESTree.Node,
133-
context: RuleContext<string, BaseOptions>,
134-
options: Partial<IgnoreOptions>
135-
): boolean {
136-
return (
137-
// Ignore if in a function and ignoreLocal is set.
138-
(Boolean(options.ignoreLocal) && inFunction(node)) ||
139-
// Ignore if in a class and ignoreClass is set.
140-
(Boolean(options.ignoreClass) && inClass(node)) ||
141-
// Ignore if in an interface and ignoreInterface is set.
142-
(Boolean(options.ignoreInterface) && inInterface(node)) ||
143-
((texts: ReadonlyArray<string>): boolean =>
144-
texts.length > 0
145-
? // Ignore if ignorePattern is set and a pattern matches.
146-
(options.ignorePattern !== undefined &&
147-
texts.every(text =>
148-
isIgnoredPattern(text, options.ignorePattern!)
149-
)) ||
150-
// Ignore if ignoreAccessorPattern is set and an accessor pattern matches.
151-
(options.ignoreAccessorPattern !== undefined &&
152-
texts.every(text =>
153-
isIgnoredAccessorPattern(text, options.ignoreAccessorPattern!)
154-
))
155-
: false)(getNodeTexts(node, context))
156-
);
157-
}
158-
159-
function getNodeTexts(
128+
function _getNodeText(
160129
node: TSESTree.Node,
161130
context: RuleContext<string, BaseOptions>
162-
): ReadonlyArray<string> {
163-
return (isVariableDeclaration(node)
164-
? node.declarations.flatMap(declarator => getNodeText(declarator, context))
165-
: [getNodeText(node, context)]
166-
).filter(name => name !== undefined) as ReadonlyArray<string>;
131+
): string {
132+
return isIdentifier(node)
133+
? node.name
134+
: isMemberExpression(node)
135+
? `${_getNodeText(node.object, context)}.${_getNodeText(
136+
node.property,
137+
context
138+
)}`
139+
: context.getSourceCode().getText(node);
167140
}
168141

169142
function getNodeText(
@@ -183,18 +156,14 @@ function getNodeText(
183156
: _getNodeText(node, context);
184157
}
185158

186-
function _getNodeText(
159+
function getNodeTexts(
187160
node: TSESTree.Node,
188161
context: RuleContext<string, BaseOptions>
189-
): string {
190-
return isIdentifier(node)
191-
? node.name
192-
: isMemberExpression(node)
193-
? `${_getNodeText(node.object, context)}.${_getNodeText(
194-
node.property,
195-
context
196-
)}`
197-
: context.getSourceCode().getText(node);
162+
): ReadonlyArray<string> {
163+
return (isVariableDeclaration(node)
164+
? node.declarations.flatMap(declarator => getNodeText(declarator, context))
165+
: [getNodeText(node, context)]
166+
).filter(name => name !== undefined) as ReadonlyArray<string>;
198167
}
199168

200169
function isIgnoredPattern(
@@ -209,20 +178,6 @@ function isIgnoredPattern(
209178
return patterns.some(pattern => new RegExp(pattern).test(text));
210179
}
211180

212-
function isIgnoredAccessorPattern(
213-
text: string,
214-
ignorePattern: ReadonlyArray<string> | string
215-
): boolean {
216-
const patterns: ReadonlyArray<string> = Array.isArray(ignorePattern)
217-
? ignorePattern
218-
: [ignorePattern];
219-
220-
// One or more patterns match?
221-
return patterns.some(pattern =>
222-
findMatch(pattern.split("."), text.split("."))
223-
);
224-
}
225-
226181
function findMatch(
227182
[pattern, ...remainingPatternParts]: ReadonlyArray<string>,
228183
textParts: ReadonlyArray<string>,
@@ -248,3 +203,48 @@ function findMatch(
248203
textParts[0]
249204
) && findMatch(remainingPatternParts, textParts.slice(1), allowExtra);
250205
}
206+
207+
function isIgnoredAccessorPattern(
208+
text: string,
209+
ignorePattern: ReadonlyArray<string> | string
210+
): boolean {
211+
const patterns: ReadonlyArray<string> = Array.isArray(ignorePattern)
212+
? ignorePattern
213+
: [ignorePattern];
214+
215+
// One or more patterns match?
216+
return patterns.some(pattern =>
217+
findMatch(pattern.split("."), text.split("."))
218+
);
219+
}
220+
221+
/**
222+
* Should the given node be ignored?
223+
*/
224+
export function shouldIgnore(
225+
node: TSESTree.Node,
226+
context: RuleContext<string, BaseOptions>,
227+
options: Partial<IgnoreOptions>
228+
): boolean {
229+
return (
230+
// Ignore if in a function and ignoreLocal is set.
231+
(Boolean(options.ignoreLocal) && inFunction(node)) ||
232+
// Ignore if in a class and ignoreClass is set.
233+
(Boolean(options.ignoreClass) && inClass(node)) ||
234+
// Ignore if in an interface and ignoreInterface is set.
235+
(Boolean(options.ignoreInterface) && inInterface(node)) ||
236+
((texts: ReadonlyArray<string>): boolean =>
237+
texts.length > 0
238+
? // Ignore if ignorePattern is set and a pattern matches.
239+
(options.ignorePattern !== undefined &&
240+
texts.every(text =>
241+
isIgnoredPattern(text, options.ignorePattern!)
242+
)) ||
243+
// Ignore if ignoreAccessorPattern is set and an accessor pattern matches.
244+
(options.ignoreAccessorPattern !== undefined &&
245+
texts.every(text =>
246+
isIgnoredAccessorPattern(text, options.ignoreAccessorPattern!)
247+
))
248+
: false)(getNodeTexts(node, context))
249+
);
250+
}

src/rules/functional-parameters.ts

+20-20
Original file line numberDiff line numberDiff line change
@@ -83,26 +83,6 @@ const meta: RuleMetaData<keyof typeof errorMessages> = {
8383
schema
8484
};
8585

86-
/**
87-
* Check if the given function node has a reset parameter this rule.
88-
*/
89-
function checkFunction(
90-
node:
91-
| TSESTree.FunctionDeclaration
92-
| TSESTree.FunctionExpression
93-
| TSESTree.ArrowFunctionExpression,
94-
context: RuleContext<keyof typeof errorMessages, Options>,
95-
options: Options
96-
): RuleResult<keyof typeof errorMessages, Options> {
97-
return {
98-
context,
99-
descriptors: [
100-
...getRestParamViolations(options.allowRestParameter, node),
101-
...getParamCountViolations(options.enforceParameterCount, node)
102-
]
103-
};
104-
}
105-
10686
function getRestParamViolations(
10787
allowRestParameter: boolean,
10888
node:
@@ -146,6 +126,26 @@ function getParamCountViolations(
146126
: [];
147127
}
148128

129+
/**
130+
* Check if the given function node has a reset parameter this rule.
131+
*/
132+
function checkFunction(
133+
node:
134+
| TSESTree.FunctionDeclaration
135+
| TSESTree.FunctionExpression
136+
| TSESTree.ArrowFunctionExpression,
137+
context: RuleContext<keyof typeof errorMessages, Options>,
138+
options: Options
139+
): RuleResult<keyof typeof errorMessages, Options> {
140+
return {
141+
context,
142+
descriptors: [
143+
...getRestParamViolations(options.allowRestParameter, node),
144+
...getParamCountViolations(options.enforceParameterCount, node)
145+
]
146+
};
147+
}
148+
149149
/**
150150
* Check if the given identifier is for the "arguments" keyword.
151151
*/

src/rules/immutable-data.ts

+41-41
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,47 @@ function checkUpdateExpression(
195195
};
196196
}
197197

198+
/**
199+
* Check if the given the given MemberExpression is part of a chain and
200+
* immediately follows a method/function call that returns a new array.
201+
*
202+
* If this is the case, then the given MemberExpression is allowed to be
203+
* a mutator method call.
204+
*/
205+
function isInChainCallAndFollowsNew(
206+
node: TSESTree.MemberExpression,
207+
context: RuleContext<keyof typeof errorMessages, Options>,
208+
assumeArrayTypes: boolean
209+
): boolean {
210+
return (
211+
// Check for: [0, 1, 2]
212+
isArrayExpression(node.object) ||
213+
// Check for: new Array()
214+
((isNewExpression(node.object) &&
215+
isArrayConstructorType(
216+
getTypeOfNode(node.object.callee, context),
217+
assumeArrayTypes,
218+
node.object.callee
219+
)) ||
220+
(isCallExpression(node.object) &&
221+
isMemberExpression(node.object.callee) &&
222+
isIdentifier(node.object.callee.property) &&
223+
// Check for: Array.from(iterable)
224+
((arrayConstructorFunctions.some(
225+
isExpected(node.object.callee.property.name)
226+
) &&
227+
isArrayConstructorType(
228+
getTypeOfNode(node.object.callee.object, context),
229+
assumeArrayTypes,
230+
node.object.callee.object
231+
)) ||
232+
// Check for: array.slice(0)
233+
arrayNewObjectReturningMethods.some(
234+
isExpected(node.object.callee.property.name)
235+
))))
236+
);
237+
}
238+
198239
/**
199240
* Check if the given node violates this rule.
200241
*/
@@ -254,47 +295,6 @@ function checkCallExpression(
254295
};
255296
}
256297

257-
/**
258-
* Check if the given the given MemberExpression is part of a chain and
259-
* immediately follows a method/function call that returns a new array.
260-
*
261-
* If this is the case, then the given MemberExpression is allowed to be
262-
* a mutator method call.
263-
*/
264-
function isInChainCallAndFollowsNew(
265-
node: TSESTree.MemberExpression,
266-
context: RuleContext<keyof typeof errorMessages, Options>,
267-
assumeArrayTypes: boolean
268-
): boolean {
269-
return (
270-
// Check for: [0, 1, 2]
271-
isArrayExpression(node.object) ||
272-
// Check for: new Array()
273-
((isNewExpression(node.object) &&
274-
isArrayConstructorType(
275-
getTypeOfNode(node.object.callee, context),
276-
assumeArrayTypes,
277-
node.object.callee
278-
)) ||
279-
(isCallExpression(node.object) &&
280-
isMemberExpression(node.object.callee) &&
281-
isIdentifier(node.object.callee.property) &&
282-
// Check for: Array.from(iterable)
283-
((arrayConstructorFunctions.some(
284-
isExpected(node.object.callee.property.name)
285-
) &&
286-
isArrayConstructorType(
287-
getTypeOfNode(node.object.callee.object, context),
288-
assumeArrayTypes,
289-
node.object.callee.object
290-
)) ||
291-
// Check for: array.slice(0)
292-
arrayNewObjectReturningMethods.some(
293-
isExpected(node.object.callee.property.name)
294-
))))
295-
);
296-
}
297-
298298
// Create the rule.
299299
export const rule = createRule<keyof typeof errorMessages, Options>(
300300
name,

src/util/tree.ts

+14-14
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,20 @@ import {
1010
isTSInterfaceBody
1111
} from "./typeguard";
1212

13+
/**
14+
* Return the parent that meets the given check criteria.
15+
*/
16+
function getParentOfType<T extends TSESTree.Node>(
17+
checker: (node: TSESTree.Node) => node is T,
18+
node: TSESTree.Node
19+
): T | null {
20+
return checker(node)
21+
? node
22+
: node.parent == undefined
23+
? null
24+
: getParentOfType(checker, node.parent);
25+
}
26+
1327
/**
1428
* Test if the given node is in a function.
1529
*/
@@ -73,17 +87,3 @@ export function isPropertyName(node: TSESTree.Identifier): boolean {
7387
node.parent.key === node
7488
);
7589
}
76-
77-
/**
78-
* Return the parent that meets the given check criteria.
79-
*/
80-
function getParentOfType<T extends TSESTree.Node>(
81-
checker: (node: TSESTree.Node) => node is T,
82-
node: TSESTree.Node
83-
): T | null {
84-
return checker(node)
85-
? node
86-
: node.parent == undefined
87-
? null
88-
: getParentOfType(checker, node.parent);
89-
}

tests/util.ts

+12-12
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,6 @@ export type InvalidTestCase = Omit<
2424
> &
2525
OptionsSet;
2626

27-
/**
28-
* Convert our test cases into ones eslint test runner is expecting.
29-
*/
30-
export function processValidTestCase(
31-
testCases: ReadonlyArray<ValidTestCase>
32-
): Array<ESLintRuleTester.ValidTestCase> {
33-
// Ideally these two functions should be merged into 1 but I haven't been able
34-
// to get the typing information right - so for now they are two functions.
35-
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
36-
return processInvalidTestCase(testCases as any);
37-
}
38-
3927
/**
4028
* Convert our test cases into ones eslint test runner is expecting.
4129
*/
@@ -65,6 +53,18 @@ export function processInvalidTestCase(
6553
) as Array<ESLintRuleTester.InvalidTestCase>;
6654
}
6755

56+
/**
57+
* Convert our test cases into ones eslint test runner is expecting.
58+
*/
59+
export function processValidTestCase(
60+
testCases: ReadonlyArray<ValidTestCase>
61+
): Array<ESLintRuleTester.ValidTestCase> {
62+
// Ideally these two functions should be merged into 1 but I haven't been able
63+
// to get the typing information right - so for now they are two functions.
64+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
65+
return processInvalidTestCase(testCases as any);
66+
}
67+
6868
export function createDummyRule(
6969
create: (
7070
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */

0 commit comments

Comments
 (0)