mirror of https://github.com/sveltejs/svelte
parent
e5615f30f9
commit
9cf08e4597
@ -1,212 +1,59 @@
|
|||||||
import { Parser } from '../index';
|
import { Parser } from "../index";
|
||||||
import { reserved } from '../../utils/names';
|
import { isIdentifierStart } from "acorn";
|
||||||
|
import full_char_code_at from "../../utils/full_char_code_at";
|
||||||
interface Identifier {
|
import {
|
||||||
start: number;
|
is_bracket_open,
|
||||||
end: number;
|
is_bracket_close,
|
||||||
type: 'Identifier';
|
is_bracket_pair,
|
||||||
name: string;
|
get_bracket_close
|
||||||
}
|
} from "../utils/bracket";
|
||||||
|
import { parse_expression_at } from "../acorn";
|
||||||
interface Property {
|
import { Pattern } from "estree";
|
||||||
start: number;
|
|
||||||
end: number;
|
export default function read_context(parser: Parser): Pattern {
|
||||||
type: 'Property';
|
|
||||||
kind: 'init' | 'rest';
|
|
||||||
shorthand: boolean;
|
|
||||||
key: Identifier;
|
|
||||||
value: Context;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface RestElement {
|
|
||||||
start: number;
|
|
||||||
end: number;
|
|
||||||
type: 'RestElement';
|
|
||||||
argument: Identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Context {
|
|
||||||
start: number;
|
|
||||||
end: number;
|
|
||||||
type: 'Identifier' | 'ArrayPattern' | 'ObjectPattern' | 'RestElement';
|
|
||||||
name?: string;
|
|
||||||
argument?: Context;
|
|
||||||
elements?: Context[];
|
|
||||||
properties?: Array<Property|RestElement>;
|
|
||||||
}
|
|
||||||
|
|
||||||
function error_on_assignment_pattern(parser: Parser) {
|
|
||||||
if (parser.eat('=')) {
|
|
||||||
parser.error({
|
|
||||||
code: 'invalid-assignment-pattern',
|
|
||||||
message: 'Assignment patterns are not supported'
|
|
||||||
}, parser.index - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function error_on_rest_pattern_not_last(parser: Parser) {
|
|
||||||
parser.error({
|
|
||||||
code: 'rest-pattern-not-last',
|
|
||||||
message: 'Rest destructuring expected to be last'
|
|
||||||
}, parser.index);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function read_context(parser: Parser) {
|
|
||||||
const context: Context = {
|
|
||||||
start: parser.index,
|
|
||||||
end: null,
|
|
||||||
type: null
|
|
||||||
};
|
|
||||||
|
|
||||||
if (parser.eat('[')) {
|
|
||||||
context.type = 'ArrayPattern';
|
|
||||||
context.elements = [];
|
|
||||||
|
|
||||||
do {
|
|
||||||
parser.allow_whitespace();
|
|
||||||
|
|
||||||
const lastContext = context.elements[context.elements.length - 1];
|
|
||||||
if (lastContext && lastContext.type === 'RestElement') {
|
|
||||||
error_on_rest_pattern_not_last(parser);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parser.template[parser.index] === ',') {
|
|
||||||
context.elements.push(null);
|
|
||||||
} else {
|
|
||||||
context.elements.push(read_context(parser));
|
|
||||||
parser.allow_whitespace();
|
|
||||||
}
|
|
||||||
} while (parser.eat(','));
|
|
||||||
|
|
||||||
error_on_assignment_pattern(parser);
|
|
||||||
parser.eat(']', true);
|
|
||||||
context.end = parser.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (parser.eat('{')) {
|
|
||||||
context.type = 'ObjectPattern';
|
|
||||||
context.properties = [];
|
|
||||||
|
|
||||||
do {
|
|
||||||
parser.allow_whitespace();
|
|
||||||
|
|
||||||
if (parser.eat('...')) {
|
|
||||||
parser.allow_whitespace();
|
|
||||||
|
|
||||||
const start = parser.index;
|
const start = parser.index;
|
||||||
const name = parser.read_identifier();
|
let i = parser.index;
|
||||||
const key: Identifier = {
|
|
||||||
start,
|
|
||||||
end: parser.index,
|
|
||||||
type: 'Identifier',
|
|
||||||
name
|
|
||||||
};
|
|
||||||
const property: RestElement = {
|
|
||||||
start,
|
|
||||||
end: parser.index,
|
|
||||||
type: 'RestElement',
|
|
||||||
argument: key,
|
|
||||||
};
|
|
||||||
|
|
||||||
context.properties.push(property);
|
|
||||||
|
|
||||||
parser.allow_whitespace();
|
const code = full_char_code_at(parser.template, i);
|
||||||
|
if (isIdentifierStart(code, true)) {
|
||||||
if (parser.eat(',')) {
|
return { type: "Identifier", name: parser.read_identifier() };
|
||||||
parser.error({
|
|
||||||
code: `comma-after-rest`,
|
|
||||||
message: `Comma is not permitted after the rest element`
|
|
||||||
}, parser.index - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
if (!is_bracket_open(code)) {
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: DRY this out somehow
|
|
||||||
// We don't know whether we want to allow reserved words until we see whether there's a ':' after it
|
|
||||||
// Probably ideally we'd use Acorn to do all of this
|
|
||||||
const start = parser.index;
|
|
||||||
const name = parser.read_identifier(true);
|
|
||||||
const key: Identifier = {
|
|
||||||
start,
|
|
||||||
end: parser.index,
|
|
||||||
type: 'Identifier',
|
|
||||||
name
|
|
||||||
};
|
|
||||||
parser.allow_whitespace();
|
|
||||||
|
|
||||||
let value: Context;
|
|
||||||
if (parser.eat(':')) {
|
|
||||||
parser.allow_whitespace();
|
|
||||||
value = read_context(parser);
|
|
||||||
} else {
|
|
||||||
if (reserved.has(name)) {
|
|
||||||
parser.error({
|
parser.error({
|
||||||
code: `unexpected-reserved-word`,
|
code: "unexpected-token",
|
||||||
message: `'${name}' is a reserved word in JavaScript and cannot be used here`
|
message: "Expected identifier or destructure pattern"
|
||||||
}, start);
|
});
|
||||||
}
|
|
||||||
value = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
const property: Property = {
|
|
||||||
start,
|
|
||||||
end: value.end,
|
|
||||||
type: 'Property',
|
|
||||||
kind: 'init',
|
|
||||||
shorthand: value.type === 'Identifier' && value.name === name,
|
|
||||||
key,
|
|
||||||
value
|
|
||||||
};
|
|
||||||
|
|
||||||
context.properties.push(property);
|
|
||||||
|
|
||||||
parser.allow_whitespace();
|
|
||||||
} while (parser.eat(','));
|
|
||||||
|
|
||||||
error_on_assignment_pattern(parser);
|
|
||||||
parser.eat('}', true);
|
|
||||||
context.end = parser.index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (parser.eat('...')) {
|
const bracket_stack = [code];
|
||||||
const name = parser.read_identifier();
|
i += code <= 0xffff ? 1 : 2;
|
||||||
if (name) {
|
|
||||||
context.type = 'RestElement';
|
|
||||||
context.end = parser.index;
|
|
||||||
context.argument = {
|
|
||||||
type: 'Identifier',
|
|
||||||
start: context.start + 3,
|
|
||||||
end: parser.index,
|
|
||||||
name,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
while (i < parser.template.length) {
|
||||||
|
const code = full_char_code_at(parser.template, i);
|
||||||
|
if (is_bracket_open(code)) {
|
||||||
|
bracket_stack.push(code);
|
||||||
|
} else if (is_bracket_close(code)) {
|
||||||
|
if (!is_bracket_pair(bracket_stack[bracket_stack.length - 1], code)) {
|
||||||
parser.error({
|
parser.error({
|
||||||
code: 'invalid-context',
|
code: "unexpected-token",
|
||||||
message: 'Expected a rest pattern'
|
message: `Expected ${String.fromCharCode(
|
||||||
|
get_bracket_close(bracket_stack[bracket_stack.length - 1])
|
||||||
|
)}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
bracket_stack.pop();
|
||||||
|
if (bracket_stack.length === 0) {
|
||||||
|
i += code <= 0xffff ? 1 : 2;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
|
||||||
const name = parser.read_identifier();
|
|
||||||
if (name) {
|
|
||||||
context.type = 'Identifier';
|
|
||||||
context.end = parser.index;
|
|
||||||
context.name = name;
|
|
||||||
}
|
}
|
||||||
|
i += code <= 0xffff ? 1 : 2;
|
||||||
else {
|
|
||||||
parser.error({
|
|
||||||
code: 'invalid-context',
|
|
||||||
message: 'Expected a name, array pattern or object pattern'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error_on_assignment_pattern(parser);
|
parser.index = i;
|
||||||
}
|
|
||||||
|
|
||||||
return context;
|
const pattern_string = parser.template.slice(start, i);
|
||||||
|
return (parse_expression_at(`${' '.repeat(start - 1)}(${pattern_string} = 1)`, start - 1) as any)
|
||||||
|
.left as Pattern;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
<script>
|
||||||
|
export let animalEntries;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#each animalEntries as { animal, species = 'unknown', kilogram: weight = 50 , ...props } }
|
||||||
|
<p {...props}>{animal} - {species} - {weight}kg</p>
|
||||||
|
{/each}
|
Loading…
Reference in new issue