From d6a9182d219fd08aa9855807af529462f84f252a Mon Sep 17 00:00:00 2001 From: Billy Levin Date: Tue, 2 Jun 2020 22:31:12 +0100 Subject: [PATCH] warn on assignment to const --- src/compiler/compile/Component.ts | 27 ++++++++ .../compile/nodes/shared/Expression.ts | 17 ++++- .../samples/assignment-to-const/input.svelte | 34 ++++++++++ .../samples/assignment-to-const/warnings.json | 62 +++++++++++++++++++ 4 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 test/validator/samples/assignment-to-const/input.svelte create mode 100644 test/validator/samples/assignment-to-const/warnings.json diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 2f8874de7a..85623c6da7 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -788,6 +788,33 @@ export default class Component { scope = map.get(node); } + let deep = false; + let names: string[] | null; + + if (node.type === 'AssignmentExpression') { + deep = node.left.type === 'MemberExpression'; + names = deep + ? [get_object(node.left).name] + : extract_names(node.left); + } else if (node.type === 'UpdateExpression') { + deep = node.argument.type === 'MemberExpression'; + const { name } = get_object(node.argument); + names = [name]; + } + + + if (names) { + names.forEach(name => { + const variable = component.var_lookup.get(name); + if (variable && variable.writable === false && !deep) { + component.warn(node as any, { + code: 'assignment-to-const', + message: 'You are assigning to a const' + }); + } + }); + } + if (node.type === 'ImportDeclaration') { component.extract_imports(node); // TODO: to use actual remove diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index 0603c15589..c3817dc3da 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -62,7 +62,7 @@ export default class Expression { // discover dependencies, but don't change the code yet walk(info, { - enter(node: any, parent: any, key: string) { + enter(node: Node, parent: any, key: string) { // don't manipulate shorthand props twice if (key === 'key' && parent.shorthand) return; // don't manipulate `import.meta`, `new.target` @@ -126,6 +126,7 @@ export default class Expression { deep = node.left.type === 'MemberExpression'; names = extract_names(deep ? get_object(node.left) : node.left); } else if (node.type === 'UpdateExpression') { + deep = node.argument.type === 'MemberExpression'; names = extract_names(get_object(node.argument)); } } @@ -146,8 +147,18 @@ export default class Expression { } else { component.add_reference(node, name); - const variable = component.var_lookup.get(name); - if (variable) variable[deep ? 'mutated' : 'reassigned'] = true; + const variable = component.var_lookup.get(name); + + if (variable) { + variable[deep ? 'mutated' : 'reassigned'] = true; + + if (!deep && variable.writable === false) { + component.warn(node as any, { + code: 'assignment-to-const', + message: 'You are assigning to a const' + }); + } + } } }); } diff --git a/test/validator/samples/assignment-to-const/input.svelte b/test/validator/samples/assignment-to-const/input.svelte new file mode 100644 index 0000000000..b685507b56 --- /dev/null +++ b/test/validator/samples/assignment-to-const/input.svelte @@ -0,0 +1,34 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/test/validator/samples/assignment-to-const/warnings.json b/test/validator/samples/assignment-to-const/warnings.json new file mode 100644 index 0000000000..fac54a6058 --- /dev/null +++ b/test/validator/samples/assignment-to-const/warnings.json @@ -0,0 +1,62 @@ +[ + { + "code": "assignment-to-const", + "message": "You are assigning to a const", + "start": { + "line": 31, + "column": 24, + "character": 512 + }, + "end": { + "line": 31, + "column": 41, + "character": 529 + }, + "pos": 512 + }, + { + "code": "assignment-to-const", + "message": "You are assigning to a const", + "start": { + "line": 32, + "column": 24, + "character": 570 + }, + "end": { + "line": 32, + "column": 36, + "character": 582 + }, + "pos": 570 + }, + { + "code": "assignment-to-const", + "message": "You are assigning to a const", + "start": { + "line": 10, + "column": 2, + "character": 171 + }, + "end": { + "line": 10, + "column": 19, + "character": 188 + }, + "pos": 171 + }, + { + "code": "assignment-to-const", + "message": "You are assigning to a const", + "start": { + "line": 14, + "column": 2, + "character": 215 + }, + "end": { + "line": 14, + "column": 14, + "character": 227 + }, + "pos": 215 + } +] \ No newline at end of file