cleaning up

pull/6519/head
tanhauhau 5 years ago
parent 903d27e1ed
commit 77310c320b

@ -1,178 +1,192 @@
// All parser errors should be listed and accessed from here
import list from '../utils/list';
/**
* @internal
*/
export default {
unexpected_eof: {
code: 'unexpected-eof',
message: 'Unexpected end of input'
},
attribute_duplicate: {
css_syntax_error: (message) => ({
code: 'css-syntax-error',
message
}),
duplicate_attribute: {
code: 'duplicate-attribute',
message: 'Attributes need to be unique'
},
expected_token_equal: {
code: 'unexpected-token',
message: 'Expected ='
},
directive_value_invalid: {
code: 'invalid-directive-value',
message: 'Directive value must be a JavaScript expression enclosed in curly braces'
},
duplicate_element: (slug: string, name: string) => ({
code: `duplicate-${slug}`,
message: `A component can only have one <${name}> tag`
}),
duplicate_style: {
code: 'duplicate-style',
message: 'You can only have one top-level <style> tag per component'
},
duplicate_instance_script: () => ({
code: 'invalid-script',
message: 'A component can only have one instance-level <script> element'
empty_attribute_shorthand: {
code: 'empty-attribute-shorthand',
message: 'Attribute shorthand cannot be empty'
},
empty_directive_name: (type: string) => ({
code: 'empty-directive-name',
message: `${type} name cannot be empty`
}),
duplicate_module_script: () => ({
code: 'invalid-script',
message: 'A component can only have one <script context="module"> element'
empty_global_selector: {
code: 'css-syntax-error',
message: ':global() must contain a selector'
},
expected_block_type: {
code: 'expected-block-type',
message: 'Expected if, each or await'
},
expected_name: {
code: 'expected-name',
message: 'Expected name'
},
invalid_catch_placement_unclosed_block: (block) => ({
code: 'invalid-catch-placement',
message: `Expected to close ${block} before seeing {:catch} block`
}),
dynamic_context_attribute: () => ({
code: 'invalid-script',
message: 'context attribute must be static'
invalid_catch_placement_without_await: {
code: 'invalid-catch-placement',
message: 'Cannot have an {:catch} block outside an {#await ...} block'
},
invalid_component_definition: {
code: 'invalid-component-definition',
message: 'invalid component definition'
},
invalid_closing_tag_unopened: (name: string) => ({
code: 'invalid-closing-tag',
message: `</${name}> attempted to close an element that was not open`
}),
fixed_context_attribute: () => ({
code: 'invalid-script',
message: 'If the context attribute is supplied, its value must be "module"'
invalid_closing_tag_autoclosed: (name: string, reason: string) => ({
code: 'invalid-closing-tag',
message: `</${name}> attempted to close <${name}> that was already automatically closed by <${reason}>`
}),
invalid_debug_args: {
code: 'invalid-debug-args',
message:
'{@debug ...} arguments must be identifiers, not arbitrary expressions'
},
invalid_declaration: {
code: 'invalid-declaration',
message: 'Declaration cannot be empty'
},
invalid_directive_value: {
code: 'invalid-directive-value',
message: 'Directive value must be a JavaScript expression enclosed in curly braces'
},
invalid_elseif: {
code: 'invalid-elseif',
message: '\'elseif\' should be \'else if\''
},
else_if_without_if: {
invalid_elseif_placement_outside_if: {
code: 'invalid-elseif-placement',
message: 'Cannot have an {:else if ...} block outside an {#if ...} block'
},
else_if_before_block_close: (block) => ({
invalid_elseif_placement_unclosed_block: (block) => ({
code: 'invalid-elseif-placement',
message: `Expected to close ${block} before seeing {:else if ...} block`
}),
else_without_if_each: () => ({
invalid_else_placement_outside_if: {
code: 'invalid-else-placement',
message: 'Cannot have an {:else} block outside an {#if ...} or {#each ...} block'
}),
else_before_block_close: (block) => ({
},
invalid_else_placement_unclosed_block: (block) => ({
code: 'invalid-else-placement',
message: `Expected to close ${block} before seeing {:else} block`
}),
then_before_close_block: (block) => ({
code: 'invalid-then-placement',
message: `Expected to close ${block} before seeing {:then} block`
invalid_element_content: (slug: string, name: string) => ({
code: `invalid-${slug}-content`,
message: `<${name}> cannot have children`
}),
then_without_await: {
code: 'invalid-then-placement',
message: 'Cannot have an {:then} block outside an {#await ...} block'
},
catch_before_close_block: (block) => ({
code: 'invalid-catch-placement',
message: `Expected to close ${block} before seeing {:catch} block`
invalid_element_placement: (slug: string, name: string) => ({
code: `invalid-${slug}-placement`,
message: `<${name}> tags cannot be inside elements or blocks`
}),
catch_without_await: {
code: 'invalid-catch-placement',
message: 'Cannot have an {:catch} block outside an {#await ...} block'
invalid_ref_directive: (name: string) => ({
code: 'invalid-ref-directive',
message: `The ref directive is no longer supported — use \`bind:this={${name}}\` instead`
}),
invalid_ref_selector: {
code: 'invalid-ref-selector',
message: 'ref selectors are no longer supported'
},
component_definition_invalid: {
code: 'invalid-component-definition',
message: 'invalid component definition'
invalid_self_placement: {
code: 'invalid-self-placement',
message: '<svelte:self> components can only exist inside {#if} blocks, {#each} blocks, or slots passed to components'
},
component_definition_missing: {
code: 'missing-component-definition',
message: '<svelte:component> must have a \'this\' attribute'
invalid_script_instance: {
code: 'invalid-script',
message: 'A component can only have one instance-level <script> element'
},
expected_block_type: {
code: 'expected-block-type',
message: 'Expected if, each or await'
invalid_script_module: {
code: 'invalid-script',
message: 'A component can only have one <script context="module"> element'
},
expected_name: {
code: 'expected-name',
message: 'Expected name'
invalid_script_context_attribute: {
code: 'invalid-script',
message: 'context attribute must be static'
},
unexpected_block_close: {
code: 'unexpected-block-close',
message: 'Unexpected block closing tag'
invalid_script_context_value: {
code: 'invalid-script',
message: 'If the context attribute is supplied, its value must be "module"'
},
debug_args: () => ({
code: 'invalid-debug-args',
message:
'{@debug ...} arguments must be identifiers, not arbitrary expressions'
}),
element_unopened: (name) => ({
code: 'invalid-closing-tag',
message: `</${name}> attempted to close an element that was not open`
}),
element_autoclosed: (name, reason) => ({
code: 'invalid-closing-tag',
message: `</${name}> attempted to close <${name}> that was already automatically closed by <${reason}>`
}),
element_tag_name_invalid: {
invalid_tag_name: {
code: 'invalid-tag-name',
message: 'Expected valid tag name'
},
meta_no_children: (slug, name) => ({
code: `invalid-${slug}-content`,
message: `<${name}> cannot have children`
}),
meta_duplicate: (slug, name) => ({
code: `duplicate-${slug}`,
message: `A component can only have one <${name}> tag`
}),
meta_top_level: (slug, name) => ({
code: `invalid-${slug}-placement`,
message: `<${name}> tags cannot be inside elements or blocks`
}),
self_placement_invalid: {
code: 'invalid-self-placement',
message: '<svelte:self> components can only exist inside {#if} blocks, {#each} blocks, or slots passed to components'
},
meta_tag_name_invalid: (tags, match) => ({
invalid_tag_name_svelte_element: (tags: string[], match: string) => ({
code: 'invalid-tag-name',
message: `Valid <svelte:...> tag names are ${tags}${
message: `Valid <svelte:...> tag names are ${list(tags)}${
match ? ' (did you mean ' + match + '?)' : ''
}`
}),
ref_directive_invalid: (name) => ({
code: 'invalid-ref-directive',
message: `The ref directive is no longer supported — use \`bind:this={${name}}\` instead`
invalid_then_placement_unclosed_block: (block) => ({
code: 'invalid-then-placement',
message: `Expected to close ${block} before seeing {:then} block`
}),
void_no_children: (name) => ({
invalid_then_placement_without_await: {
code: 'invalid-then-placement',
message: 'Cannot have an {:then} block outside an {#await ...} block'
},
invalid_void_content: (name: string) => ({
code: 'invalid-void-content',
message: `<${name}> is a void element and cannot have children, or a closing tag`
}),
unclosed_script: () => ({
missing_component_definition: {
code: 'missing-component-definition',
message: '<svelte:component> must have a \'this\' attribute'
},
unclosed_script: {
code: 'unclosed-script',
message: '<script> must have a closing tag'
}),
unclosed_style: () => ({
},
unclosed_style: {
code: 'unclosed-style',
message: '<style> must have a closing tag'
}),
unclosed_comment: () => ({
},
unclosed_comment: {
code: 'unclosed-comment',
message: 'comment was left open, expected -->'
},
unexpected_block_close: {
code: 'unexpected-block-close',
message: 'Unexpected block closing tag'
},
unexpected_eof: {
code: 'unexpected-eof',
message: 'Unexpected end of input'
},
unexpected_eof_token: (token: string) => ({
code: 'unexpected-eof',
message: `Unexpected ${token}`
}),
unexpected_token: () => ({
unexpected_token: (token: string) => ({
code: 'unexpected-token',
message: 'Expected )'
}),
invalid_ref_selector: () => ({
code: 'invalid-ref-selector',
message: 'ref selectors are no longer supported'
message: `Expected ${token}`
}),
invalid_declaration: () => ({
code: 'invalid-declaration',
message: 'Declaration cannot be empty'
}),
empty_global_selector: () => ({
code: 'css-syntax-error',
message: ':global() must contain a selector'
}),
syntax_error: (message) => ({
code: 'css-syntax-error',
message
})
unexpected_token_destructure: {
code: 'unexpected-token',
message: 'Expected identifier or destructure pattern'
}
};

@ -107,17 +107,18 @@ export class Parser {
});
}
eat(str: string, required?: boolean, message?: string) {
eat(str: string, required?: boolean, error?: { code: string, message: string }) {
if (this.match(str)) {
this.index += str.length;
return true;
}
if (required) {
this.error({
code: `unexpected-${this.index === this.template.length ? 'eof' : 'token'}`,
message: message || `Expected ${str}`
});
this.error(error ||
(this.index === this.template.length
? parser_errors.unexpected_eof_token(str)
: parser_errors.unexpected_token(str))
);
}
return false;
@ -226,11 +227,11 @@ export default function parse(
const module_scripts = parser.js.filter(script => script.context === 'module');
if (instance_scripts.length > 1) {
parser.error(parser_errors.duplicate_instance_script(), instance_scripts[1].start);
parser.error(parser_errors.invalid_script_instance, instance_scripts[1].start);
}
if (module_scripts.length > 1) {
parser.error(parser_errors.duplicate_module_script(), module_scripts[1].start);
parser.error(parser_errors.invalid_script_module, module_scripts[1].start);
}
return {

@ -9,6 +9,7 @@ import {
} from '../utils/bracket';
import { parse_expression_at } from '../acorn';
import { Pattern } from 'estree';
import parser_errors from '../errors';
export default function read_context(
parser: Parser
@ -27,10 +28,7 @@ export default function read_context(
}
if (!is_bracket_open(code)) {
parser.error({
code: 'unexpected-token',
message: 'Expected identifier or destructure pattern'
});
parser.error(parser_errors.unexpected_token_destructure);
}
const bracket_stack = [code];
@ -42,12 +40,11 @@ export default function read_context(
bracket_stack.push(code);
} else if (is_bracket_close(code)) {
if (!is_bracket_pair(bracket_stack[bracket_stack.length - 1], code)) {
parser.error({
code: 'unexpected-token',
message: `Expected ${String.fromCharCode(
get_bracket_close(bracket_stack[bracket_stack.length - 1])
)}`
});
parser.error(
parser_errors.unexpected_token(
String.fromCharCode(get_bracket_close(bracket_stack[bracket_stack.length - 1]))
)
);
}
bracket_stack.pop();
if (bracket_stack.length === 0) {

@ -2,6 +2,7 @@ import { parse_expression_at } from '../acorn';
import { Parser } from '../index';
import { Node } from 'estree';
import { whitespace } from '../../utils/patterns';
import parser_errors from '../errors';
export default function read_expression(parser: Parser): Node {
try {
@ -20,10 +21,7 @@ export default function read_expression(parser: Parser): Node {
if (char === ')') {
num_parens -= 1;
} else if (!whitespace.test(char)) {
parser.error({
code: 'unexpected-token',
message: 'Expected )'
}, index);
parser.error(parser_errors.unexpected_token(')'), index);
}
index += 1;

@ -9,13 +9,13 @@ function get_context(parser: Parser, attributes: any[], start: number): string {
if (!context) return 'default';
if (context.value.length !== 1 || context.value[0].type !== 'Text') {
parser.error(parser_errors.dynamic_context_attribute(), start);
parser.error(parser_errors.invalid_script_context_attribute, start);
}
const value = context.value[0].data;
if (value !== 'module') {
parser.error(parser_errors.fixed_context_attribute(), context.start);
parser.error(parser_errors.invalid_script_context_value, context.start);
}
return value;
@ -23,10 +23,9 @@ function get_context(parser: Parser, attributes: any[], start: number): string {
export default function read_script(parser: Parser, start: number, attributes: Node[]): Script {
const script_start = parser.index;
const error_message = parser_errors.unclosed_script();
const data = parser.read_until(/<\/script\s*>/, error_message);
const data = parser.read_until(/<\/script\s*>/, parser_errors.unclosed_script);
if (parser.index >= parser.template.length) {
parser.error(error_message);
parser.error(parser_errors.unclosed_script);
}
const source = parser.template.slice(0, script_start).replace(/[^\n]/g, ' ') + data;

@ -7,12 +7,11 @@ import parser_errors from '../errors';
export default function read_style(parser: Parser, start: number, attributes: Node[]): Style {
const content_start = parser.index;
const error_message = parser_errors.unclosed_style();
const styles = parser.read_until(/<\/style\s*>/, error_message);
const styles = parser.read_until(/<\/style\s*>/, parser_errors.unclosed_style);
if (parser.index >= parser.template.length) {
parser.error(error_message);
parser.error(parser_errors.unclosed_style);
}
const content_end = parser.index;
@ -29,7 +28,7 @@ export default function read_style(parser: Parser, start: number, attributes: No
});
} catch (err) {
if (err.name === 'SyntaxError') {
parser.error(parser_errors.syntax_error(err.message), err.offset);
parser.error(parser_errors.css_syntax_error(err.message), err.offset);
} else {
throw err;
}
@ -47,17 +46,17 @@ export default function read_style(parser: Parser, start: number, attributes: No
const b = node.children[i + 1];
if (is_ref_selector(a, b)) {
parser.error(parser_errors.invalid_ref_selector(), a.loc.start.offset);
parser.error(parser_errors.invalid_ref_selector, a.loc.start.offset);
}
}
}
if (node.type === 'Declaration' && node.value.type === 'Value' && node.value.children.length === 0) {
parser.error(parser_errors.invalid_declaration(), node.start);
parser.error(parser_errors.invalid_declaration, node.start);
}
if (node.type === 'PseudoClassSelector' && node.name === 'global' && node.children === null) {
parser.error(parser_errors.empty_global_selector(), node.loc.start.offset);
parser.error(parser_errors.empty_global_selector, node.loc.start.offset);
}
if (node.loc) {

@ -107,8 +107,8 @@ export default function mustache(parser: Parser) {
if (block.type !== 'IfBlock') {
parser.error(
parser.stack.some(block => block.type === 'IfBlock')
? parser_errors.else_if_before_block_close(to_string(block))
: parser_errors.else_if_without_if
? parser_errors.invalid_elseif_placement_unclosed_block(to_string(block))
: parser_errors.invalid_elseif_placement_outside_if
);
}
@ -142,8 +142,8 @@ export default function mustache(parser: Parser) {
if (block.type !== 'IfBlock' && block.type !== 'EachBlock') {
parser.error(
parser.stack.some(block => block.type === 'IfBlock' || block.type === 'EachBlock')
? parser_errors.else_before_block_close(to_string(block))
: parser_errors.else_without_if_each()
? parser_errors.invalid_else_placement_unclosed_block(to_string(block))
: parser_errors.invalid_else_placement_outside_if
);
}
@ -167,15 +167,15 @@ export default function mustache(parser: Parser) {
if (block.type !== 'PendingBlock') {
parser.error(
parser.stack.some(block => block.type === 'PendingBlock')
? parser_errors.then_before_close_block(to_string(block))
: parser_errors.then_without_await
? parser_errors.invalid_then_placement_unclosed_block(to_string(block))
: parser_errors.invalid_then_placement_without_await
);
}
} else {
if (block.type !== 'ThenBlock' && block.type !== 'PendingBlock') {
parser.error(parser.stack.some(block => block.type === 'ThenBlock' || block.type === 'PendingBlock')
? parser_errors.catch_before_close_block(to_string(block))
: parser_errors.catch_without_await
? parser_errors.invalid_catch_placement_unclosed_block(to_string(block))
: parser_errors.invalid_catch_placement_without_await
);
}
}
@ -353,7 +353,7 @@ export default function mustache(parser: Parser) {
identifiers.forEach(node => {
if (node.type !== 'Identifier') {
parser.error(parser_errors.debug_args(), node.start);
parser.error(parser_errors.invalid_debug_args, node.start);
}
});

@ -6,7 +6,6 @@ import { is_void } from '../../utils/names';
import { Parser } from '../index';
import { Directive, DirectiveType, TemplateNode, Text } from '../../interfaces';
import fuzzymatch from '../../utils/fuzzymatch';
import list from '../../utils/list';
import parser_errors from '../errors';
// eslint-disable-next-line no-useless-escape
@ -59,7 +58,7 @@ export default function tag(parser: Parser) {
if (parser.eat('!--')) {
const data = parser.read_until(/-->/);
parser.eat('-->', true, 'comment was left open, expected -->');
parser.eat('-->', true, parser_errors.unclosed_comment);
parser.current().children.push({
start,
@ -83,17 +82,17 @@ export default function tag(parser: Parser) {
parser.current().children.length
) {
parser.error(
parser_errors.meta_no_children(slug, name),
parser_errors.invalid_element_content(slug, name),
parser.current().children[0].start
);
}
} else {
if (name in parser.meta_tags) {
parser.error(parser_errors.meta_duplicate(slug, name), start);
parser.error(parser_errors.duplicate_element(slug, name), start);
}
if (parser.stack.length > 1) {
parser.error(parser_errors.meta_top_level(slug, name), start);
parser.error(parser_errors.invalid_element_placement(slug, name), start);
}
parser.meta_tags[name] = true;
@ -120,7 +119,7 @@ export default function tag(parser: Parser) {
if (is_closing_tag) {
if (is_void(name)) {
parser.error(parser_errors.void_no_children(name), start);
parser.error(parser_errors.invalid_void_content(name), start);
}
parser.eat('>', true);
@ -129,8 +128,8 @@ export default function tag(parser: Parser) {
while (parent.name !== name) {
if (parent.type !== 'Element') {
const error = parser.last_auto_closed_tag && parser.last_auto_closed_tag.tag === name
? parser_errors.element_autoclosed(name, parser.last_auto_closed_tag.reason)
: parser_errors.element_unopened(name);
? parser_errors.invalid_closing_tag_autoclosed(name, parser.last_auto_closed_tag.reason)
: parser_errors.invalid_closing_tag_unopened(name);
parser.error(error, start);
}
@ -169,12 +168,12 @@ export default function tag(parser: Parser) {
if (name === 'svelte:component') {
const index = element.attributes.findIndex(attr => attr.type === 'Attribute' && attr.name === 'this');
if (!~index) {
parser.error(parser_errors.component_definition_missing, start);
parser.error(parser_errors.missing_component_definition, start);
}
const definition = element.attributes.splice(index, 1)[0];
if (definition.value === true || definition.value.length !== 1 || definition.value[0].type === 'Text') {
parser.error(parser_errors.component_definition_invalid, definition.start);
parser.error(parser_errors.invalid_component_definition, definition.start);
}
element.expression = definition.value[0].expression;
@ -239,7 +238,7 @@ function read_tag_name(parser: Parser) {
}
if (!legal) {
parser.error(parser_errors.self_placement_invalid, start);
parser.error(parser_errors.invalid_self_placement, start);
}
return 'svelte:self';
@ -257,13 +256,13 @@ function read_tag_name(parser: Parser) {
const match = fuzzymatch(name.slice(7), valid_meta_tags);
parser.error(
parser_errors.meta_tag_name_invalid(list(valid_meta_tags), match),
parser_errors.invalid_tag_name_svelte_element(valid_meta_tags, match),
start
);
}
if (!valid_tag_name.test(name)) {
parser.error(parser_errors.element_tag_name_invalid, start);
parser.error(parser_errors.invalid_tag_name, start);
}
return name;
@ -274,7 +273,7 @@ function read_attribute(parser: Parser, unique_names: Set<string>) {
function check_unique(name: string) {
if (unique_names.has(name)) {
parser.error(parser_errors.attribute_duplicate, start);
parser.error(parser_errors.duplicate_attribute, start);
}
unique_names.add(name);
}
@ -302,10 +301,7 @@ function read_attribute(parser: Parser, unique_names: Set<string>) {
parser.eat('}', true);
if (name === null) {
parser.error({
code: 'empty-attribute-shorthand',
message: 'Attribute shorthand cannot be empty'
}, start);
parser.error(parser_errors.empty_attribute_shorthand, start);
}
check_unique(name);
@ -347,17 +343,14 @@ function read_attribute(parser: Parser, unique_names: Set<string>) {
value = read_attribute_value(parser);
end = parser.index;
} else if (parser.match_regex(/["']/)) {
parser.error(parser_errors.expected_token_equal, parser.index);
parser.error(parser_errors.unexpected_token('='), parser.index);
}
if (type) {
const [directive_name, ...modifiers] = name.slice(colon_index + 1).split('|');
if (directive_name === '') {
parser.error({
code: 'empty-directive-name',
message: `${type} name cannot be empty`
}, start + colon_index + 1);
parser.error(parser_errors.empty_directive_name(type), start + colon_index + 1);
}
if (type === 'Binding' && directive_name !== 'this') {
@ -367,12 +360,12 @@ function read_attribute(parser: Parser, unique_names: Set<string>) {
}
if (type === 'Ref') {
parser.error(parser_errors.ref_directive_invalid(directive_name), start);
parser.error(parser_errors.invalid_ref_directive(directive_name), start);
}
if (value[0]) {
if ((value as any[]).length > 1 || value[0].type === 'Text') {
parser.error(parser_errors.directive_value_invalid, value[0].start);
parser.error(parser_errors.invalid_directive_value, value[0].start);
}
}

@ -1,5 +1,5 @@
{
"code": "unexpected-eof",
"code": "unclosed-comment",
"message": "comment was left open, expected -->",
"start": {
"line": 1,

Loading…
Cancel
Save