Skip to content

Commit cc96baa

Browse files
committed
chore: extracted expression affix funtions from no-navigation-without-base
1 parent 294bf5e commit cc96baa

File tree

2 files changed

+79
-81
lines changed

2 files changed

+79
-81
lines changed

packages/eslint-plugin-svelte/src/rules/no-navigation-without-base.ts

Lines changed: 3 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { createRule } from '../utils/index.js';
33
import { ReferenceTracker } from '@eslint-community/eslint-utils';
44
import { getSourceCode } from '../utils/compat.js';
55
import { findVariable } from '../utils/ast-utils.js';
6+
import { extractExpressionPrefixVariable } from '../utils/expression-affixes.js';
67
import type { RuleContext } from '../types.js';
78
import type { SvelteLiteral } from 'svelte-eslint-parser/lib/ast';
89

@@ -224,87 +225,8 @@ function expressionStartsWithBase(
224225
url: TSESTree.Expression,
225226
basePathNames: Set<TSESTree.Identifier>
226227
): boolean {
227-
switch (url.type) {
228-
case 'BinaryExpression':
229-
return binaryExpressionStartsWithBase(context, url, basePathNames);
230-
case 'Identifier':
231-
return variableStartsWithBase(context, url, basePathNames);
232-
case 'MemberExpression':
233-
return memberExpressionStartsWithBase(url, basePathNames);
234-
case 'TemplateLiteral':
235-
return templateLiteralStartsWithBase(context, url, basePathNames);
236-
default:
237-
return false;
238-
}
239-
}
240-
241-
function binaryExpressionStartsWithBase(
242-
context: RuleContext,
243-
url: TSESTree.BinaryExpression,
244-
basePathNames: Set<TSESTree.Identifier>
245-
): boolean {
246-
return (
247-
url.left.type !== 'PrivateIdentifier' &&
248-
expressionStartsWithBase(context, url.left, basePathNames)
249-
);
250-
}
251-
252-
function memberExpressionStartsWithBase(
253-
url: TSESTree.MemberExpression,
254-
basePathNames: Set<TSESTree.Identifier>
255-
): boolean {
256-
return url.property.type === 'Identifier' && basePathNames.has(url.property);
257-
}
258-
259-
function variableStartsWithBase(
260-
context: RuleContext,
261-
url: TSESTree.Identifier,
262-
basePathNames: Set<TSESTree.Identifier>
263-
): boolean {
264-
if (basePathNames.has(url)) {
265-
return true;
266-
}
267-
const variable = findVariable(context, url);
268-
if (
269-
variable === null ||
270-
variable.identifiers.length !== 1 ||
271-
variable.identifiers[0].parent.type !== 'VariableDeclarator' ||
272-
variable.identifiers[0].parent.init === null
273-
) {
274-
return false;
275-
}
276-
return expressionStartsWithBase(context, variable.identifiers[0].parent.init, basePathNames);
277-
}
278-
279-
function templateLiteralStartsWithBase(
280-
context: RuleContext,
281-
url: TSESTree.TemplateLiteral,
282-
basePathNames: Set<TSESTree.Identifier>
283-
): boolean {
284-
const startingIdentifier = extractLiteralStartingExpression(url);
285-
return (
286-
startingIdentifier !== undefined &&
287-
expressionStartsWithBase(context, startingIdentifier, basePathNames)
288-
);
289-
}
290-
291-
function extractLiteralStartingExpression(
292-
templateLiteral: TSESTree.TemplateLiteral
293-
): TSESTree.Expression | undefined {
294-
const literalParts = [...templateLiteral.expressions, ...templateLiteral.quasis].sort((a, b) =>
295-
a.range[0] < b.range[0] ? -1 : 1
296-
);
297-
for (const part of literalParts) {
298-
if (part.type === 'TemplateElement' && part.value.raw === '') {
299-
// Skip empty quasi in the begining
300-
continue;
301-
}
302-
if (part.type !== 'TemplateElement') {
303-
return part;
304-
}
305-
return undefined;
306-
}
307-
return undefined;
228+
const prefixVariable = extractExpressionPrefixVariable(context, url);
229+
return prefixVariable !== null && basePathNames.has(prefixVariable);
308230
}
309231

310232
function expressionIsEmpty(url: TSESTree.Expression): boolean {
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import type { TSESTree } from '@typescript-eslint/types';
2+
import { findVariable } from './ast-utils.js';
3+
import type { RuleContext } from '../types.js';
4+
5+
// Variable prefix extraction
6+
7+
export function extractExpressionPrefixVariable(
8+
context: RuleContext,
9+
expression: TSESTree.Expression
10+
): TSESTree.Identifier | null {
11+
switch (expression.type) {
12+
case 'BinaryExpression':
13+
return extractBinaryExpressionPrefixVariable(context, expression);
14+
case 'Identifier':
15+
return extractVariablePrefixVariable(context, expression);
16+
case 'MemberExpression':
17+
return extractMemberExpressionPrefixVariable(expression);
18+
case 'TemplateLiteral':
19+
return extractTemplateLiteralPrefixVariable(context, expression);
20+
default:
21+
return null;
22+
}
23+
}
24+
25+
function extractBinaryExpressionPrefixVariable(
26+
context: RuleContext,
27+
expression: TSESTree.BinaryExpression
28+
): TSESTree.Identifier | null {
29+
return expression.left.type !== 'PrivateIdentifier'
30+
? extractExpressionPrefixVariable(context, expression.left)
31+
: null;
32+
}
33+
34+
function extractVariablePrefixVariable(
35+
context: RuleContext,
36+
expression: TSESTree.Identifier
37+
): TSESTree.Identifier | null {
38+
const variable = findVariable(context, expression);
39+
if (
40+
variable === null ||
41+
variable.identifiers.length !== 1 ||
42+
variable.identifiers[0].parent.type !== 'VariableDeclarator' ||
43+
variable.identifiers[0].parent.init === null
44+
) {
45+
return expression;
46+
}
47+
return (
48+
extractExpressionPrefixVariable(context, variable.identifiers[0].parent.init) ?? expression
49+
);
50+
}
51+
52+
function extractMemberExpressionPrefixVariable(
53+
expression: TSESTree.MemberExpression
54+
): TSESTree.Identifier | null {
55+
return expression.property.type === 'Identifier' ? expression.property : null;
56+
}
57+
58+
function extractTemplateLiteralPrefixVariable(
59+
context: RuleContext,
60+
expression: TSESTree.TemplateLiteral
61+
): TSESTree.Identifier | null {
62+
const literalParts = [...expression.expressions, ...expression.quasis].sort((a, b) =>
63+
a.range[0] < b.range[0] ? -1 : 1
64+
);
65+
for (const part of literalParts) {
66+
if (part.type === 'TemplateElement' && part.value.raw === '') {
67+
// Skip empty quasi in the begining
68+
continue;
69+
}
70+
if (part.type !== 'TemplateElement') {
71+
return extractExpressionPrefixVariable(context, part);
72+
}
73+
return null;
74+
}
75+
return null;
76+
}

0 commit comments

Comments
 (0)