mirror of https://github.com/sveltejs/svelte
parent
f54d3197fb
commit
72418ecfac
@ -0,0 +1,55 @@
|
||||
import { error } from '../../errors.js';
|
||||
|
||||
/**
|
||||
* @param {import('../../errors.js').NodeLike} node
|
||||
* @param {import('estree').Pattern | import('estree').Expression} argument
|
||||
* @param {import('../scope').Scope} scope
|
||||
* @param {boolean} is_binding
|
||||
*/
|
||||
export function validate_no_const_assignment(node, argument, scope, is_binding) {
|
||||
if (argument.type === 'Identifier') {
|
||||
const binding = scope.get(argument.name);
|
||||
if (binding?.declaration_kind === 'const' && binding.kind !== 'each') {
|
||||
error(
|
||||
node,
|
||||
'invalid-const-assignment',
|
||||
is_binding,
|
||||
// This takes advantage of the fact that we don't assign initial for let directives and then/catch variables.
|
||||
// If we start doing that, we need another property on the binding to differentiate, or give up on the more precise error message.
|
||||
binding.kind !== 'state' && (binding.kind !== 'normal' || !binding.initial)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('estree').AssignmentExpression | import('estree').UpdateExpression} node
|
||||
* @param {import('estree').Pattern | import('estree').Expression} argument
|
||||
* @param {import('./types.js').AnalysisState} state
|
||||
*/
|
||||
export function validate_assignment(node, argument, state) {
|
||||
validate_no_const_assignment(node, argument, state.scope, false);
|
||||
|
||||
let left = /** @type {import('estree').Expression | import('estree').Super} */ (argument);
|
||||
|
||||
/** @type {import('estree').Expression | import('estree').PrivateIdentifier | null} */
|
||||
let property = null;
|
||||
|
||||
while (left.type === 'MemberExpression') {
|
||||
property = left.property;
|
||||
left = left.object;
|
||||
}
|
||||
|
||||
if (left.type === 'Identifier') {
|
||||
const binding = state.scope.get(left.name);
|
||||
if (binding?.kind === 'derived') {
|
||||
error(node, 'invalid-derived-assignment');
|
||||
}
|
||||
}
|
||||
|
||||
if (left.type === 'ThisExpression' && property?.type === 'PrivateIdentifier') {
|
||||
if (state.private_derived_state.includes(property.name)) {
|
||||
error(node, 'invalid-derived-assignment');
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
import { error } from '../../../errors.js';
|
||||
import { validate_assignment } from '../utils.js';
|
||||
|
||||
/** @type {import('../types').Visitors} */
|
||||
export const validate_legacy = {
|
||||
VariableDeclarator(node) {
|
||||
if (node.init?.type !== 'CallExpression') return;
|
||||
|
||||
const callee = node.init.callee;
|
||||
if (
|
||||
callee.type !== 'Identifier' ||
|
||||
(callee.name !== '$state' && callee.name !== '$derived' && callee.name !== '$props')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO check if it's a store subscription that's called? How likely is it that someone uses a store that contains a function?
|
||||
error(node.init, 'invalid-rune-usage', callee.name);
|
||||
},
|
||||
ExportNamedDeclaration(node) {
|
||||
if (
|
||||
node.declaration &&
|
||||
node.declaration.type !== 'VariableDeclaration' &&
|
||||
node.declaration.type !== 'FunctionDeclaration'
|
||||
) {
|
||||
error(node, 'TODO', 'whatever this is');
|
||||
}
|
||||
},
|
||||
AssignmentExpression(node, { state, path }) {
|
||||
// TODO this is also in validation_runes, DRY out
|
||||
const parent = path.at(-1);
|
||||
if (parent && parent.type === 'ConstTag') return;
|
||||
validate_assignment(node, node.left, state);
|
||||
},
|
||||
UpdateExpression(node, { state }) {
|
||||
// TODO this is also in validation_runes, DRY out
|
||||
validate_assignment(node, node.argument, state);
|
||||
}
|
||||
};
|
Loading…
Reference in new issue