Skip to content

Commit

Permalink
Merge pull request #852 from sveltejs/gh-849
Browse files Browse the repository at this point in the history
compile time error on slotted content inside if/each blocks. closes #849
  • Loading branch information
Rich-Harris authored Sep 16, 2017
2 parents 1446338 + 9b505de commit 6ad8c38
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 6 deletions.
5 changes: 4 additions & 1 deletion src/validate/html/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const meta = new Map([[':Window', validateWindow]]);
export default function validateHtml(validator: Validator, html: Node) {
const refs = new Map();
const refCallees: Node[] = [];
const stack: Node[] = [];
const elementStack: Node[] = [];

function visit(node: Node) {
Expand All @@ -21,7 +22,7 @@ export default function validateHtml(validator: Validator, html: Node) {
return meta.get(node.name)(validator, node, refs, refCallees);
}

validateElement(validator, node, refs, refCallees, elementStack);
validateElement(validator, node, refs, refCallees, stack, elementStack);
} else if (node.type === 'EachBlock') {
if (validator.helpers.has(node.context)) {
let c = node.expression.end;
Expand All @@ -40,7 +41,9 @@ export default function validateHtml(validator: Validator, html: Node) {

if (node.children) {
if (node.type === 'Element') elementStack.push(node);
stack.push(node);
node.children.forEach(visit);
stack.pop();
if (node.type === 'Element') elementStack.pop();
}

Expand Down
23 changes: 18 additions & 5 deletions src/validate/html/validateElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default function validateElement(
node: Node,
refs: Map<string, Node[]>,
refCallees: Node[],
stack: Node[],
elementStack: Node[]
) {
const isComponent =
Expand Down Expand Up @@ -189,11 +190,23 @@ export default function validateElement(
}
}

if (attribute.name === 'slot' && !isComponent && isDynamic(attribute)) {
validator.error(
`slot attribute cannot have a dynamic value`,
attribute.start
);
if (attribute.name === 'slot' && !isComponent) {
let i = stack.length;
while (i--) {
const parent = stack[i];
if (parent.type === 'Element' && validator.components.has(parent.name)) break;
if (parent.type === 'IfBlock' || parent.type === 'EachBlock') {
const message = `Cannot place slotted elements inside an ${parent.type === 'IfBlock' ? 'if' : 'each'}-block`;
validator.error(message, attribute.start);
}
}

if (isDynamic(attribute)) {
validator.error(
`slot attribute cannot have a dynamic value`,
attribute.start
);
}
}
}
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[{
"message": "Cannot place slotted elements inside an each-block",
"loc": {
"line": 3,
"column": 7
},
"pos": 43
}]
15 changes: 15 additions & 0 deletions test/validator/samples/component-slotted-each-block/input.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Nested>
{{#each things as thing}}
<div slot='foo'>{{thing}}</div>
{{/each}}
</Nested>

<script>
import Nested from './Nested.html';

export default {
components: {
Nested
}
};
</script>
8 changes: 8 additions & 0 deletions test/validator/samples/component-slotted-if-block/errors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[{
"message": "Cannot place slotted elements inside an if-block",
"loc": {
"line": 3,
"column": 7
},
"pos": 31
}]
15 changes: 15 additions & 0 deletions test/validator/samples/component-slotted-if-block/input.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Nested>
{{#if thing}}
<div slot='foo'>{{thing}}</div>
{{/if}}
</Nested>

<script>
import Nested from './Nested.html';

export default {
components: {
Nested
}
};
</script>

0 comments on commit 6ad8c38

Please sign in to comment.