Skip to content

Commit e35f174

Browse files
authored
Merge pull request #1628 from sveltejs/gh-1540
handle rest elements in computed properties
2 parents 65aae85 + 7d55a57 commit e35f174

File tree

6 files changed

+71
-9
lines changed

6 files changed

+71
-9
lines changed

src/compile/Compiler.ts

+11-6
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ import { Node, GenerateOptions, ShorthandImport, Ast, CompileOptions, CustomElem
2424

2525
interface Computation {
2626
key: string;
27-
deps: string[]
27+
deps: string[];
28+
hasRestParam: boolean;
2829
}
2930

3031
function detectIndentation(str: string) {
@@ -436,7 +437,6 @@ export default class Compiler {
436437
code,
437438
source,
438439
computations,
439-
methods,
440440
templateProperties,
441441
imports
442442
} = this;
@@ -588,15 +588,20 @@ export default class Compiler {
588588

589589
const param = value.params[0];
590590

591-
if (param.type === 'ObjectPattern') {
591+
const hasRestParam = (
592+
param.properties &&
593+
param.properties.some(prop => prop.type === 'RestElement')
594+
);
595+
596+
if (param.type !== 'ObjectPattern' || hasRestParam) {
597+
fullStateComputations.push({ key, deps: null, hasRestParam });
598+
} else {
592599
const deps = param.properties.map(prop => prop.key.name);
593600

594601
deps.forEach(dep => {
595602
this.expectedProperties.add(dep);
596603
});
597604
dependencies.set(key, deps);
598-
} else {
599-
fullStateComputations.push({ key, deps: null })
600605
}
601606
});
602607

@@ -611,7 +616,7 @@ export default class Compiler {
611616
const deps = dependencies.get(key);
612617
deps.forEach(visit);
613618

614-
computations.push({ key, deps });
619+
computations.push({ key, deps, hasRestParam: false });
615620

616621
const prop = templateProperties.computed.value.properties.find((prop: Node) => getName(prop.key) === key);
617622
};

src/compile/dom/index.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export default function dom(
6767
const computationDeps = new Set();
6868

6969
if (computations.length) {
70-
computations.forEach(({ key, deps }) => {
70+
computations.forEach(({ key, deps, hasRestParam }) => {
7171
if (target.readonly.has(key)) {
7272
// <svelte:window> bindings
7373
throw new Error(
@@ -89,8 +89,10 @@ export default function dom(
8989
} else {
9090
// computed property depends on entire state object —
9191
// these must go at the end
92+
const arg = hasRestParam ? `@exclude(state, "${key}")` : `state`;
93+
9294
computationBuilder.addLine(
93-
`if (this._differs(state.${key}, (state.${key} = %computed-${key}(state)))) changed.${key} = true;`
95+
`if (this._differs(state.${key}, (state.${key} = %computed-${key}(${arg})))) changed.${key} = true;`
9496
);
9597
}
9698
});

src/shared/utils.js

+6
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,10 @@ export function addLoc(element, file, line, column, char) {
2525
element.__svelte_meta = {
2626
loc: { file, line, column, char }
2727
};
28+
}
29+
30+
export function exclude(src, prop) {
31+
const tar = {};
32+
for (const k in src) k === prop || (tar[k] = src[k]);
33+
return tar;
2834
}

src/utils/annotateWithScopes.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,11 @@ const extractors = {
137137

138138
ObjectPattern(names: string[], param: Node) {
139139
param.properties.forEach((prop: Node) => {
140-
extractors[prop.value.type](names, prop.value);
140+
if (prop.type === 'RestElement') {
141+
names.push(prop.argument.name);
142+
} else {
143+
extractors[prop.value.type](names, prop.value);
144+
}
141145
});
142146
},
143147

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
export default {
2+
skip: +/v(\d+)/.exec(process.version)[1] < 8,
3+
4+
html: `
5+
<pre>{"wanted":2}</pre>
6+
`,
7+
8+
test(assert, component, target) {
9+
component.set({
10+
unwanted: 3,
11+
wanted: 4
12+
});
13+
14+
assert.htmlEqual(target.innerHTML, `
15+
<pre>{"wanted":4}</pre>
16+
`);
17+
18+
component.set({
19+
unwanted: 5,
20+
wanted: 6
21+
});
22+
23+
assert.htmlEqual(target.innerHTML, `
24+
<pre>{"wanted":6}</pre>
25+
`);
26+
}
27+
};
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<pre>{JSON.stringify(props)}</pre>
2+
<script>
3+
export default {
4+
data: () => ({
5+
unwanted: 1,
6+
wanted: 2
7+
}),
8+
9+
helpers: {
10+
// prevent this being mixed in with data
11+
JSON
12+
},
13+
14+
computed: {
15+
props: ({ unwanted, ...x }) => x
16+
}
17+
};
18+
</script>

0 commit comments

Comments
 (0)