Files
headroom/frontend/node_modules/eslint-plugin-svelte/lib/rules/valid-prop-names-in-kit-pages.js
Santhosh Janardhanan de2d83092e feat: Reinitialize frontend with SvelteKit and TypeScript
- Delete old Vite+Svelte frontend
- Initialize new SvelteKit project with TypeScript
- Configure Tailwind CSS v4 + DaisyUI
- Implement JWT authentication with auto-refresh
- Create login page with form validation (Zod)
- Add protected route guards
- Update Docker configuration for single-stage build
- Add E2E tests with Playwright (6/11 passing)
- Fix Svelte 5 reactivity with $state() runes

Known issues:
- 5 E2E tests failing (timing/async issues)
- Token refresh implementation needs debugging
- Validation error display timing
2026-02-17 16:19:59 -05:00

97 lines
3.4 KiB
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);
}
};
}
});