eslint-plugin-svelte
Version:
ESLint plugin for Svelte using AST
97 lines (96 loc) • 3.53 kB
JavaScript
import { createRule } from '../utils/index.js';
import { getSvelteVersion } from '../utils/svelte-context.js';
const EXPECTED_PROP_NAMES = ['data', 'errors', 'form', 'params', 'snapshot'];
const EXPECTED_PROP_NAMES_SVELTE5 = [...EXPECTED_PROP_NAMES, 'children'];
function checkProp(node, context, expectedPropNames) {
if (node.id.type !== 'ObjectPattern')
return;
for (const p of node.id.properties) {
if (p.type === 'Property' &&
p.key.type === 'Identifier' &&
!expectedPropNames.includes(p.key.name)) {
context.report({
node: p.key,
loc: p.key.loc,
messageId: 'unexpected'
});
}
}
}
function isModuleScript(node) {
// <script context="module">
if (node.key.name === 'context' &&
node.value.some((v) => v.type === 'SvelteLiteral' && v.value === 'module')) {
return true;
}
// <script module>
if (node.key.name === 'module' && node.value.length === 0) {
return true;
}
return false;
}
export default createRule('valid-prop-names-in-kit-pages', {
meta: {
docs: {
description: 'disallow props other than data or errors in SvelteKit page components.',
category: 'SvelteKit',
recommended: true
},
schema: [],
messages: {
unexpected: 'disallow props other than data or errors in SvelteKit page components.'
},
type: 'problem',
conditions: [
{
svelteKitFileTypes: ['+page.svelte', '+error.svelte', '+layout.svelte']
}
]
},
create(context) {
let isScript = false;
const isSvelte5 = getSvelteVersion() === '5';
const expectedPropNames = isSvelte5 ? EXPECTED_PROP_NAMES_SVELTE5 : EXPECTED_PROP_NAMES;
return {
// <script>
'Program > SvelteScriptElement > SvelteStartTag': (node) => {
// except for <script context="module">
isScript = !node.attributes.some((a) => a.type === 'SvelteAttribute' && isModuleScript(a));
},
// </script>
'Program > SvelteScriptElement:exit': () => {
isScript = false;
},
// Svelte3,4
'ExportNamedDeclaration > VariableDeclaration > VariableDeclarator': (node) => {
if (!isScript)
return;
// export let foo
if (node.id.type === 'Identifier') {
if (!expectedPropNames.includes(node.id.name)) {
context.report({
node,
loc: node.loc,
messageId: 'unexpected'
});
}
return;
}
// export let { xxx, yyy } = zzz
checkProp(node, context, expectedPropNames);
},
// Svelte5
// let { foo, bar } = $props();
'VariableDeclaration > VariableDeclarator': (node) => {
if (!isScript)
return;
if (node.init?.type !== 'CallExpression' ||
node.init.callee?.type !== 'Identifier' ||
node.init.callee?.name !== '$props') {
return;
}
checkProp(node, context, expectedPropNames);
}
};
}
});