pull/9754/head
Simon Holthausen 3 years ago
parent 8b084cdca0
commit 5b7081fd81

@ -24,7 +24,7 @@ const internal = {
const parse = {
/** @param {string} name */
'unclosed-element': (name) => `<${name}> was left open`,
'unclosed-block': () => `block was left open`,
'unclosed-block': () => `Block was left open`,
'unexpected-block-close': () => `Unexpected block closing tag`,
'unexpected-eof': () => `Unexpected end of input`,
/** @param {string} message */

@ -77,8 +77,10 @@ export class Parser {
const current = this.current();
if (current.type === 'RegularElement') {
current.end = current.start + 1;
error(current, 'unclosed-element', current.name);
} else {
current.end = current.start + 1;
error(current, 'unclosed-block');
}
}

@ -202,11 +202,12 @@ export default function tag(parser) {
let attribute;
while ((attribute = read(parser))) {
if (
(attribute.type === 'Attribute' || attribute.type === 'BindDirective') &&
unique_names.includes(attribute.name)
) {
error(attribute.start, 'duplicate-attribute');
if (attribute.type === 'Attribute' || attribute.type === 'BindDirective') {
if (unique_names.includes(attribute.name)) {
error(attribute.start, 'duplicate-attribute');
} else {
unique_names.push(attribute.name);
}
}
element.attributes.push(attribute);
@ -635,13 +636,14 @@ function read_attribute_value(parser) {
'in attribute value'
);
} catch (/** @type {any} e */ e) {
if (e.code === 'parse-error') {
if (e.code === 'js-parse-error') {
// if the attribute value didn't close + self-closing tag
// eg: `<Component test={{a:1} />`
// acorn may throw a `Unterminated regular expression` because of `/>`
if (parser.template.slice(e.pos - 1, e.pos + 1) === '/>') {
parser.index = e.pos;
error(e.pos, 'unclosed-attribute-value', quote_mark || '}');
const pos = e.position?.[0];
if (pos !== undefined && parser.template.slice(pos - 1, pos + 1) === '/>') {
parser.index = pos;
error(pos, 'unclosed-attribute-value', quote_mark || '}');
}
}
throw e;

@ -4,6 +4,6 @@ export default test({
error: {
code: 'invalid-state-location',
message: '$state() can only be used as a variable declaration initializer or a class field',
position: process.platform === 'win32' ? [35, 43] : [33, 41]
position: [33, 41]
}
});

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'css-syntax-error',
code: 'invalid-css-identifier',
message: ':global() must contain a selector',
position: [9, 9]
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'css-syntax-error',
code: 'invalid-css-identifier',
message: '"{" is expected',
position: [24, 24]
}

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'empty-directive-name',
message: 'Class name cannot be empty',
message: 'ClassDirective name cannot be empty',
position: [10, 10]
}
});

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'empty-directive-name',
message: 'Action name cannot be empty',
message: 'UseDirective name cannot be empty',
position: [8, 8]
}
});

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'parse-error',
code: 'js-parse-error',
message: 'Assigning to rvalue',
position: [1, 1]
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'duplicate-style',
code: 'duplicate-style-element',
message: 'You can only have one top-level <style> tag per component',
position: [58, 58]
}

@ -4,7 +4,7 @@ export default test({
error: {
code: 'invalid-self-placement',
message:
'<svelte:self> components can only exist inside {#if} blocks, {#each} blocks,, {#snippet} blocks or slots passed to components',
'<svelte:self> components can only exist inside {#if} blocks, {#each} blocks, {#snippet} blocks or slots passed to components',
position: [1, 1]
}
});

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid-tag-name',
code: 'invalid-svelte-tag',
message:
'Valid <svelte:...> tag names are svelte:head, svelte:options, svelte:window, svelte:document, svelte:body, svelte:self, svelte:component, svelte:fragment or svelte:element',
position: [10, 10]

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'unclosed-attribute-value',
message: 'Expected to close the attribute value with }',
position: [25, 25]
message: 'Expected closing } character',
position: [19, 19]
}
});

@ -4,6 +4,6 @@ export default test({
error: {
code: 'unclosed-block',
message: 'Block was left open',
position: [0, 0]
position: [0, 1]
}
});

@ -4,6 +4,6 @@ export default test({
error: {
code: 'unclosed-element',
message: '<div> was left open',
position: [0, 0]
position: [0, 1]
}
});

@ -2,8 +2,8 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid-closing-tag',
message: '</p> attempted to close <p> that was already automatically closed by <pre>',
code: 'invalid-closing-tag-after-autoclose',
message: '</p> attempted to close element that was already automatically closed by <pre>',
position: [24, 24]
}
});

@ -3,7 +3,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid-void-content',
message: '<input> is a void element and cannot have children, or a closing tag',
message: 'Void elements cannot have children or closing tags',
position: [23, 23]
}
});

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid-window-content',
code: 'invalid-element-content',
message: '<svelte:window> cannot have children',
position: [15, 15]
}

@ -2,8 +2,8 @@ import { test } from '../../test';
export default test({
error: {
code: 'duplicate-window',
message: 'A component can only have one <svelte:window> tag',
code: 'duplicate-svelte-element',
message: 'A component can only have one <svelte:window> element',
position: [17, 17]
}
});

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid-window-placement',
code: 'invalid-svelte-element-placement',
message: '<svelte:window> tags cannot be inside elements or blocks',
position: [11, 11]
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid-window-placement',
code: 'invalid-svelte-element-placement',
message: '<svelte:window> tags cannot be inside elements or blocks',
position: [7, 7]
}

@ -2,6 +2,7 @@ import * as fs from 'node:fs';
import { assert, expect } from 'vitest';
import { compile, compileModule, type CompileError } from 'svelte/compiler';
import { suite, type BaseTest } from '../suite';
import { read_file } from '../helpers.js';
interface CompilerErrorTest extends BaseTest {
error: {
@ -20,7 +21,7 @@ const { test, run } = suite<CompilerErrorTest>((config, cwd) => {
let caught_error = false;
try {
compile(fs.readFileSync(`${cwd}/main.svelte`, 'utf-8'), {
compile(read_file(`${cwd}/main.svelte`), {
generate: 'client'
});
} catch (e) {
@ -45,7 +46,7 @@ const { test, run } = suite<CompilerErrorTest>((config, cwd) => {
let caught_error = false;
try {
compileModule(fs.readFileSync(`${cwd}/main.svelte.js`, 'utf-8'), {
compileModule(read_file(`${cwd}/main.svelte.js`), {
generate: 'client'
});
} catch (e) {

@ -20,13 +20,20 @@ export function try_load_json(file) {
*/
export function try_read_file(file) {
try {
return fs.readFileSync(file, 'utf-8').replace(/\r\n/g, '\n');
return read_file(file);
} catch (err) {
if (/** @type {any} */ (err).code !== 'ENOENT') throw err;
return null;
}
}
/**
* @param {string} file
*/
export function read_file(file) {
return fs.readFileSync(file, 'utf-8').replace(/\r\n/g, '\n');
}
export function create_deferred() {
/** @param {any} [value] */
let resolve = (value) => {};

Loading…
Cancel
Save