Skip to content

Commit

Permalink
warn on assignment to const (#4960)
Browse files Browse the repository at this point in the history
* warn on assignment to const

* fix formatting and switch to error

* check most local scopes first

* fix logic and add more tests

* more formatting

* Fix broken test

* use find_owner instead

Co-authored-by: tanhauhau <lhtan93@gmail.com>
  • Loading branch information
BillyLevin and tanhauhau committed Oct 13, 2022
1 parent ab1285a commit 88ed993
Show file tree
Hide file tree
Showing 12 changed files with 207 additions and 3 deletions.
36 changes: 36 additions & 0 deletions src/compiler/compile/Component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,42 @@ export default class Component {
scope = map.get(node);
}

let deep = false;
let names: string[] | undefined;

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 => {
let current_scope = scope;
let declaration;

while (current_scope) {
if (current_scope.declarations.has(name)) {
declaration = current_scope.declarations.get(name);
break;
}
current_scope = current_scope.parent;
}

if (declaration && declaration.kind === 'const' && !deep) {
component.error(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
Expand Down
22 changes: 21 additions & 1 deletion src/compiler/compile/nodes/shared/Expression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,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));
}
}
Expand All @@ -149,7 +150,26 @@ export default class Expression {
component.add_reference(node, name);

const variable = component.var_lookup.get(name);
if (variable) variable[deep ? 'mutated' : 'reassigned'] = true;

if (variable) {
variable[deep ? 'mutated' : 'reassigned'] = true;
}

const declaration: any = scope.find_owner(name)?.declarations.get(name);

if (declaration) {
if (declaration.kind === 'const' && !deep) {
component.error(node, {
code: 'assignment-to-const',
message: 'You are assigning to a const'
});
}
} else if (variable && variable.writable === false && !deep) {
component.error(node, {
code: 'assignment-to-const',
message: 'You are assigning to a const'
});
}
}
});
}
Expand Down
2 changes: 1 addition & 1 deletion test/js/samples/unchanged-expression/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ let world1 = 'world';
let world2 = 'world';

function instance($$self, $$props, $$invalidate) {
const world3 = 'world';
let world3 = 'world';

function foo() {
$$invalidate(0, world3 = 'svelte');
Expand Down
2 changes: 1 addition & 1 deletion test/js/samples/unchanged-expression/input.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script>
let world1 = 'world';
let world2 = 'world';
const world3 = 'world';
let world3 = 'world';
function foo() {
world3 = 'svelte';
}
Expand Down
17 changes: 17 additions & 0 deletions test/validator/samples/assignment-to-const-2/errors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[
{
"code": "assignment-to-const",
"message": "You are assigning to a const",
"start": {
"line": 13,
"column": 24,
"character": 282
},
"end": {
"line": 13,
"column": 35,
"character": 293
},
"pos": 282
}
]
15 changes: 15 additions & 0 deletions test/validator/samples/assignment-to-const-2/input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script>
const immutable = 0;
const obj1 = { prop: true };
const obj2 = { prop: 0 }
</script>

<!-- should not error -->
<button on:click={() => obj1.prop = false}>click</button>
<button on:click={() => obj2.prop++}>click</button>

<!-- should error -->
<button on:click={() => immutable++}>click</button>


17 changes: 17 additions & 0 deletions test/validator/samples/assignment-to-const-3/errors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[
{
"code": "assignment-to-const",
"message": "You are assigning to a const",
"start": {
"line": 14,
"column": 3,
"character": 172
},
"end": {
"line": 14,
"column": 10,
"character": 179
},
"pos": 172
}
]
20 changes: 20 additions & 0 deletions test/validator/samples/assignment-to-const-3/input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script>
const foo = 'hello';
function shouldNotError() {
let foo = 0;
function inner() {
foo = 1;
}
}
function shouldError() {
function inner() {
foo = 1;
}
}
</script>

<button on:click={shouldNotError}>click</button>
<button on:click={shouldError}>click</button>
17 changes: 17 additions & 0 deletions test/validator/samples/assignment-to-const-4/errors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[
{
"code": "assignment-to-const",
"message": "You are assigning to a const",
"start": {
"line": 17,
"column": 2,
"character": 189
},
"end": {
"line": 17,
"column": 9,
"character": 196
},
"pos": 189
}
]
21 changes: 21 additions & 0 deletions test/validator/samples/assignment-to-const-4/input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script>
const foo = 'hello';
</script>

<button on:click={() => {
let foo = 0;

function inner() {
foo = 1;
}
}}>
click
</button>

<button on:click={() => {
function inner() {
foo = 1;
}
}}>
click
</button>
17 changes: 17 additions & 0 deletions test/validator/samples/assignment-to-const/errors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[
{
"code": "assignment-to-const",
"message": "You are assigning to a const",
"start": {
"line": 16,
"column": 2,
"character": 225
},
"end": {
"line": 16,
"column": 18,
"character": 241
},
"pos": 225
}
]
24 changes: 24 additions & 0 deletions test/validator/samples/assignment-to-const/input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script>
const immutable = false;
const obj1 = { prop: true };
const obj2 = { prop: 0 };
function shouldNotError() {
obj1.prop = false;
}
function shouldNotError2() {
obj2.prop++;
}
function shouldError() {
immutable = true
}
</script>

<button on:click={shouldNotError}>click</button>
<button on:click={shouldNotError2}>click</button>
<button on:click={shouldError}>click</button>

0 comments on commit 88ed993

Please sign in to comment.