eslint-plugin-svelte 3.0.2 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/main.d.ts +1 -1
- package/lib/meta.d.ts +1 -1
- package/lib/meta.js +1 -1
- package/lib/rule-types.d.ts +1 -0
- package/lib/rules/consistent-selector-style.js +7 -0
- package/lib/rules/no-navigation-without-base.js +27 -2
- package/lib/rules/prefer-const.js +23 -7
- package/lib/rules/valid-prop-names-in-kit-pages.js +4 -4
- package/lib/utils/svelte-context.js +1 -1
- package/package.json +3 -3
package/lib/main.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export declare const configs: {
|
|
|
14
14
|
export declare const rules: Record<string, Rule.RuleModule>;
|
|
15
15
|
export declare const meta: {
|
|
16
16
|
name: "eslint-plugin-svelte";
|
|
17
|
-
version: "3.0
|
|
17
|
+
version: "3.1.0";
|
|
18
18
|
};
|
|
19
19
|
export declare const processors: {
|
|
20
20
|
'.svelte': typeof processor;
|
package/lib/meta.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare const name = "eslint-plugin-svelte";
|
|
2
|
-
export declare const version = "3.0
|
|
2
|
+
export declare const version = "3.1.0";
|
package/lib/meta.js
CHANGED
package/lib/rule-types.d.ts
CHANGED
|
@@ -49,6 +49,7 @@ export default createRule('consistent-selector-style', {
|
|
|
49
49
|
const styleSelectorNodeLoc = sourceCode.parserServices.styleSelectorNodeLoc;
|
|
50
50
|
const checkGlobal = context.options[0]?.checkGlobal ?? false;
|
|
51
51
|
const style = context.options[0]?.style ?? ['type', 'id', 'class'];
|
|
52
|
+
const whitelistedClasses = [];
|
|
52
53
|
const classSelections = new Map();
|
|
53
54
|
const idSelections = new Map();
|
|
54
55
|
const typeSelections = new Map();
|
|
@@ -89,6 +90,9 @@ export default createRule('consistent-selector-style', {
|
|
|
89
90
|
* Checks a class selector
|
|
90
91
|
*/
|
|
91
92
|
function checkClassSelector(node) {
|
|
93
|
+
if (whitelistedClasses.includes(node.value)) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
92
96
|
const selection = classSelections.get(node.value) ?? [];
|
|
93
97
|
for (const styleValue of style) {
|
|
94
98
|
if (styleValue === 'class') {
|
|
@@ -171,6 +175,9 @@ export default createRule('consistent-selector-style', {
|
|
|
171
175
|
addToArrayMap(classSelections, className, node);
|
|
172
176
|
}
|
|
173
177
|
for (const attribute of node.startTag.attributes) {
|
|
178
|
+
if (attribute.type === 'SvelteDirective' && attribute.kind === 'Class') {
|
|
179
|
+
whitelistedClasses.push(attribute.key.name.name);
|
|
180
|
+
}
|
|
174
181
|
if (attribute.type !== 'SvelteAttribute' || attribute.key.name !== 'id') {
|
|
175
182
|
continue;
|
|
176
183
|
}
|
|
@@ -71,13 +71,14 @@ export default createRule('no-navigation-without-base', {
|
|
|
71
71
|
}
|
|
72
72
|
const hrefValue = node.value[0];
|
|
73
73
|
if (hrefValue.type === 'SvelteLiteral') {
|
|
74
|
-
if (!expressionIsAbsolute(hrefValue)) {
|
|
74
|
+
if (!expressionIsAbsolute(hrefValue) && !expressionIsFragment(hrefValue)) {
|
|
75
75
|
context.report({ loc: hrefValue.loc, messageId: 'linkNotPrefixed' });
|
|
76
76
|
}
|
|
77
77
|
return;
|
|
78
78
|
}
|
|
79
79
|
if (!expressionStartsWithBase(context, hrefValue.expression, basePathNames) &&
|
|
80
|
-
!expressionIsAbsolute(hrefValue.expression)
|
|
80
|
+
!expressionIsAbsolute(hrefValue.expression) &&
|
|
81
|
+
!expressionIsFragment(hrefValue.expression)) {
|
|
81
82
|
context.report({ loc: hrefValue.loc, messageId: 'linkNotPrefixed' });
|
|
82
83
|
}
|
|
83
84
|
}
|
|
@@ -247,3 +248,27 @@ function templateLiteralIsAbsolute(url) {
|
|
|
247
248
|
function urlValueIsAbsolute(url) {
|
|
248
249
|
return url.includes('://');
|
|
249
250
|
}
|
|
251
|
+
function expressionIsFragment(url) {
|
|
252
|
+
switch (url.type) {
|
|
253
|
+
case 'BinaryExpression':
|
|
254
|
+
return binaryExpressionIsFragment(url);
|
|
255
|
+
case 'Literal':
|
|
256
|
+
return typeof url.value === 'string' && urlValueIsFragment(url.value);
|
|
257
|
+
case 'SvelteLiteral':
|
|
258
|
+
return urlValueIsFragment(url.value);
|
|
259
|
+
case 'TemplateLiteral':
|
|
260
|
+
return templateLiteralIsFragment(url);
|
|
261
|
+
default:
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function binaryExpressionIsFragment(url) {
|
|
266
|
+
return url.left.type !== 'PrivateIdentifier' && expressionIsFragment(url.left);
|
|
267
|
+
}
|
|
268
|
+
function templateLiteralIsFragment(url) {
|
|
269
|
+
return ((url.expressions.length >= 1 && expressionIsFragment(url.expressions[0])) ||
|
|
270
|
+
(url.quasis.length >= 1 && urlValueIsFragment(url.quasis[0].value.raw)));
|
|
271
|
+
}
|
|
272
|
+
function urlValueIsFragment(url) {
|
|
273
|
+
return url.startsWith('#');
|
|
274
|
+
}
|
|
@@ -15,7 +15,7 @@ function findDeclarationCallee(node) {
|
|
|
15
15
|
* Determines if a declaration should be skipped in the const preference analysis.
|
|
16
16
|
* Specifically checks for Svelte's state management utilities ($props, $derived).
|
|
17
17
|
*/
|
|
18
|
-
function shouldSkipDeclaration(declaration) {
|
|
18
|
+
function shouldSkipDeclaration(declaration, excludedRunes) {
|
|
19
19
|
if (!declaration) {
|
|
20
20
|
return false;
|
|
21
21
|
}
|
|
@@ -23,15 +23,13 @@ function shouldSkipDeclaration(declaration) {
|
|
|
23
23
|
if (!callee) {
|
|
24
24
|
return false;
|
|
25
25
|
}
|
|
26
|
-
if (callee.type === 'Identifier' &&
|
|
26
|
+
if (callee.type === 'Identifier' && excludedRunes.includes(callee.name)) {
|
|
27
27
|
return true;
|
|
28
28
|
}
|
|
29
29
|
if (callee.type !== 'MemberExpression' || callee.object.type !== 'Identifier') {
|
|
30
30
|
return false;
|
|
31
31
|
}
|
|
32
|
-
if (callee.object.name
|
|
33
|
-
callee.property.type === 'Identifier' &&
|
|
34
|
-
callee.property.name === 'by') {
|
|
32
|
+
if (excludedRunes.includes(callee.object.name)) {
|
|
35
33
|
return true;
|
|
36
34
|
}
|
|
37
35
|
return false;
|
|
@@ -44,16 +42,34 @@ export default createRule('prefer-const', {
|
|
|
44
42
|
category: 'Best Practices',
|
|
45
43
|
recommended: false,
|
|
46
44
|
extensionRule: 'prefer-const'
|
|
47
|
-
}
|
|
45
|
+
},
|
|
46
|
+
schema: [
|
|
47
|
+
{
|
|
48
|
+
type: 'object',
|
|
49
|
+
properties: {
|
|
50
|
+
destructuring: { enum: ['any', 'all'] },
|
|
51
|
+
ignoreReadBeforeAssign: { type: 'boolean' },
|
|
52
|
+
excludedRunes: {
|
|
53
|
+
type: 'array',
|
|
54
|
+
items: {
|
|
55
|
+
type: 'string'
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
additionalProperties: false
|
|
60
|
+
}
|
|
61
|
+
]
|
|
48
62
|
},
|
|
49
63
|
create(context) {
|
|
64
|
+
const config = context.options[0] ?? {};
|
|
65
|
+
const excludedRunes = config.excludedRunes ?? ['$props', '$derived'];
|
|
50
66
|
return defineWrapperListener(coreRule, context, {
|
|
51
67
|
createListenerProxy(coreListener) {
|
|
52
68
|
return {
|
|
53
69
|
...coreListener,
|
|
54
70
|
VariableDeclaration(node) {
|
|
55
71
|
for (const decl of node.declarations) {
|
|
56
|
-
if (shouldSkipDeclaration(decl.init)) {
|
|
72
|
+
if (shouldSkipDeclaration(decl.init, excludedRunes)) {
|
|
57
73
|
return;
|
|
58
74
|
}
|
|
59
75
|
}
|
|
@@ -7,11 +7,11 @@ function checkProp(node, context, expectedPropNames) {
|
|
|
7
7
|
return;
|
|
8
8
|
for (const p of node.id.properties) {
|
|
9
9
|
if (p.type === 'Property' &&
|
|
10
|
-
p.
|
|
11
|
-
!expectedPropNames.includes(p.
|
|
10
|
+
p.key.type === 'Identifier' &&
|
|
11
|
+
!expectedPropNames.includes(p.key.name)) {
|
|
12
12
|
context.report({
|
|
13
|
-
node: p.
|
|
14
|
-
loc: p.
|
|
13
|
+
node: p.key,
|
|
14
|
+
loc: p.key.loc,
|
|
15
15
|
messageId: 'unexpected'
|
|
16
16
|
});
|
|
17
17
|
}
|
|
@@ -16,7 +16,7 @@ function getSvelteFileType(filePath) {
|
|
|
16
16
|
return null;
|
|
17
17
|
}
|
|
18
18
|
function getSvelteKitFileTypeFromFilePath(filePath) {
|
|
19
|
-
const fileName = filePath.split(
|
|
19
|
+
const fileName = filePath.split(/[/\\]/).pop();
|
|
20
20
|
switch (fileName) {
|
|
21
21
|
case '+page.svelte': {
|
|
22
22
|
return '+page.svelte';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-svelte",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "ESLint plugin for Svelte using AST",
|
|
5
5
|
"repository": "git+https://github.com/sveltejs/eslint-plugin-svelte.git",
|
|
6
6
|
"homepage": "https://sveltejs.github.io/eslint-plugin-svelte",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"funding": "https://github.com/sponsors/ota-meshi",
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"engines": {
|
|
11
|
-
"node": "^18.
|
|
11
|
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
|
12
12
|
},
|
|
13
13
|
"type": "module",
|
|
14
14
|
"main": "lib/index.js",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"postcss-load-config": "^3.1.4",
|
|
42
42
|
"postcss-safe-parser": "^7.0.0",
|
|
43
43
|
"semver": "^7.6.3",
|
|
44
|
-
"svelte-eslint-parser": "^1.0.
|
|
44
|
+
"svelte-eslint-parser": "^1.0.1"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@babel/core": "^7.26.0",
|