pull/787/head
Rich Harris 7 years ago
parent aa183df289
commit a023346c91

@ -143,6 +143,26 @@ export default function tag(parser: Parser) {
}
}
if (name === 'slot') {
let i = parser.stack.length;
while (i--) {
const item = parser.stack[i];
if (item.type === 'EachBlock') {
parser.error(
`<slot> cannot be a child of an each-block`,
start
);
}
if (item.type === 'Element' && item.name === 'slot') {
parser.error(
`<slot> elements cannot be nested`,
start
);
}
}
}
const attributes = [];
const uniqueNames = new Set();

@ -11,6 +11,35 @@ export default function validateElement(validator: Validator, node: Node, refs:
validator.warn(`${node.name} component is not defined`, node.start);
}
if (node.name === 'slot') {
const nameAttribute = node.attributes.find((attribute: Node) => attribute.name === 'name');
if (nameAttribute) {
if (nameAttribute.value.length !== 1 || nameAttribute.value[0].type !== 'Text') {
validator.error(`<slot> name cannot be dynamic`, nameAttribute.start);
}
const slotName = nameAttribute.value[0].data;
if (slotName === 'default') {
validator.error(`default is a reserved word — it cannot be used as a slot name`, nameAttribute.start);
}
// TODO should duplicate slots be disallowed? Feels like it's more likely to be a
// bug than anything. Perhaps it should be a warning
// if (validator.slots.has(slotName)) {
// validator.error(`duplicate '${slotName}' <slot> element`, nameAttribute.start);
// }
// validator.slots.add(slotName);
} else {
// if (validator.slots.has('default')) {
// validator.error(`duplicate default <slot> element`, node.start);
// }
// validator.slots.add('default');
}
}
let hasIntro: boolean;
let hasOutro: boolean;
let hasTransition: boolean;
@ -136,6 +165,13 @@ export default function validateElement(validator: Validator, node: Node, refs:
);
}
}
if (attribute.name === 'slot' && !isComponent && isDynamic(attribute)) {
validator.error(
`slot attribute cannot have a dynamic value`,
attribute.start
);
}
}
});
}
@ -150,7 +186,7 @@ function checkTypeAttribute(validator: Validator, node: Node) {
validator.error(`'type' attribute must be specified`, attribute.start);
}
if (attribute.value.length > 1 || attribute.value[0].type !== 'Text') {
if (isDynamic(attribute)) {
validator.error(
`'type' attribute cannot be dynamic if input uses two-way binding`,
attribute.start
@ -159,3 +195,7 @@ function checkTypeAttribute(validator: Validator, node: Node) {
return attribute.value[0].data;
}
function isDynamic(attribute: Node) {
return attribute.value.length > 1 || attribute.value[0].type !== 'Text';
}

@ -32,6 +32,7 @@ export class Validator {
methods: Map<string, Node>;
helpers: Map<string, Node>;
transitions: Map<string, Node>;
slots: Set<string>;
constructor(parsed: Parsed, source: string, options: CompileOptions) {
this.source = source;
@ -47,6 +48,7 @@ export class Validator {
this.methods = new Map();
this.helpers = new Map();
this.transitions = new Map();
this.slots = new Set();
}
error(message: string, pos: number) {

@ -8,12 +8,13 @@ describe("validate", () => {
// add .solo to a sample directory name to only run that test
const solo = /\.solo/.test(dir);
const skip = /\.skip/.test(dir);
if (solo && process.env.CI) {
throw new Error("Forgot to remove `solo: true` from test");
}
(solo ? it.only : it)(dir, () => {
(solo ? it.only : skip ? it.skip : it)(dir, () => {
const filename = `test/validator/samples/${dir}/input.html`;
const input = fs.readFileSync(filename, "utf-8").replace(/\s+$/, "");

@ -0,0 +1,8 @@
[{
"message": "duplicate default <slot> element",
"loc": {
"line": 2,
"column": 0
},
"pos": 14
}]

@ -0,0 +1,8 @@
[{
"message": "default is a reserved word — it cannot be used as a slot name",
"loc": {
"line": 1,
"column": 6
},
"pos": 6
}]

@ -0,0 +1,8 @@
[{
"message": "slot attribute cannot have a dynamic value",
"loc": {
"line": 2,
"column": 9
},
"pos": 18
}]

@ -0,0 +1,3 @@
<Nested>
<button slot='{{foo}}'>click me</button>
</Nested>

@ -0,0 +1,8 @@
[{
"message": "<slot> name cannot be dynamic",
"loc": {
"line": 1,
"column": 6
},
"pos": 6
}]

@ -0,0 +1,8 @@
[{
"message": "<slot> cannot be a child of an each-block",
"loc": {
"line": 2,
"column": 1
},
"pos": 27
}]

@ -0,0 +1,3 @@
{{#each things as thing}}
<slot name='foo'></slot>
{{/each}}

@ -0,0 +1,8 @@
[{
"message": "duplicate 'foo' <slot> element",
"loc": {
"line": 2,
"column": 6
},
"pos": 31
}]

@ -0,0 +1,2 @@
<slot name='foo'></slot>
<slot name='foo'></slot>

@ -0,0 +1,8 @@
[{
"message": "<slot> elements cannot be nested",
"loc": {
"line": 2,
"column": 1
},
"pos": 8
}]

@ -0,0 +1,3 @@
<slot>
<slot name='foo'></slot>
</slot>
Loading…
Cancel
Save