diff --git a/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap b/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap
new file mode 100644
index 00000000..ce41e304
--- /dev/null
+++ b/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap
@@ -0,0 +1,7392 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`parser/parse invalid html 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 1,
+ "line": 3,
+ "offset": 13,
+ },
+ "source": "
+",
+ "start": Object {
+ "column": 1,
+ "line": 2,
+ "offset": 6,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "span",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 7,
+ "line": 3,
+ "offset": 19,
+ },
+ "source": "
+
+
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 8,
+ "line": 4,
+ "offset": 27,
+ },
+ "source": "
+
+
+",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option ABRUPT_CLOSING_OF_EMPTY_COMMENT 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "",
+ "loc": Object {
+ "end": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 1,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option ABRUPT_CLOSING_OF_EMPTY_COMMENT 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "",
+ "loc": Object {
+ "end": Object {
+ "column": 17,
+ "line": 1,
+ "offset": 16,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 1,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 28,
+ "line": 1,
+ "offset": 27,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 28,
+ "line": 1,
+ "offset": 27,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option ABRUPT_CLOSING_OF_EMPTY_COMMENT 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "",
+ "loc": Object {
+ "end": Object {
+ "column": 18,
+ "line": 1,
+ "offset": 17,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 1,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 29,
+ "line": 1,
+ "offset": 28,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 29,
+ "line": 1,
+ "offset": 28,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option ABSENCE_OF_DIGITS_IN_NUMERIC_CHARACTER_REFERENCE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 35,
+ "line": 1,
+ "offset": 34,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 23,
+ "line": 1,
+ "offset": 22,
+ },
+ "source": "attr=\\"c\\"",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "name": "attr",
+ "type": 3,
+ "value": Object {
+ "content": "c",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 23,
+ "line": 1,
+ "offset": 22,
+ },
+ "source": "\\"c\\"",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "type": 0,
+ },
+ },
+ ],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 35,
+ "line": 1,
+ "offset": 34,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option ABSENCE_OF_DIGITS_IN_NUMERIC_CHARACTER_REFERENCE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 34,
+ "line": 1,
+ "offset": 33,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 22,
+ "line": 1,
+ "offset": 21,
+ },
+ "source": "attr=\\"a;\\"",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "name": "attr",
+ "type": 3,
+ "value": Object {
+ "content": "a;",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 22,
+ "line": 1,
+ "offset": 21,
+ },
+ "source": "\\"a;\\"",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "type": 0,
+ },
+ },
+ ],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 34,
+ "line": 1,
+ "offset": 33,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option ABSENCE_OF_DIGITS_IN_NUMERIC_CHARACTER_REFERENCE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 36,
+ "line": 1,
+ "offset": 35,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 24,
+ "line": 1,
+ "offset": 23,
+ },
+ "source": "attr=\\"ÿ\\"",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "name": "attr",
+ "type": 3,
+ "value": Object {
+ "content": "ÿ",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 24,
+ "line": 1,
+ "offset": 23,
+ },
+ "source": "\\"ÿ\\"",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "type": 0,
+ },
+ },
+ ],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 36,
+ "line": 1,
+ "offset": 35,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option ABSENCE_OF_DIGITS_IN_NUMERIC_CHARACTER_REFERENCE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 35,
+ "line": 1,
+ "offset": 34,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 23,
+ "line": 1,
+ "offset": 22,
+ },
+ "source": "attr=\\"g;\\"",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "name": "attr",
+ "type": 3,
+ "value": Object {
+ "content": "g;",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 23,
+ "line": 1,
+ "offset": 22,
+ },
+ "source": "\\"g;\\"",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "type": 0,
+ },
+ },
+ ],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 35,
+ "line": 1,
+ "offset": 34,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option ABSENCE_OF_DIGITS_IN_NUMERIC_CHARACTER_REFERENCE c 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "c",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ "source": "c",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "c",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "c",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option ABSENCE_OF_DIGITS_IN_NUMERIC_CHARACTER_REFERENCE a; 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "a;",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 15,
+ "line": 1,
+ "offset": 14,
+ },
+ "source": "a;",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 26,
+ "line": 1,
+ "offset": 25,
+ },
+ "source": "a;",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 26,
+ "line": 1,
+ "offset": 25,
+ },
+ "source": "a;",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option ABSENCE_OF_DIGITS_IN_NUMERIC_CHARACTER_REFERENCE ÿ 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "ÿ",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 17,
+ "line": 1,
+ "offset": 16,
+ },
+ "source": "ÿ",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 28,
+ "line": 1,
+ "offset": 27,
+ },
+ "source": "ÿ",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 28,
+ "line": 1,
+ "offset": 27,
+ },
+ "source": "ÿ",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option ABSENCE_OF_DIGITS_IN_NUMERIC_CHARACTER_REFERENCE g; 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "g;",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ "source": "g;",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "g;",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "g;",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option CDATA_IN_HTML_CONTENT 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "[CDATA[cdata]]",
+ "loc": Object {
+ "end": Object {
+ "column": 28,
+ "line": 1,
+ "offset": 27,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 1,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 39,
+ "line": 1,
+ "offset": 38,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 39,
+ "line": 1,
+ "offset": 38,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option CDATA_IN_HTML_CONTENT 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "cdata",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 30,
+ "line": 1,
+ "offset": 29,
+ },
+ "source": "cdata",
+ "start": Object {
+ "column": 25,
+ "line": 1,
+ "offset": 24,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 39,
+ "line": 1,
+ "offset": 38,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 1,
+ "props": Array [],
+ "tag": "svg",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 50,
+ "line": 1,
+ "offset": 49,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 50,
+ "line": 1,
+ "offset": 49,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option CHARACTER_REFERENCE_OUTSIDE_UNICODE_RANGE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "�",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 21,
+ "line": 1,
+ "offset": 20,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 32,
+ "line": 1,
+ "offset": 31,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 32,
+ "line": 1,
+ "offset": 31,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option CONTROL_CHARACTER_REFERENCE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 18,
+ "line": 1,
+ "offset": 17,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 29,
+ "line": 1,
+ "offset": 28,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 29,
+ "line": 1,
+ "offset": 28,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option CONTROL_CHARACTER_REFERENCE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 17,
+ "line": 1,
+ "offset": 16,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 28,
+ "line": 1,
+ "offset": 27,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 28,
+ "line": 1,
+ "offset": 27,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option DUPLICATE_ATTRIBUTE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 34,
+ "line": 1,
+ "offset": 33,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 21,
+ "line": 1,
+ "offset": 20,
+ },
+ "source": "id=\\"\\"",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "name": "id",
+ "type": 3,
+ "value": Object {
+ "content": "",
+ "isEmpty": true,
+ "loc": Object {
+ "end": Object {
+ "column": 21,
+ "line": 1,
+ "offset": 20,
+ },
+ "source": "\\"\\"",
+ "start": Object {
+ "column": 19,
+ "line": 1,
+ "offset": 18,
+ },
+ },
+ "type": 0,
+ },
+ },
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "id=\\"\\"",
+ "start": Object {
+ "column": 22,
+ "line": 1,
+ "offset": 21,
+ },
+ },
+ "name": "id",
+ "type": 3,
+ "value": Object {
+ "content": "",
+ "isEmpty": true,
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "\\"\\"",
+ "start": Object {
+ "column": 25,
+ "line": 1,
+ "offset": 24,
+ },
+ },
+ "type": 0,
+ },
+ },
+ ],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 45,
+ "line": 1,
+ "offset": 44,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 45,
+ "line": 1,
+ "offset": 44,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option END_TAG_WITH_ATTRIBUTES 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 28,
+ "line": 1,
+ "offset": 27,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 39,
+ "line": 1,
+ "offset": 38,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 39,
+ "line": 1,
+ "offset": 38,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option END_TAG_WITH_TRAILING_SOLIDUS 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 23,
+ "line": 1,
+ "offset": 22,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 34,
+ "line": 1,
+ "offset": 33,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 34,
+ "line": 1,
+ "offset": 33,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option EOF_BEFORE_TAG_NAME < 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "<",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 12,
+ "line": 1,
+ "offset": 11,
+ },
+ "source": "<",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 12,
+ "line": 1,
+ "offset": 11,
+ },
+ "source": "<",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 12,
+ "line": 1,
+ "offset": 11,
+ },
+ "source": "<",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option EOF_BEFORE_TAG_NAME 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 13,
+ "line": 1,
+ "offset": 12,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 13,
+ "line": 1,
+ "offset": 12,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 13,
+ "line": 1,
+ "offset": 12,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option EOF_IN_CDATA 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "comment",
+ "loc": Object {
+ "end": Object {
+ "column": 26,
+ "line": 1,
+ "offset": 25,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 1,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 37,
+ "line": 1,
+ "offset": 36,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 37,
+ "line": 1,
+ "offset": 36,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option INCORRECTLY_OPENED_COMMENT 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "content": "DOCTYPE html",
+ "loc": Object {
+ "end": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 1,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option INCORRECTLY_OPENED_COMMENT 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "",
+ "loc": Object {
+ "end": Object {
+ "column": 14,
+ "line": 1,
+ "offset": 13,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 1,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 25,
+ "line": 1,
+ "offset": 24,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 25,
+ "line": 1,
+ "offset": 24,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option INCORRECTLY_OPENED_COMMENT 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "-",
+ "loc": Object {
+ "end": Object {
+ "column": 15,
+ "line": 1,
+ "offset": 14,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 1,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 26,
+ "line": 1,
+ "offset": 25,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 26,
+ "line": 1,
+ "offset": 25,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option INCORRECTLY_OPENED_COMMENT 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "ELEMENT br EMPTY",
+ "loc": Object {
+ "end": Object {
+ "column": 30,
+ "line": 1,
+ "offset": 29,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 1,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 41,
+ "line": 1,
+ "offset": 40,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 41,
+ "line": 1,
+ "offset": 40,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option INVALID_FIRST_CHARACTER_OF_TAG_NAME �> 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "�",
+ "loc": Object {
+ "end": Object {
+ "column": 15,
+ "line": 1,
+ "offset": 14,
+ },
+ "source": "�>",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 1,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 26,
+ "line": 1,
+ "offset": 25,
+ },
+ "source": "�>",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 26,
+ "line": 1,
+ "offset": 25,
+ },
+ "source": "�>",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option INVALID_FIRST_CHARACTER_OF_TAG_NAME <�> 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "<�>",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 14,
+ "line": 1,
+ "offset": 13,
+ },
+ "source": "<�>",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 25,
+ "line": 1,
+ "offset": 24,
+ },
+ "source": "<�>",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 25,
+ "line": 1,
+ "offset": 24,
+ },
+ "source": "<�>",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option INVALID_FIRST_CHARACTER_OF_TAG_NAME {{a < b}} 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "a < b",
+ "isStatic": false,
+ "loc": Object {
+ "end": Object {
+ "column": 20,
+ "line": 1,
+ "offset": 19,
+ },
+ "source": "{{a < b}}",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 4,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 31,
+ "line": 1,
+ "offset": 30,
+ },
+ "source": "{{a < b}}",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 31,
+ "line": 1,
+ "offset": 30,
+ },
+ "source": "{{a < b}}",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option INVALID_FIRST_CHARACTER_OF_TAG_NAME a < b 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "a < b",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ "source": "a < b",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "a < b",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "a < b",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option INVALID_FIRST_CHARACTER_OF_TAG_NAME a b 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "a ",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 13,
+ "line": 1,
+ "offset": 12,
+ },
+ "source": "a ",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ Object {
+ "content": " b",
+ "start": Object {
+ "column": 13,
+ "line": 1,
+ "offset": 12,
+ },
+ },
+ "type": 1,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 28,
+ "line": 1,
+ "offset": 27,
+ },
+ "source": "a b",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 28,
+ "line": 1,
+ "offset": 27,
+ },
+ "source": "a b",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option MISSING_ATTRIBUTE_VALUE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 28,
+ "line": 1,
+ "offset": 27,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 21,
+ "line": 1,
+ "offset": 20,
+ },
+ "source": "id= /",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "name": "id",
+ "type": 3,
+ "value": Object {
+ "content": "/",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 21,
+ "line": 1,
+ "offset": 20,
+ },
+ "source": "/",
+ "start": Object {
+ "column": 20,
+ "line": 1,
+ "offset": 19,
+ },
+ },
+ "type": 0,
+ },
+ },
+ ],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 39,
+ "line": 1,
+ "offset": 38,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 39,
+ "line": 1,
+ "offset": 38,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option MISSING_ATTRIBUTE_VALUE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 20,
+ "line": 1,
+ "offset": 19,
+ },
+ "source": "id= ",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "name": "id",
+ "type": 3,
+ "value": undefined,
+ },
+ ],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 38,
+ "line": 1,
+ "offset": 37,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 38,
+ "line": 1,
+ "offset": 37,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option MISSING_ATTRIBUTE_VALUE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 26,
+ "line": 1,
+ "offset": 25,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 19,
+ "line": 1,
+ "offset": 18,
+ },
+ "source": "id=",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "name": "id",
+ "type": 3,
+ "value": undefined,
+ },
+ ],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 37,
+ "line": 1,
+ "offset": 36,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 37,
+ "line": 1,
+ "offset": 36,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option MISSING_END_TAG_NAME > 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 25,
+ "line": 1,
+ "offset": 24,
+ },
+ "source": ">",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 25,
+ "line": 1,
+ "offset": 24,
+ },
+ "source": ">",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option MISSING_SEMICOLON_AFTER_CHARACTER_REFERENCE ( 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "(",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 15,
+ "line": 1,
+ "offset": 14,
+ },
+ "source": "(",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 26,
+ "line": 1,
+ "offset": 25,
+ },
+ "source": "(",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 26,
+ "line": 1,
+ "offset": 25,
+ },
+ "source": "(",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option MISSING_SEMICOLON_AFTER_CHARACTER_REFERENCE @ 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "@",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ "source": "@",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "@",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "@",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option MISSING_SEMICOLON_AFTER_CHARACTER_REFERENCE & 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "&",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 15,
+ "line": 1,
+ "offset": 14,
+ },
+ "source": "&",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 26,
+ "line": 1,
+ "offset": 25,
+ },
+ "source": "&",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 26,
+ "line": 1,
+ "offset": 25,
+ },
+ "source": "&",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option MISSING_WHITESPACE_BETWEEN_ATTRIBUTES 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 19,
+ "line": 2,
+ "offset": 43,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 24,
+ "line": 1,
+ "offset": 23,
+ },
+ "source": "id=\\"foo\\"",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "name": "id",
+ "type": 3,
+ "value": Object {
+ "content": "foo",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 24,
+ "line": 1,
+ "offset": 23,
+ },
+ "source": "\\"foo\\"",
+ "start": Object {
+ "column": 19,
+ "line": 1,
+ "offset": 18,
+ },
+ },
+ "type": 0,
+ },
+ },
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 12,
+ "line": 2,
+ "offset": 36,
+ },
+ "source": "class=\\"bar\\"",
+ "start": Object {
+ "column": 1,
+ "line": 2,
+ "offset": 25,
+ },
+ },
+ "name": "class",
+ "type": 3,
+ "value": Object {
+ "content": "bar",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 12,
+ "line": 2,
+ "offset": 36,
+ },
+ "source": "\\"bar\\"",
+ "start": Object {
+ "column": 7,
+ "line": 2,
+ "offset": 31,
+ },
+ },
+ "type": 0,
+ },
+ },
+ ],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 30,
+ "line": 2,
+ "offset": 54,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 30,
+ "line": 2,
+ "offset": 54,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option MISSING_WHITESPACE_BETWEEN_ATTRIBUTES 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 42,
+ "line": 1,
+ "offset": 41,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 24,
+ "line": 1,
+ "offset": 23,
+ },
+ "source": "id=\\"foo\\"",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "name": "id",
+ "type": 3,
+ "value": Object {
+ "content": "foo",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 24,
+ "line": 1,
+ "offset": 23,
+ },
+ "source": "\\"foo\\"",
+ "start": Object {
+ "column": 19,
+ "line": 1,
+ "offset": 18,
+ },
+ },
+ "type": 0,
+ },
+ },
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 35,
+ "line": 1,
+ "offset": 34,
+ },
+ "source": "class=\\"bar\\"",
+ "start": Object {
+ "column": 24,
+ "line": 1,
+ "offset": 23,
+ },
+ },
+ "name": "class",
+ "type": 3,
+ "value": Object {
+ "content": "bar",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 35,
+ "line": 1,
+ "offset": 34,
+ },
+ "source": "\\"bar\\"",
+ "start": Object {
+ "column": 30,
+ "line": 1,
+ "offset": 29,
+ },
+ },
+ "type": 0,
+ },
+ },
+ ],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 53,
+ "line": 1,
+ "offset": 52,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 53,
+ "line": 1,
+ "offset": 52,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option NESTED_COMMENT 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "a",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 1,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 32,
+ "line": 1,
+ "offset": 31,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 32,
+ "line": 1,
+ "offset": 31,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option NESTED_COMMENT 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "a",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 1,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 40,
+ "line": 1,
+ "offset": 39,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 40,
+ "line": 1,
+ "offset": 39,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option NESTED_COMMENT 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "a",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 1,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 35,
+ "line": 1,
+ "offset": 34,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 35,
+ "line": 1,
+ "offset": 34,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option NONCHARACTER_CHARACTER_REFERENCE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 20,
+ "line": 1,
+ "offset": 19,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 31,
+ "line": 1,
+ "offset": 30,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 31,
+ "line": 1,
+ "offset": 30,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option NONCHARACTER_CHARACTER_REFERENCE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 19,
+ "line": 1,
+ "offset": 18,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 30,
+ "line": 1,
+ "offset": 29,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 30,
+ "line": 1,
+ "offset": 29,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option NULL_CHARACTER_REFERENCE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "�",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 18,
+ "line": 1,
+ "offset": 17,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 29,
+ "line": 1,
+ "offset": 28,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 29,
+ "line": 1,
+ "offset": 28,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option SURROGATE_CHARACTER_REFERENCE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "�",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 19,
+ "line": 1,
+ "offset": 18,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 30,
+ "line": 1,
+ "offset": 29,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 30,
+ "line": 1,
+ "offset": 29,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 30,
+ "line": 1,
+ "offset": 29,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 23,
+ "line": 1,
+ "offset": 22,
+ },
+ "source": "a\\"bc=''",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "name": "a\\"bc",
+ "type": 3,
+ "value": Object {
+ "content": "",
+ "isEmpty": true,
+ "loc": Object {
+ "end": Object {
+ "column": 23,
+ "line": 1,
+ "offset": 22,
+ },
+ "source": "''",
+ "start": Object {
+ "column": 21,
+ "line": 1,
+ "offset": 20,
+ },
+ },
+ "type": 0,
+ },
+ },
+ ],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 41,
+ "line": 1,
+ "offset": 40,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 41,
+ "line": 1,
+ "offset": 40,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 30,
+ "line": 1,
+ "offset": 29,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 23,
+ "line": 1,
+ "offset": 22,
+ },
+ "source": "a'bc=''",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "name": "a'bc",
+ "type": 3,
+ "value": Object {
+ "content": "",
+ "isEmpty": true,
+ "loc": Object {
+ "end": Object {
+ "column": 23,
+ "line": 1,
+ "offset": 22,
+ },
+ "source": "''",
+ "start": Object {
+ "column": 21,
+ "line": 1,
+ "offset": 20,
+ },
+ },
+ "type": 0,
+ },
+ },
+ ],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 41,
+ "line": 1,
+ "offset": 40,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 41,
+ "line": 1,
+ "offset": 40,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 30,
+ "line": 1,
+ "offset": 29,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 23,
+ "line": 1,
+ "offset": 22,
+ },
+ "source": "a",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 41,
+ "line": 1,
+ "offset": 40,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 31,
+ "line": 1,
+ "offset": 30,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 24,
+ "line": 1,
+ "offset": 23,
+ },
+ "source": "foo=bar\\"",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "name": "foo",
+ "type": 3,
+ "value": Object {
+ "content": "bar\\"",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 24,
+ "line": 1,
+ "offset": 23,
+ },
+ "source": "bar\\"",
+ "start": Object {
+ "column": 20,
+ "line": 1,
+ "offset": 19,
+ },
+ },
+ "type": 0,
+ },
+ },
+ ],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 42,
+ "line": 1,
+ "offset": 41,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 42,
+ "line": 1,
+ "offset": 41,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 31,
+ "line": 1,
+ "offset": 30,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 24,
+ "line": 1,
+ "offset": 23,
+ },
+ "source": "foo=bar'",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "name": "foo",
+ "type": 3,
+ "value": Object {
+ "content": "bar'",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 24,
+ "line": 1,
+ "offset": 23,
+ },
+ "source": "bar'",
+ "start": Object {
+ "column": 20,
+ "line": 1,
+ "offset": 19,
+ },
+ },
+ "type": 0,
+ },
+ },
+ ],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 42,
+ "line": 1,
+ "offset": 41,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 42,
+ "line": 1,
+ "offset": 41,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 34,
+ "line": 1,
+ "offset": 33,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "foo=bar",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 45,
+ "line": 1,
+ "offset": 44,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE
1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 34,
+ "line": 1,
+ "offset": 33,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "foo=bar=baz",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "name": "foo",
+ "type": 3,
+ "value": Object {
+ "content": "bar=baz",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "bar=baz",
+ "start": Object {
+ "column": 20,
+ "line": 1,
+ "offset": 19,
+ },
+ },
+ "type": 0,
+ },
+ },
+ ],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 45,
+ "line": 1,
+ "offset": 44,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 45,
+ "line": 1,
+ "offset": 44,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE
1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 31,
+ "line": 1,
+ "offset": 30,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 24,
+ "line": 1,
+ "offset": 23,
+ },
+ "source": "foo=bar\`",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "name": "foo",
+ "type": 3,
+ "value": Object {
+ "content": "bar\`",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 24,
+ "line": 1,
+ "offset": 23,
+ },
+ "source": "bar\`",
+ "start": Object {
+ "column": 20,
+ "line": 1,
+ "offset": 19,
+ },
+ },
+ "type": 0,
+ },
+ },
+ ],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 42,
+ "line": 1,
+ "offset": 41,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 42,
+ "line": 1,
+ "offset": 41,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME
1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 24,
+ "line": 1,
+ "offset": 23,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 17,
+ "line": 1,
+ "offset": 16,
+ },
+ "source": "=",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "name": "=",
+ "type": 3,
+ "value": undefined,
+ },
+ ],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 35,
+ "line": 1,
+ "offset": 34,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 35,
+ "line": 1,
+ "offset": 34,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME
1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 31,
+ "line": 1,
+ "offset": 30,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 24,
+ "line": 1,
+ "offset": 23,
+ },
+ "source": "=foo=bar",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "name": "=foo",
+ "type": 3,
+ "value": Object {
+ "content": "bar",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 24,
+ "line": 1,
+ "offset": 23,
+ },
+ "source": "bar",
+ "start": Object {
+ "column": 21,
+ "line": 1,
+ "offset": 20,
+ },
+ },
+ "type": 0,
+ },
+ },
+ ],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 42,
+ "line": 1,
+ "offset": 41,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 42,
+ "line": 1,
+ "offset": 41,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME
1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "?xml?",
+ "loc": Object {
+ "end": Object {
+ "column": 18,
+ "line": 1,
+ "offset": 17,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 1,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 29,
+ "line": 1,
+ "offset": 28,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 29,
+ "line": 1,
+ "offset": 28,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option UNEXPECTED_SOLIDUS_IN_TAG
1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 26,
+ "line": 1,
+ "offset": 25,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 17,
+ "line": 1,
+ "offset": 16,
+ },
+ "source": "a",
+ "start": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ },
+ "name": "a",
+ "type": 3,
+ "value": undefined,
+ },
+ Object {
+ "loc": Object {
+ "end": Object {
+ "column": 19,
+ "line": 1,
+ "offset": 18,
+ },
+ "source": "b",
+ "start": Object {
+ "column": 18,
+ "line": 1,
+ "offset": 17,
+ },
+ },
+ "name": "b",
+ "type": 3,
+ "value": undefined,
+ },
+ ],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 37,
+ "line": 1,
+ "offset": 36,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 37,
+ "line": 1,
+ "offset": 36,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option UNKNOWN_NAMED_CHARACTER_REFERENCE
&unknown; 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "&unknown;",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 20,
+ "line": 1,
+ "offset": 19,
+ },
+ "source": "&unknown;",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 31,
+ "line": 1,
+ "offset": 30,
+ },
+ "source": "
&unknown;",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 31,
+ "line": 1,
+ "offset": 30,
+ },
+ "source": "
&unknown;",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option X_INVALID_END_TAG
]]> 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "
",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 21,
+ "line": 1,
+ "offset": 20,
+ },
+ "source": "",
+ "start": Object {
+ "column": 15,
+ "line": 1,
+ "offset": 14,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 30,
+ "line": 1,
+ "offset": 29,
+ },
+ "source": "]]>",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 1,
+ "props": Array [],
+ "tag": "svg",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 30,
+ "line": 1,
+ "offset": 29,
+ },
+ "source": "]]>",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option X_INVALID_END_TAG 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "",
+ "loc": Object {
+ "end": Object {
+ "column": 19,
+ "line": 1,
+ "offset": 18,
+ },
+ "source": "",
+ "start": Object {
+ "column": 6,
+ "line": 1,
+ "offset": 5,
+ },
+ },
+ "type": 1,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 25,
+ "line": 1,
+ "offset": 24,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 1,
+ "props": Array [],
+ "tag": "svg",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 25,
+ "line": 1,
+ "offset": 24,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option X_INVALID_END_TAG 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 34,
+ "line": 1,
+ "offset": 33,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 34,
+ "line": 1,
+ "offset": 33,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option X_INVALID_END_TAG 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 28,
+ "line": 1,
+ "offset": 27,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 28,
+ "line": 1,
+ "offset": 27,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option X_INVALID_END_TAG {{''}} 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "''",
+ "isStatic": false,
+ "loc": Object {
+ "end": Object {
+ "column": 23,
+ "line": 1,
+ "offset": 22,
+ },
+ "source": "{{''}}",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 4,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 34,
+ "line": 1,
+ "offset": 33,
+ },
+ "source": "{{''}}",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 34,
+ "line": 1,
+ "offset": 33,
+ },
+ "source": "{{''}}",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option X_INVALID_END_TAG 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "content": "",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 17,
+ "line": 1,
+ "offset": 16,
+ },
+ "source": "",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 28,
+ "line": 1,
+ "offset": 27,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "textarea",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 28,
+ "line": 1,
+ "offset": 27,
+ },
+ "source": "",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option X_MISSING_END_TAG 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option X_MISSING_END_TAG
1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 16,
+ "line": 1,
+ "offset": 15,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 11,
+ "line": 1,
+ "offset": 10,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [],
+ "tag": "template",
+ "tagType": 3,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 27,
+ "line": 1,
+ "offset": 26,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option X_MISSING_INTERPOLATION_END {{ 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "content": "{{",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 3,
+ "line": 1,
+ "offset": 2,
+ },
+ "source": "{{",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 3,
+ "line": 1,
+ "offset": 2,
+ },
+ "source": "{{",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option X_MISSING_INTERPOLATION_END {{ foo 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "content": "{{ foo",
+ "isEmpty": false,
+ "loc": Object {
+ "end": Object {
+ "column": 7,
+ "line": 1,
+ "offset": 6,
+ },
+ "source": "{{ foo",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 0,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 7,
+ "line": 1,
+ "offset": 6,
+ },
+ "source": "{{ foo",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse onError option X_MISSING_INTERPOLATION_END {{}} 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "content": "",
+ "isStatic": true,
+ "loc": Object {
+ "end": Object {
+ "column": 5,
+ "line": 1,
+ "offset": 4,
+ },
+ "source": "{{}}",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 4,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 5,
+ "line": 1,
+ "offset": 4,
+ },
+ "source": "{{}}",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse self closing multiple tag 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": true,
+ "loc": Object {
+ "end": Object {
+ "column": 37,
+ "line": 1,
+ "offset": 36,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "arg": Object {
+ "content": "class",
+ "isStatic": true,
+ "loc": Object {
+ "end": Object {
+ "column": 12,
+ "line": 1,
+ "offset": 11,
+ },
+ "source": "class",
+ "start": Object {
+ "column": 7,
+ "line": 1,
+ "offset": 6,
+ },
+ },
+ "type": 4,
+ },
+ "exp": Object {
+ "content": "{ some: condition }",
+ "isStatic": false,
+ "loc": Object {
+ "end": Object {
+ "column": 34,
+ "line": 1,
+ "offset": 33,
+ },
+ "source": "\\"{ some: condition }\\"",
+ "start": Object {
+ "column": 13,
+ "line": 1,
+ "offset": 12,
+ },
+ },
+ "type": 4,
+ },
+ "loc": Object {
+ "end": Object {
+ "column": 34,
+ "line": 1,
+ "offset": 33,
+ },
+ "source": ":class=\\"{ some: condition }\\"",
+ "start": Object {
+ "column": 6,
+ "line": 1,
+ "offset": 5,
+ },
+ },
+ "modifiers": Array [],
+ "name": "bind",
+ "type": 5,
+ },
+ ],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ Object {
+ "children": Array [],
+ "isSelfClosing": true,
+ "loc": Object {
+ "end": Object {
+ "column": 37,
+ "line": 2,
+ "offset": 73,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 2,
+ "offset": 37,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "arg": Object {
+ "content": "style",
+ "isStatic": true,
+ "loc": Object {
+ "end": Object {
+ "column": 16,
+ "line": 2,
+ "offset": 52,
+ },
+ "source": "style",
+ "start": Object {
+ "column": 11,
+ "line": 2,
+ "offset": 47,
+ },
+ },
+ "type": 4,
+ },
+ "exp": Object {
+ "content": "{ color: 'red' }",
+ "isStatic": false,
+ "loc": Object {
+ "end": Object {
+ "column": 35,
+ "line": 2,
+ "offset": 71,
+ },
+ "source": "\\"{ color: 'red' }\\"",
+ "start": Object {
+ "column": 17,
+ "line": 2,
+ "offset": 53,
+ },
+ },
+ "type": 4,
+ },
+ "loc": Object {
+ "end": Object {
+ "column": 35,
+ "line": 2,
+ "offset": 71,
+ },
+ "source": "v-bind:style=\\"{ color: 'red' }\\"",
+ "start": Object {
+ "column": 4,
+ "line": 2,
+ "offset": 40,
+ },
+ },
+ "modifiers": Array [],
+ "name": "bind",
+ "type": 5,
+ },
+ ],
+ "tag": "p",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 37,
+ "line": 2,
+ "offset": 73,
+ },
+ "source": "
+
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
+
+exports[`parser/parse valid html 1`] = `
+Object {
+ "children": Array [
+ Object {
+ "children": Array [
+ Object {
+ "children": Array [],
+ "isSelfClosing": true,
+ "loc": Object {
+ "end": Object {
+ "column": 38,
+ "line": 2,
+ "offset": 73,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 2,
+ "line": 2,
+ "offset": 37,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "arg": Object {
+ "content": "style",
+ "isStatic": true,
+ "loc": Object {
+ "end": Object {
+ "column": 17,
+ "line": 2,
+ "offset": 52,
+ },
+ "source": "style",
+ "start": Object {
+ "column": 12,
+ "line": 2,
+ "offset": 47,
+ },
+ },
+ "type": 4,
+ },
+ "exp": Object {
+ "content": "{ color: 'red' }",
+ "isStatic": false,
+ "loc": Object {
+ "end": Object {
+ "column": 36,
+ "line": 2,
+ "offset": 71,
+ },
+ "source": "\\"{ color: 'red' }\\"",
+ "start": Object {
+ "column": 18,
+ "line": 2,
+ "offset": 53,
+ },
+ },
+ "type": 4,
+ },
+ "loc": Object {
+ "end": Object {
+ "column": 36,
+ "line": 2,
+ "offset": 71,
+ },
+ "source": "v-bind:style=\\"{ color: 'red' }\\"",
+ "start": Object {
+ "column": 5,
+ "line": 2,
+ "offset": 40,
+ },
+ },
+ "modifiers": Array [],
+ "name": "bind",
+ "type": 5,
+ },
+ ],
+ "tag": "p",
+ "tagType": 0,
+ "type": 2,
+ },
+ Object {
+ "content": " a comment with inside it ",
+ "loc": Object {
+ "end": Object {
+ "column": 42,
+ "line": 3,
+ "offset": 116,
+ },
+ "source": "",
+ "start": Object {
+ "column": 2,
+ "line": 3,
+ "offset": 76,
+ },
+ },
+ "type": 1,
+ },
+ ],
+ "isSelfClosing": false,
+ "loc": Object {
+ "end": Object {
+ "column": 7,
+ "line": 4,
+ "offset": 123,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "ns": 0,
+ "props": Array [
+ Object {
+ "arg": Object {
+ "content": "class",
+ "isStatic": true,
+ "loc": Object {
+ "end": Object {
+ "column": 12,
+ "line": 1,
+ "offset": 11,
+ },
+ "source": "class",
+ "start": Object {
+ "column": 7,
+ "line": 1,
+ "offset": 6,
+ },
+ },
+ "type": 4,
+ },
+ "exp": Object {
+ "content": "{ some: condition }",
+ "isStatic": false,
+ "loc": Object {
+ "end": Object {
+ "column": 34,
+ "line": 1,
+ "offset": 33,
+ },
+ "source": "\\"{ some: condition }\\"",
+ "start": Object {
+ "column": 13,
+ "line": 1,
+ "offset": 12,
+ },
+ },
+ "type": 4,
+ },
+ "loc": Object {
+ "end": Object {
+ "column": 34,
+ "line": 1,
+ "offset": 33,
+ },
+ "source": ":class=\\"{ some: condition }\\"",
+ "start": Object {
+ "column": 6,
+ "line": 1,
+ "offset": 5,
+ },
+ },
+ "modifiers": Array [],
+ "name": "bind",
+ "type": 5,
+ },
+ ],
+ "tag": "div",
+ "tagType": 0,
+ "type": 2,
+ },
+ ],
+ "loc": Object {
+ "end": Object {
+ "column": 7,
+ "line": 4,
+ "offset": 123,
+ },
+ "source": "
",
+ "start": Object {
+ "column": 1,
+ "line": 1,
+ "offset": 0,
+ },
+ },
+ "type": 6,
+}
+`;
diff --git a/packages/compiler-core/__tests__/parse.spec.ts b/packages/compiler-core/__tests__/parse.spec.ts
new file mode 100644
index 00000000..8879c454
--- /dev/null
+++ b/packages/compiler-core/__tests__/parse.spec.ts
@@ -0,0 +1,2517 @@
+import { parse, ParserOptions } from '../src/parser'
+import {
+ AttributeNode,
+ CommentNode,
+ DirectiveNode,
+ ElementNode,
+ ElementTypes,
+ ExpressionNode,
+ Namespaces,
+ NodeTypes,
+ Position,
+ TextNode
+} from '../src/ast'
+import { ParserErrorTypes } from '../src/errorTypes'
+import { parserOptionsMinimal as parserOptions } from '../src/parserOptionsMinimal'
+
+describe('parser/parse', () => {
+ describe('Text', () => {
+ test('simple text', () => {
+ const ast = parse('some text', parserOptions)
+ const text = ast.children[0] as TextNode
+
+ expect(text).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: 'some text',
+ isEmpty: false,
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 9, line: 1, column: 10 },
+ source: 'some text'
+ }
+ })
+ })
+
+ test('simple text with invalid end tag', () => {
+ const ast = parse('some text
', {
+ ...parserOptions,
+ onError: () => {}
+ })
+ const text = ast.children[0] as TextNode
+
+ expect(text).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: 'some text',
+ isEmpty: false,
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 9, line: 1, column: 10 },
+ source: 'some text'
+ }
+ })
+ })
+
+ test('text with interpolation', () => {
+ const ast = parse('some {{ foo + bar }} text', parserOptions)
+ const text1 = ast.children[0] as TextNode
+ const text2 = ast.children[2] as TextNode
+
+ expect(text1).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: 'some ',
+ isEmpty: false,
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 5, line: 1, column: 6 },
+ source: 'some '
+ }
+ })
+ expect(text2).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: ' text',
+ isEmpty: false,
+ loc: {
+ start: { offset: 20, line: 1, column: 21 },
+ end: { offset: 25, line: 1, column: 26 },
+ source: ' text'
+ }
+ })
+ })
+
+ test('text with interpolation which has `<`', () => {
+ const ast = parse('some {{ ad }} text', parserOptions)
+ const text1 = ast.children[0] as TextNode
+ const text2 = ast.children[2] as TextNode
+
+ expect(text1).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: 'some ',
+ isEmpty: false,
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 5, line: 1, column: 6 },
+ source: 'some '
+ }
+ })
+ expect(text2).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: ' text',
+ isEmpty: false,
+ loc: {
+ start: { offset: 21, line: 1, column: 22 },
+ end: { offset: 26, line: 1, column: 27 },
+ source: ' text'
+ }
+ })
+ })
+
+ test('text with mix of tags and interpolations', () => {
+ const ast = parse(
+ 'some {{ foo < bar + foo }} text',
+ parserOptions
+ )
+ const text1 = ast.children[0] as TextNode
+ const text2 = (ast.children[1] as ElementNode).children![1] as TextNode
+
+ expect(text1).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: 'some ',
+ isEmpty: false,
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 5, line: 1, column: 6 },
+ source: 'some '
+ }
+ })
+ expect(text2).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: ' text',
+ isEmpty: false,
+ loc: {
+ start: { offset: 32, line: 1, column: 33 },
+ end: { offset: 37, line: 1, column: 38 },
+ source: ' text'
+ }
+ })
+ })
+
+ test('CDATA', () => {
+ const ast = parse('', parserOptions)
+ const text = (ast.children[0] as ElementNode).children![0] as TextNode
+
+ expect(text).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: 'some text',
+ isEmpty: false,
+ loc: {
+ start: { offset: 14, line: 1, column: 15 },
+ end: { offset: 23, line: 1, column: 24 },
+ source: 'some text'
+ }
+ })
+ })
+
+ test('lonly "<" don\'t separate nodes', () => {
+ const ast = parse('a < b', {
+ ...parserOptions,
+ onError: errorCode => {
+ if (
+ errorCode !== ParserErrorTypes.INVALID_FIRST_CHARACTER_OF_TAG_NAME
+ ) {
+ throw new Error(`${errorCode}`)
+ }
+ }
+ })
+ const text = ast.children[0] as TextNode
+
+ expect(text).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: 'a < b',
+ isEmpty: false,
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 5, line: 1, column: 6 },
+ source: 'a < b'
+ }
+ })
+ })
+
+ test('lonly "{{" don\'t separate nodes', () => {
+ const ast = parse('a {{ b', {
+ ...parserOptions,
+ onError: errorCode => {
+ if (errorCode !== ParserErrorTypes.X_MISSING_INTERPOLATION_END) {
+ throw new Error(`${errorCode}`)
+ }
+ }
+ })
+ const text = ast.children[0] as TextNode
+
+ expect(text).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: 'a {{ b',
+ isEmpty: false,
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 6, line: 1, column: 7 },
+ source: 'a {{ b'
+ }
+ })
+ })
+
+ test('textarea handles comments/elements as just a text', () => {
+ const ast = parse(
+ '',
+ parserOptions
+ )
+ const element = ast.children[0] as ElementNode
+ const text = element.children[0] as TextNode
+
+ expect(text).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: 'sometext
and',
+ isEmpty: false,
+ loc: {
+ start: { offset: 10, line: 1, column: 11 },
+ end: { offset: 46, line: 1, column: 47 },
+ source: 'sometext
and'
+ }
+ })
+ })
+
+ test('textarea handles character references', () => {
+ const ast = parse('', parserOptions)
+ const element = ast.children[0] as ElementNode
+ const text = element.children[0] as TextNode
+
+ expect(text).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: '&',
+ isEmpty: false,
+ loc: {
+ start: { offset: 10, line: 1, column: 11 },
+ end: { offset: 15, line: 1, column: 16 },
+ source: '&'
+ }
+ })
+ })
+
+ test('style handles comments/elements as just a text', () => {
+ const ast = parse(
+ '',
+ parserOptions
+ )
+ const element = ast.children[0] as ElementNode
+ const text = element.children[0] as TextNode
+
+ expect(text).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: 'sometext
and',
+ isEmpty: false,
+ loc: {
+ start: { offset: 7, line: 1, column: 8 },
+ end: { offset: 43, line: 1, column: 44 },
+ source: 'sometext
and'
+ }
+ })
+ })
+
+ test("style doesn't handle character references", () => {
+ const ast = parse('', parserOptions)
+ const element = ast.children[0] as ElementNode
+ const text = element.children[0] as TextNode
+
+ expect(text).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: '&',
+ isEmpty: false,
+ loc: {
+ start: { offset: 7, line: 1, column: 8 },
+ end: { offset: 12, line: 1, column: 13 },
+ source: '&'
+ }
+ })
+ })
+
+ test('HTML entities compatibility in text (https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state).', () => {
+ const spy = jest.fn()
+ const ast = parse('&ersand;', {
+ ...parserOptions,
+ namedCharacterReferences: { amp: '&' },
+ onError: spy
+ })
+ const text = ast.children[0] as TextNode
+
+ expect(text).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: '&ersand;',
+ isEmpty: false,
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 11, line: 1, column: 12 },
+ source: '&ersand;'
+ }
+ })
+ expect(spy.mock.calls).toEqual([
+ [
+ ParserErrorTypes.MISSING_SEMICOLON_AFTER_CHARACTER_REFERENCE,
+ { offset: 4, line: 1, column: 5 }
+ ]
+ ])
+ })
+
+ test('HTML entities compatibility in attribute (https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state).', () => {
+ const spy = jest.fn()
+ const ast = parse(
+ '',
+ {
+ ...parserOptions,
+ namedCharacterReferences: { amp: '&', 'amp;': '&' },
+ onError: spy
+ }
+ )
+ const element = ast.children[0] as ElementNode
+ const text1 = (element.props[0] as AttributeNode).value
+ const text2 = (element.props[1] as AttributeNode).value
+ const text3 = (element.props[2] as AttributeNode).value
+
+ expect(text1).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: '&ersand;',
+ isEmpty: false,
+ loc: {
+ start: { offset: 7, line: 1, column: 8 },
+ end: { offset: 20, line: 1, column: 21 },
+ source: '"&ersand;"'
+ }
+ })
+ expect(text2).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: '&ersand;',
+ isEmpty: false,
+ loc: {
+ start: { offset: 23, line: 1, column: 24 },
+ end: { offset: 37, line: 1, column: 38 },
+ source: '"&ersand;"'
+ }
+ })
+ expect(text3).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: '&!',
+ isEmpty: false,
+ loc: {
+ start: { offset: 40, line: 1, column: 41 },
+ end: { offset: 47, line: 1, column: 48 },
+ source: '"&!"'
+ }
+ })
+ expect(spy.mock.calls).toEqual([
+ [
+ ParserErrorTypes.MISSING_SEMICOLON_AFTER_CHARACTER_REFERENCE,
+ { offset: 45, line: 1, column: 46 }
+ ]
+ ])
+ })
+
+ test('Some control character reference should be replaced.', () => {
+ const spy = jest.fn()
+ const ast = parse('', { ...parserOptions, onError: spy })
+ const text = ast.children[0] as TextNode
+
+ expect(text).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: '†',
+ isEmpty: false,
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 6, line: 1, column: 7 },
+ source: ''
+ }
+ })
+ expect(spy.mock.calls).toEqual([
+ [
+ ParserErrorTypes.CONTROL_CHARACTER_REFERENCE,
+ { offset: 0, line: 1, column: 1 }
+ ]
+ ])
+ })
+ })
+
+ describe('Interpolation', () => {
+ test('simple interpolation', () => {
+ const ast = parse('{{message}}', parserOptions)
+ const interpolation = ast.children[0] as ExpressionNode
+
+ expect(interpolation).toStrictEqual({
+ type: NodeTypes.EXPRESSION,
+ content: 'message',
+ isStatic: false,
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 11, line: 1, column: 12 },
+ source: '{{message}}'
+ }
+ })
+ })
+
+ test('it can have tag-like notation', () => {
+ const ast = parse('{{ a {
+ const ast = parse('{{ ad }}', parserOptions)
+ const interpolation1 = ast.children[0] as ExpressionNode
+ const interpolation2 = ast.children[1] as ExpressionNode
+
+ expect(interpolation1).toStrictEqual({
+ type: NodeTypes.EXPRESSION,
+ content: 'ad',
+ isStatic: false,
+ loc: {
+ start: { offset: 9, line: 1, column: 10 },
+ end: { offset: 18, line: 1, column: 19 },
+ source: '{{ c>d }}'
+ }
+ })
+ })
+
+ test('it can have tag-like notation (3)', () => {
+ const ast = parse('{{ "
" }} ', parserOptions)
+ const element = ast.children[0] as ElementNode
+ const interpolation = element.children[0] as ExpressionNode
+
+ expect(interpolation).toStrictEqual({
+ type: NodeTypes.EXPRESSION,
+ content: '""',
+ isStatic: false,
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 19, line: 1, column: 20 },
+ source: '{{ "
" }}'
+ }
+ })
+ })
+
+ test('HTML entities in interpolation should be translated for backward compatibility.', () => {
+ const ast = parse('{{ a < b }}
', parserOptions)
+ const element = ast.children[0] as ElementNode
+ const interpolation = element.children[0] as ExpressionNode
+
+ expect(interpolation).toStrictEqual({
+ type: NodeTypes.EXPRESSION,
+ content: 'a < b',
+ isStatic: false,
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 19, line: 1, column: 20 },
+ source: '{{ a < b }}'
+ }
+ })
+ })
+ })
+
+ describe('Comment', () => {
+ test('empty comment', () => {
+ const ast = parse('', parserOptions)
+ const comment = ast.children[0] as CommentNode
+
+ expect(comment).toStrictEqual({
+ type: NodeTypes.COMMENT,
+ content: '',
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 7, line: 1, column: 8 },
+ source: ''
+ }
+ })
+ })
+
+ test('simple comment', () => {
+ const ast = parse('', parserOptions)
+ const comment = ast.children[0] as CommentNode
+
+ expect(comment).toStrictEqual({
+ type: NodeTypes.COMMENT,
+ content: 'abc',
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 10, line: 1, column: 11 },
+ source: ''
+ }
+ })
+ })
+
+ test('two comments', () => {
+ const ast = parse('', parserOptions)
+ const comment1 = ast.children[0] as CommentNode
+ const comment2 = ast.children[1] as CommentNode
+
+ expect(comment1).toStrictEqual({
+ type: NodeTypes.COMMENT,
+ content: 'abc',
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 10, line: 1, column: 11 },
+ source: ''
+ }
+ })
+ expect(comment2).toStrictEqual({
+ type: NodeTypes.COMMENT,
+ content: 'def',
+ loc: {
+ start: { offset: 10, line: 1, column: 11 },
+ end: { offset: 20, line: 1, column: 21 },
+ source: ''
+ }
+ })
+ })
+ })
+
+ describe('Element', () => {
+ test('simple div', () => {
+ const ast = parse('hello
', parserOptions)
+ const element = ast.children[0] as ElementNode
+
+ expect(element).toStrictEqual({
+ type: NodeTypes.ELEMENT,
+ ns: Namespaces.HTML,
+ tag: 'div',
+ tagType: ElementTypes.ELEMENT,
+ props: [],
+ isSelfClosing: false,
+ children: [
+ {
+ type: NodeTypes.TEXT,
+ content: 'hello',
+ isEmpty: false,
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 10, line: 1, column: 11 },
+ source: 'hello'
+ }
+ }
+ ],
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 16, line: 1, column: 17 },
+ source: 'hello
'
+ }
+ })
+ })
+
+ test('empty', () => {
+ const ast = parse('', parserOptions)
+ const element = ast.children[0] as ElementNode
+
+ expect(element).toStrictEqual({
+ type: NodeTypes.ELEMENT,
+ ns: Namespaces.HTML,
+ tag: 'div',
+ tagType: ElementTypes.ELEMENT,
+ props: [],
+ isSelfClosing: false,
+ children: [],
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 11, line: 1, column: 12 },
+ source: ''
+ }
+ })
+ })
+
+ test('self closing', () => {
+ const ast = parse('after', parserOptions)
+ const element = ast.children[0] as ElementNode
+
+ expect(element).toStrictEqual({
+ type: NodeTypes.ELEMENT,
+ ns: Namespaces.HTML,
+ tag: 'div',
+ tagType: ElementTypes.ELEMENT,
+ props: [],
+ isSelfClosing: true,
+ children: [],
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 6, line: 1, column: 7 },
+ source: ''
+ }
+ })
+ })
+
+ test('void element', () => {
+ const ast = parse('after', parserOptions)
+ const element = ast.children[0] as ElementNode
+
+ expect(element).toStrictEqual({
+ type: NodeTypes.ELEMENT,
+ ns: Namespaces.HTML,
+ tag: 'img',
+ tagType: ElementTypes.ELEMENT,
+ props: [],
+ isSelfClosing: false,
+ children: [],
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 5, line: 1, column: 6 },
+ source: ''
+ }
+ })
+ })
+
+ test('attribute with no value', () => {
+ const ast = parse('', parserOptions)
+ const element = ast.children[0] as ElementNode
+
+ expect(element).toStrictEqual({
+ type: NodeTypes.ELEMENT,
+ ns: Namespaces.HTML,
+ tag: 'div',
+ tagType: ElementTypes.ELEMENT,
+ props: [
+ {
+ type: NodeTypes.ATTRIBUTE,
+ name: 'id',
+ value: undefined,
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 7, line: 1, column: 8 },
+ source: 'id'
+ }
+ }
+ ],
+ isSelfClosing: false,
+ children: [],
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 14, line: 1, column: 15 },
+ source: ''
+ }
+ })
+ })
+
+ test('attribute with empty value, double quote', () => {
+ const ast = parse('', parserOptions)
+ const element = ast.children[0] as ElementNode
+
+ expect(element).toStrictEqual({
+ type: NodeTypes.ELEMENT,
+ ns: Namespaces.HTML,
+ tag: 'div',
+ tagType: ElementTypes.ELEMENT,
+ props: [
+ {
+ type: NodeTypes.ATTRIBUTE,
+ name: 'id',
+ value: {
+ type: NodeTypes.TEXT,
+ content: '',
+ isEmpty: true,
+ loc: {
+ start: { offset: 8, line: 1, column: 9 },
+ end: { offset: 10, line: 1, column: 11 },
+ source: '""'
+ }
+ },
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 10, line: 1, column: 11 },
+ source: 'id=""'
+ }
+ }
+ ],
+ isSelfClosing: false,
+ children: [],
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 17, line: 1, column: 18 },
+ source: ''
+ }
+ })
+ })
+
+ test('attribute with empty value, single quote', () => {
+ const ast = parse("", parserOptions)
+ const element = ast.children[0] as ElementNode
+
+ expect(element).toStrictEqual({
+ type: NodeTypes.ELEMENT,
+ ns: Namespaces.HTML,
+ tag: 'div',
+ tagType: ElementTypes.ELEMENT,
+ props: [
+ {
+ type: NodeTypes.ATTRIBUTE,
+ name: 'id',
+ value: {
+ type: NodeTypes.TEXT,
+ content: '',
+ isEmpty: true,
+ loc: {
+ start: { offset: 8, line: 1, column: 9 },
+ end: { offset: 10, line: 1, column: 11 },
+ source: "''"
+ }
+ },
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 10, line: 1, column: 11 },
+ source: "id=''"
+ }
+ }
+ ],
+ isSelfClosing: false,
+ children: [],
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 17, line: 1, column: 18 },
+ source: ""
+ }
+ })
+ })
+
+ test('attribute with value, double quote', () => {
+ const ast = parse('', parserOptions)
+ const element = ast.children[0] as ElementNode
+
+ expect(element).toStrictEqual({
+ type: NodeTypes.ELEMENT,
+ ns: Namespaces.HTML,
+ tag: 'div',
+ tagType: ElementTypes.ELEMENT,
+ props: [
+ {
+ type: NodeTypes.ATTRIBUTE,
+ name: 'id',
+ value: {
+ type: NodeTypes.TEXT,
+ content: ">'",
+ isEmpty: false,
+ loc: {
+ start: { offset: 8, line: 1, column: 9 },
+ end: { offset: 12, line: 1, column: 13 },
+ source: '">\'"'
+ }
+ },
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 12, line: 1, column: 13 },
+ source: 'id=">\'"'
+ }
+ }
+ ],
+ isSelfClosing: false,
+ children: [],
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 19, line: 1, column: 20 },
+ source: ''
+ }
+ })
+ })
+
+ test('attribute with value, single quote', () => {
+ const ast = parse("", parserOptions)
+ const element = ast.children[0] as ElementNode
+
+ expect(element).toStrictEqual({
+ type: NodeTypes.ELEMENT,
+ ns: Namespaces.HTML,
+ tag: 'div',
+ tagType: ElementTypes.ELEMENT,
+ props: [
+ {
+ type: NodeTypes.ATTRIBUTE,
+ name: 'id',
+ value: {
+ type: NodeTypes.TEXT,
+ content: '>"',
+ isEmpty: false,
+ loc: {
+ start: { offset: 8, line: 1, column: 9 },
+ end: { offset: 12, line: 1, column: 13 },
+ source: "'>\"'"
+ }
+ },
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 12, line: 1, column: 13 },
+ source: "id='>\"'"
+ }
+ }
+ ],
+ isSelfClosing: false,
+ children: [],
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 19, line: 1, column: 20 },
+ source: ""
+ }
+ })
+ })
+
+ test('attribute with value, unquoted', () => {
+ const ast = parse('', parserOptions)
+ const element = ast.children[0] as ElementNode
+
+ expect(element).toStrictEqual({
+ type: NodeTypes.ELEMENT,
+ ns: Namespaces.HTML,
+ tag: 'div',
+ tagType: ElementTypes.ELEMENT,
+ props: [
+ {
+ type: NodeTypes.ATTRIBUTE,
+ name: 'id',
+ value: {
+ type: NodeTypes.TEXT,
+ content: 'a/',
+ isEmpty: false,
+ loc: {
+ start: { offset: 8, line: 1, column: 9 },
+ end: { offset: 10, line: 1, column: 11 },
+ source: 'a/'
+ }
+ },
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 10, line: 1, column: 11 },
+ source: 'id=a/'
+ }
+ }
+ ],
+ isSelfClosing: false,
+ children: [],
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 17, line: 1, column: 18 },
+ source: ''
+ }
+ })
+ })
+
+ test('multiple attributes', () => {
+ const ast = parse(
+ '',
+ parserOptions
+ )
+ const element = ast.children[0] as ElementNode
+
+ expect(element).toStrictEqual({
+ type: NodeTypes.ELEMENT,
+ ns: Namespaces.HTML,
+ tag: 'div',
+ tagType: ElementTypes.ELEMENT,
+ props: [
+ {
+ type: NodeTypes.ATTRIBUTE,
+ name: 'id',
+ value: {
+ type: NodeTypes.TEXT,
+ content: 'a',
+ isEmpty: false,
+ loc: {
+ start: { offset: 8, line: 1, column: 9 },
+ end: { offset: 9, line: 1, column: 10 },
+ source: 'a'
+ }
+ },
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 9, line: 1, column: 10 },
+ source: 'id=a'
+ }
+ },
+ {
+ type: NodeTypes.ATTRIBUTE,
+ name: 'class',
+ value: {
+ type: NodeTypes.TEXT,
+ content: 'c',
+ isEmpty: false,
+ loc: {
+ start: { offset: 16, line: 1, column: 17 },
+ end: { offset: 19, line: 1, column: 20 },
+ source: '"c"'
+ }
+ },
+ loc: {
+ start: { offset: 10, line: 1, column: 11 },
+ end: { offset: 19, line: 1, column: 20 },
+ source: 'class="c"'
+ }
+ },
+ {
+ type: NodeTypes.ATTRIBUTE,
+ name: 'inert',
+ value: undefined,
+ loc: {
+ start: { offset: 20, line: 1, column: 21 },
+ end: { offset: 25, line: 1, column: 26 },
+ source: 'inert'
+ }
+ },
+ {
+ type: NodeTypes.ATTRIBUTE,
+ name: 'style',
+ value: {
+ type: NodeTypes.TEXT,
+ content: '',
+ isEmpty: true,
+ loc: {
+ start: { offset: 32, line: 1, column: 33 },
+ end: { offset: 34, line: 1, column: 35 },
+ source: "''"
+ }
+ },
+ loc: {
+ start: { offset: 26, line: 1, column: 27 },
+ end: { offset: 34, line: 1, column: 35 },
+ source: "style=''"
+ }
+ }
+ ],
+ isSelfClosing: false,
+ children: [],
+ loc: {
+ start: { offset: 0, line: 1, column: 1 },
+ end: { offset: 41, line: 1, column: 42 },
+ source: ''
+ }
+ })
+ })
+
+ test('directive with no value', () => {
+ const ast = parse('', parserOptions)
+ const directive = (ast.children[0] as ElementNode)
+ .props[0] as DirectiveNode
+
+ expect(directive).toStrictEqual({
+ type: NodeTypes.DIRECTIVE,
+ name: 'if',
+ arg: undefined,
+ modifiers: [],
+ exp: undefined,
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 9, line: 1, column: 10 },
+ source: 'v-if'
+ }
+ })
+ })
+
+ test('directive with value', () => {
+ const ast = parse('', parserOptions)
+ const directive = (ast.children[0] as ElementNode)
+ .props[0] as DirectiveNode
+
+ expect(directive).toStrictEqual({
+ type: NodeTypes.DIRECTIVE,
+ name: 'if',
+ arg: undefined,
+ modifiers: [],
+ exp: {
+ type: NodeTypes.EXPRESSION,
+ content: 'a',
+ isStatic: false,
+ loc: {
+ start: { offset: 10, line: 1, column: 11 },
+ end: { offset: 13, line: 1, column: 14 },
+ source: '"a"'
+ }
+ },
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 13, line: 1, column: 14 },
+ source: 'v-if="a"'
+ }
+ })
+ })
+
+ test('directive with argument', () => {
+ const ast = parse('', parserOptions)
+ const directive = (ast.children[0] as ElementNode)
+ .props[0] as DirectiveNode
+
+ expect(directive).toStrictEqual({
+ type: NodeTypes.DIRECTIVE,
+ name: 'on',
+ arg: {
+ type: 4,
+ content: 'click',
+ isStatic: true,
+ loc: {
+ source: 'click',
+ start: {
+ column: 11,
+ line: 1,
+ offset: 10
+ },
+ end: {
+ column: 16,
+ line: 1,
+ offset: 15
+ }
+ }
+ },
+ modifiers: [],
+ exp: undefined,
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 15, line: 1, column: 16 },
+ source: 'v-on:click'
+ }
+ })
+ })
+
+ test('directive with a modifier', () => {
+ const ast = parse('', parserOptions)
+ const directive = (ast.children[0] as ElementNode)
+ .props[0] as DirectiveNode
+
+ expect(directive).toStrictEqual({
+ type: NodeTypes.DIRECTIVE,
+ name: 'on',
+ arg: undefined,
+ modifiers: ['enter'],
+ exp: undefined,
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 15, line: 1, column: 16 },
+ source: 'v-on.enter'
+ }
+ })
+ })
+
+ test('directive with two modifiers', () => {
+ const ast = parse('', parserOptions)
+ const directive = (ast.children[0] as ElementNode)
+ .props[0] as DirectiveNode
+
+ expect(directive).toStrictEqual({
+ type: NodeTypes.DIRECTIVE,
+ name: 'on',
+ arg: undefined,
+ modifiers: ['enter', 'exact'],
+ exp: undefined,
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 21, line: 1, column: 22 },
+ source: 'v-on.enter.exact'
+ }
+ })
+ })
+
+ test('directive with argument and modifiers', () => {
+ const ast = parse('', parserOptions)
+ const directive = (ast.children[0] as ElementNode)
+ .props[0] as DirectiveNode
+
+ expect(directive).toStrictEqual({
+ type: NodeTypes.DIRECTIVE,
+ name: 'on',
+ arg: {
+ type: 4,
+ content: 'click',
+ isStatic: true,
+ loc: {
+ source: 'click',
+ start: {
+ column: 11,
+ line: 1,
+ offset: 10
+ },
+ end: {
+ column: 16,
+ line: 1,
+ offset: 15
+ }
+ }
+ },
+ modifiers: ['enter', 'exact'],
+ exp: undefined,
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 27, line: 1, column: 28 },
+ source: 'v-on:click.enter.exact'
+ }
+ })
+ })
+
+ test('v-bind shorthand', () => {
+ const ast = parse('', parserOptions)
+ const directive = (ast.children[0] as ElementNode)
+ .props[0] as DirectiveNode
+
+ expect(directive).toStrictEqual({
+ type: NodeTypes.DIRECTIVE,
+ name: 'bind',
+ arg: {
+ type: 4,
+ content: 'a',
+ isStatic: true,
+ loc: {
+ source: 'a',
+ start: {
+ column: 7,
+ line: 1,
+ offset: 6
+ },
+ end: {
+ column: 8,
+ line: 1,
+ offset: 7
+ }
+ }
+ },
+ modifiers: [],
+ exp: {
+ type: NodeTypes.EXPRESSION,
+ content: 'b',
+ isStatic: false,
+ loc: {
+ start: { offset: 8, line: 1, column: 9 },
+ end: { offset: 9, line: 1, column: 10 },
+ source: 'b'
+ }
+ },
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 9, line: 1, column: 10 },
+ source: ':a=b'
+ }
+ })
+ })
+
+ test('v-bind shorthand with modifier', () => {
+ const ast = parse('', parserOptions)
+ const directive = (ast.children[0] as ElementNode)
+ .props[0] as DirectiveNode
+
+ expect(directive).toStrictEqual({
+ type: NodeTypes.DIRECTIVE,
+ name: 'bind',
+ arg: {
+ type: 4,
+ content: 'a',
+ isStatic: true,
+ loc: {
+ source: 'a',
+ start: {
+ column: 7,
+ line: 1,
+ offset: 6
+ },
+ end: {
+ column: 8,
+ line: 1,
+ offset: 7
+ }
+ }
+ },
+ modifiers: ['sync'],
+ exp: {
+ type: NodeTypes.EXPRESSION,
+ content: 'b',
+ isStatic: false,
+ loc: {
+ start: { offset: 13, line: 1, column: 14 },
+ end: { offset: 14, line: 1, column: 15 },
+ source: 'b'
+ }
+ },
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 14, line: 1, column: 15 },
+ source: ':a.sync=b'
+ }
+ })
+ })
+
+ test('v-on shorthand', () => {
+ const ast = parse('', parserOptions)
+ const directive = (ast.children[0] as ElementNode)
+ .props[0] as DirectiveNode
+
+ expect(directive).toStrictEqual({
+ type: NodeTypes.DIRECTIVE,
+ name: 'on',
+ arg: {
+ type: 4,
+ content: 'a',
+ isStatic: true,
+ loc: {
+ source: 'a',
+ start: {
+ column: 7,
+ line: 1,
+ offset: 6
+ },
+ end: {
+ column: 8,
+ line: 1,
+ offset: 7
+ }
+ }
+ },
+ modifiers: [],
+ exp: {
+ type: NodeTypes.EXPRESSION,
+ content: 'b',
+ isStatic: false,
+ loc: {
+ start: { offset: 8, line: 1, column: 9 },
+ end: { offset: 9, line: 1, column: 10 },
+ source: 'b'
+ }
+ },
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 9, line: 1, column: 10 },
+ source: '@a=b'
+ }
+ })
+ })
+
+ test('v-on shorthand with modifier', () => {
+ const ast = parse('', parserOptions)
+ const directive = (ast.children[0] as ElementNode)
+ .props[0] as DirectiveNode
+
+ expect(directive).toStrictEqual({
+ type: NodeTypes.DIRECTIVE,
+ name: 'on',
+ arg: {
+ type: 4,
+ content: 'a',
+ isStatic: true,
+ loc: {
+ source: 'a',
+ start: {
+ column: 7,
+ line: 1,
+ offset: 6
+ },
+ end: {
+ column: 8,
+ line: 1,
+ offset: 7
+ }
+ }
+ },
+ modifiers: ['enter'],
+ exp: {
+ type: NodeTypes.EXPRESSION,
+ content: 'b',
+ isStatic: false,
+ loc: {
+ start: { offset: 14, line: 1, column: 15 },
+ end: { offset: 15, line: 1, column: 16 },
+ source: 'b'
+ }
+ },
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 15, line: 1, column: 16 },
+ source: '@a.enter=b'
+ }
+ })
+ })
+
+ test('end tags are case-insensitive.', () => {
+ const ast = parse('hello
after', parserOptions)
+ const element = ast.children[0] as ElementNode
+ const text = element.children[0] as TextNode
+
+ expect(text).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: 'hello',
+ isEmpty: false,
+ loc: {
+ start: { offset: 5, line: 1, column: 6 },
+ end: { offset: 10, line: 1, column: 11 },
+ source: 'hello'
+ }
+ })
+ })
+
+ test('Strict end tag detection.', () => {
+ const ast = parse(
+ '">',
+ {
+ ...parserOptions,
+ onError: type => {
+ if (type !== ParserErrorTypes.END_TAG_WITH_ATTRIBUTES) {
+ throw new Error(String(type))
+ }
+ }
+ }
+ )
+ const element = ast.children[0] as ElementNode
+ const text = element.children[0] as TextNode
+
+ expect(ast.children.length).toBe(1)
+ expect(text).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: 'hello',
+ isEmpty: false,
+ loc: {
+ start: { offset: 10, line: 1, column: 11 },
+ end: { offset: 37, line: 1, column: 38 },
+ source: 'hello'
+ }
+ })
+ })
+ })
+
+ test('self closing single tag', () => {
+ const ast = parse('', parserOptions)
+
+ expect(ast.children).toHaveLength(1)
+ expect(ast.children[0]).toMatchObject({ tag: 'div' })
+ })
+
+ test('self closing multiple tag', () => {
+ const ast = parse(
+ `\n` +
+ ``,
+ parserOptions
+ )
+
+ expect(ast).toMatchSnapshot()
+
+ expect(ast.children).toHaveLength(2)
+ expect(ast.children[0]).toMatchObject({ tag: 'div' })
+ expect(ast.children[1]).toMatchObject({ tag: 'p' })
+ })
+
+ test('valid html', () => {
+ const ast = parse(
+ `\n` +
+ `
\n` +
+ ` \n` +
+ `
`,
+ parserOptions
+ )
+
+ expect(ast).toMatchSnapshot()
+
+ expect(ast.children).toHaveLength(1)
+ const el = ast.children[0] as any
+ expect(el).toMatchObject({
+ tag: 'div'
+ })
+ expect(el.children).toHaveLength(2)
+ expect(el.children[0]).toMatchObject({
+ tag: 'p'
+ })
+ expect(el.children[1]).toMatchObject({
+ type: NodeTypes.COMMENT
+ })
+ })
+
+ test('invalid html', () => {
+ expect(() => {
+ parse(`\n\n
\n`, parserOptions)
+ }).toThrow('End tag was not found. (3:1)')
+
+ const spy = jest.fn()
+ const ast = parse(`\n\n
\n`, {
+ ...parserOptions,
+ onError: spy
+ })
+
+ expect(spy).toBeCalledWith(ParserErrorTypes.X_MISSING_END_TAG, {
+ offset: 13,
+ line: 3,
+ column: 1
+ })
+ expect(spy).toBeCalledWith(ParserErrorTypes.X_INVALID_END_TAG, {
+ offset: 20,
+ line: 4,
+ column: 1
+ })
+ expect(ast).toMatchSnapshot()
+ })
+
+ test('parse with correct location info', () => {
+ const [foo, bar, but, baz] = parse(
+ 'foo \n is {{ bar }} but {{ baz }}',
+ parserOptions
+ ).children
+
+ let offset = 0
+ expect(foo.loc.start).toEqual({ line: 1, column: 1, offset })
+ offset += foo.loc.source.length
+ expect(foo.loc.end).toEqual({ line: 2, column: 4, offset })
+
+ expect(bar.loc.start).toEqual({ line: 2, column: 4, offset })
+ offset += bar.loc.source.length
+ expect(bar.loc.end).toEqual({ line: 2, column: 13, offset })
+
+ expect(but.loc.start).toEqual({ line: 2, column: 13, offset })
+ offset += but.loc.source.length
+ expect(but.loc.end).toEqual({ line: 2, column: 18, offset })
+
+ expect(baz.loc.start).toEqual({ line: 2, column: 18, offset })
+ offset += baz.loc.source.length
+ expect(baz.loc.end).toEqual({ line: 2, column: 27, offset })
+ })
+
+ describe('namedCharacterReferences option', () => {
+ test('use the given map', () => {
+ const ast: any = parse('&∪︀', {
+ ...parserOptions,
+ namedCharacterReferences: {
+ 'cups;': '\u222A\uFE00' // UNION with serifs
+ },
+ onError: () => {} // Ignore errors
+ })
+
+ expect(ast.children.length).toBe(1)
+ expect(ast.children[0].type).toBe(NodeTypes.TEXT)
+ expect(ast.children[0].content).toBe('&\u222A\uFE00')
+ })
+ })
+
+ describe('onError option', () => {
+ const patterns: {
+ [key: string]: Array<{
+ code: string
+ errors: Array<{ type: ParserErrorTypes; loc: Position }>
+ options?: Partial
+ }>
+ } = {
+ ABRUPT_CLOSING_OF_EMPTY_COMMENT: [
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.ABRUPT_CLOSING_OF_EMPTY_COMMENT,
+ loc: { offset: 10, line: 1, column: 11 }
+ }
+ ]
+ },
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.ABRUPT_CLOSING_OF_EMPTY_COMMENT,
+ loc: { offset: 10, line: 1, column: 11 }
+ }
+ ]
+ },
+ {
+ code: '',
+ errors: []
+ }
+ ],
+ ABSENCE_OF_DIGITS_IN_NUMERIC_CHARACTER_REFERENCE: [
+ {
+ code: 'a;',
+ errors: [
+ {
+ type:
+ ParserErrorTypes.ABSENCE_OF_DIGITS_IN_NUMERIC_CHARACTER_REFERENCE,
+ loc: { offset: 10, line: 1, column: 11 }
+ }
+ ]
+ },
+ {
+ code: 'g;',
+ errors: [
+ {
+ type:
+ ParserErrorTypes.ABSENCE_OF_DIGITS_IN_NUMERIC_CHARACTER_REFERENCE,
+ loc: { offset: 10, line: 1, column: 11 }
+ }
+ ]
+ },
+ {
+ code: 'c',
+ errors: []
+ },
+ {
+ code: 'ÿ',
+ errors: []
+ },
+ {
+ code: '',
+ errors: [
+ {
+ type:
+ ParserErrorTypes.ABSENCE_OF_DIGITS_IN_NUMERIC_CHARACTER_REFERENCE,
+ loc: { offset: 16, line: 1, column: 17 }
+ }
+ ]
+ },
+ {
+ code: '',
+ errors: [
+ {
+ type:
+ ParserErrorTypes.ABSENCE_OF_DIGITS_IN_NUMERIC_CHARACTER_REFERENCE,
+ loc: { offset: 16, line: 1, column: 17 }
+ }
+ ]
+ },
+ {
+ code: '',
+ errors: []
+ },
+ {
+ code: '',
+ errors: []
+ }
+ ],
+ CDATA_IN_HTML_CONTENT: [
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.CDATA_IN_HTML_CONTENT,
+ loc: { offset: 10, line: 1, column: 11 }
+ }
+ ]
+ },
+ {
+ code: '',
+ errors: []
+ }
+ ],
+ CHARACTER_REFERENCE_OUTSIDE_UNICODE_RANGE: [
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.CHARACTER_REFERENCE_OUTSIDE_UNICODE_RANGE,
+ loc: { offset: 10, line: 1, column: 11 }
+ }
+ ]
+ }
+ ],
+ CONTROL_CHARACTER_REFERENCE: [
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.CONTROL_CHARACTER_REFERENCE,
+ loc: { offset: 10, line: 1, column: 11 }
+ }
+ ]
+ },
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.CONTROL_CHARACTER_REFERENCE,
+ loc: { offset: 10, line: 1, column: 11 }
+ }
+ ]
+ }
+ ],
+ DUPLICATE_ATTRIBUTE: [
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.DUPLICATE_ATTRIBUTE,
+ loc: { offset: 21, line: 1, column: 22 }
+ }
+ ]
+ }
+ ],
+ END_TAG_WITH_ATTRIBUTES: [
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.END_TAG_WITH_ATTRIBUTES,
+ loc: { offset: 21, line: 1, column: 22 }
+ }
+ ]
+ }
+ ],
+ END_TAG_WITH_TRAILING_SOLIDUS: [
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.END_TAG_WITH_TRAILING_SOLIDUS,
+ loc: { offset: 20, line: 1, column: 21 }
+ }
+ ]
+ }
+ ],
+ EOF_BEFORE_TAG_NAME: [
+ {
+ code: '<',
+ errors: [
+ {
+ type: ParserErrorTypes.EOF_BEFORE_TAG_NAME,
+ loc: { offset: 11, line: 1, column: 12 }
+ },
+ {
+ type: ParserErrorTypes.X_MISSING_END_TAG,
+ loc: { offset: 11, line: 1, column: 12 }
+ }
+ ]
+ },
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.EOF_BEFORE_TAG_NAME,
+ loc: { offset: 12, line: 1, column: 13 }
+ },
+ {
+ type: ParserErrorTypes.X_MISSING_END_TAG,
+ loc: { offset: 12, line: 1, column: 13 }
+ }
+ ]
+ }
+ ],
+ EOF_IN_CDATA: [
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.INCORRECTLY_CLOSED_COMMENT,
+ loc: { offset: 10, line: 1, column: 11 }
+ }
+ ]
+ }
+ ],
+ INCORRECTLY_OPENED_COMMENT: [
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.INCORRECTLY_OPENED_COMMENT,
+ loc: { offset: 10, line: 1, column: 11 }
+ }
+ ]
+ },
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.INCORRECTLY_OPENED_COMMENT,
+ loc: { offset: 10, line: 1, column: 11 }
+ }
+ ]
+ },
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.INCORRECTLY_OPENED_COMMENT,
+ loc: { offset: 10, line: 1, column: 11 }
+ }
+ ]
+ },
+ // Just ignore doctype.
+ {
+ code: '',
+ errors: []
+ }
+ ],
+ INVALID_FIRST_CHARACTER_OF_TAG_NAME: [
+ {
+ code: 'a < b',
+ errors: [
+ {
+ type: ParserErrorTypes.INVALID_FIRST_CHARACTER_OF_TAG_NAME,
+ loc: { offset: 13, line: 1, column: 14 }
+ }
+ ]
+ },
+ {
+ code: '<�>',
+ errors: [
+ {
+ type: ParserErrorTypes.INVALID_FIRST_CHARACTER_OF_TAG_NAME,
+ loc: { offset: 11, line: 1, column: 12 }
+ }
+ ]
+ },
+ {
+ code: 'a b',
+ errors: [
+ {
+ type: ParserErrorTypes.INVALID_FIRST_CHARACTER_OF_TAG_NAME,
+ loc: { offset: 14, line: 1, column: 15 }
+ },
+ {
+ type: ParserErrorTypes.X_MISSING_END_TAG,
+ loc: { offset: 27, line: 1, column: 28 }
+ }
+ ]
+ },
+ {
+ code: '�>',
+ errors: [
+ {
+ type: ParserErrorTypes.INVALID_FIRST_CHARACTER_OF_TAG_NAME,
+ loc: { offset: 12, line: 1, column: 13 }
+ }
+ ]
+ },
+ // Don't throw invalid-first-character-of-tag-name in interpolation
+ {
+ code: '{{a < b}}',
+ errors: []
+ }
+ ],
+ MISSING_ATTRIBUTE_VALUE: [
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.MISSING_ATTRIBUTE_VALUE,
+ loc: { offset: 18, line: 1, column: 19 }
+ }
+ ]
+ },
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.MISSING_ATTRIBUTE_VALUE,
+ loc: { offset: 19, line: 1, column: 20 }
+ }
+ ]
+ },
+ {
+ code: '',
+ errors: []
+ }
+ ],
+ MISSING_END_TAG_NAME: [
+ {
+ code: '>',
+ errors: [
+ {
+ type: ParserErrorTypes.MISSING_END_TAG_NAME,
+ loc: { offset: 12, line: 1, column: 13 }
+ }
+ ]
+ }
+ ],
+ MISSING_SEMICOLON_AFTER_CHARACTER_REFERENCE: [
+ {
+ code: '&',
+ options: { namedCharacterReferences: { amp: '&' } },
+ errors: [
+ {
+ type:
+ ParserErrorTypes.MISSING_SEMICOLON_AFTER_CHARACTER_REFERENCE,
+ loc: { offset: 14, line: 1, column: 15 }
+ }
+ ]
+ },
+ {
+ code: '(',
+ errors: [
+ {
+ type:
+ ParserErrorTypes.MISSING_SEMICOLON_AFTER_CHARACTER_REFERENCE,
+ loc: { offset: 14, line: 1, column: 15 }
+ }
+ ]
+ },
+ {
+ code: '@',
+ errors: [
+ {
+ type:
+ ParserErrorTypes.MISSING_SEMICOLON_AFTER_CHARACTER_REFERENCE,
+ loc: { offset: 15, line: 1, column: 16 }
+ }
+ ]
+ }
+ ],
+ MISSING_WHITESPACE_BETWEEN_ATTRIBUTES: [
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.MISSING_WHITESPACE_BETWEEN_ATTRIBUTES,
+ loc: { offset: 23, line: 1, column: 24 }
+ }
+ ]
+ },
+ // CR doesn't appear in tokenization phase, but all CR are removed in preprocessing.
+ // https://html.spec.whatwg.org/multipage/parsing.html#preprocessing-the-input-stream
+ {
+ code: '',
+ errors: []
+ }
+ ],
+ NESTED_COMMENT: [
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.NESTED_COMMENT,
+ loc: { offset: 15, line: 1, column: 16 }
+ }
+ ]
+ },
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.NESTED_COMMENT,
+ loc: { offset: 15, line: 1, column: 16 }
+ },
+ {
+ type: ParserErrorTypes.NESTED_COMMENT,
+ loc: { offset: 20, line: 1, column: 21 }
+ }
+ ]
+ },
+ {
+ code: '',
+ errors: []
+ },
+ {
+ code: '',
+ errors: []
+ }
+ ],
+ X_MISSING_END_TAG: [
+ {
+ code: '',
+ errors: [
+ {
+ type: ParserErrorTypes.X_MISSING_END_TAG,
+ loc: { offset: 15, line: 1, column: 16 }
+ }
+ ]
+ },
+ {
+ code: '
',
+ errors: [
+ {
+ type: ParserErrorTypes.X_MISSING_END_TAG,
+ loc: { offset: 15, line: 1, column: 16 }
+ },
+ {
+ type: ParserErrorTypes.X_MISSING_END_TAG,
+ loc: { offset: 15, line: 1, column: 16 }
+ }
+ ]
+ }
+ ],
+ X_MISSING_INTERPOLATION_END: [
+ {
+ code: '{{ foo',
+ errors: [
+ {
+ type: ParserErrorTypes.X_MISSING_INTERPOLATION_END,
+ loc: { offset: 0, line: 1, column: 1 }
+ }
+ ]
+ },
+ {
+ code: '{{',
+ errors: [
+ {
+ type: ParserErrorTypes.X_MISSING_INTERPOLATION_END,
+ loc: { offset: 0, line: 1, column: 1 }
+ }
+ ]
+ },
+ {
+ code: '{{}}',
+ errors: []
+ }
+ ]
+ }
+
+ for (const key of Object.keys(patterns) as (keyof (typeof patterns))[]) {
+ describe(key, () => {
+ for (const { code, errors, options } of patterns[key]) {
+ test(
+ code.replace(
+ /[\r\n]/g,
+ c => `\\x0${c.codePointAt(0)!.toString(16)};`
+ ),
+ () => {
+ const spy = jest.fn()
+ const ast = parse(code, {
+ ...parserOptions,
+ ...options,
+ onError: spy
+ })
+
+ expect(spy.mock.calls).toEqual(
+ errors.map(({ type, loc }) => [type, loc])
+ )
+ expect(ast).toMatchSnapshot()
+ }
+ )
+ }
+ })
+ }
+ })
+})
diff --git a/packages/compiler-core/src/ast.ts b/packages/compiler-core/src/ast.ts
new file mode 100644
index 00000000..8941e2b3
--- /dev/null
+++ b/packages/compiler-core/src/ast.ts
@@ -0,0 +1,87 @@
+export const enum NodeTypes {
+ TEXT,
+ COMMENT,
+ ELEMENT,
+ ATTRIBUTE,
+ EXPRESSION,
+ DIRECTIVE,
+ ROOT
+}
+
+export const enum ElementTypes {
+ ELEMENT,
+ COMPONENT,
+ SLOT, // slot
+ TEMPLATE // template, component
+}
+
+export const enum Namespaces {
+ HTML,
+ SVG, // allows CDATA section and forbids end tag omission.
+ MATH_ML // allows CDATA section and forbids end tag omission.
+}
+
+export interface Node {
+ type: NodeTypes
+ loc: SourceLocation
+}
+
+export interface RootNode extends Node {
+ type: NodeTypes.ROOT
+ children: Array
+}
+
+export interface ElementNode extends Node {
+ type: NodeTypes.ELEMENT
+ ns: Namespaces
+ tag: string
+ tagType: ElementTypes
+ isSelfClosing: boolean
+ props: Array
+ children: Array
+}
+
+export interface TextNode extends Node {
+ type: NodeTypes.TEXT
+ content: string
+ isEmpty: boolean
+}
+
+export interface CommentNode extends Node {
+ type: NodeTypes.COMMENT
+ content: string
+}
+
+export interface AttributeNode extends Node {
+ type: NodeTypes.ATTRIBUTE
+ name: string
+ value: TextNode | undefined
+}
+
+export interface DirectiveNode extends Node {
+ type: NodeTypes.DIRECTIVE
+ name: string
+ exp: ExpressionNode | undefined
+ arg: ExpressionNode | undefined
+ modifiers: string[]
+}
+
+export interface ExpressionNode extends Node {
+ type: NodeTypes.EXPRESSION
+ content: string
+ isStatic: boolean
+}
+
+export interface Position {
+ offset: number // from start of file
+ line: number
+ column: number
+}
+
+// The node's range. The `start` is inclusive and `end` is exclusive.
+// [start, end)
+export interface SourceLocation {
+ start: Position
+ end: Position
+ source: string
+}
diff --git a/packages/compiler-core/src/errorTypes.ts b/packages/compiler-core/src/errorTypes.ts
new file mode 100644
index 00000000..aad1047d
--- /dev/null
+++ b/packages/compiler-core/src/errorTypes.ts
@@ -0,0 +1,37 @@
+export const enum ParserErrorTypes {
+ ABRUPT_CLOSING_OF_EMPTY_COMMENT,
+ ABSENCE_OF_DIGITS_IN_NUMERIC_CHARACTER_REFERENCE,
+ CDATA_IN_HTML_CONTENT,
+ CHARACTER_REFERENCE_OUTSIDE_UNICODE_RANGE,
+ CONTROL_CHARACTER_REFERENCE,
+ DUPLICATE_ATTRIBUTE,
+ END_TAG_WITH_ATTRIBUTES,
+ END_TAG_WITH_TRAILING_SOLIDUS,
+ EOF_BEFORE_TAG_NAME,
+ EOF_IN_CDATA,
+ EOF_IN_COMMENT,
+ EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT,
+ EOF_IN_TAG,
+ INCORRECTLY_CLOSED_COMMENT,
+ INCORRECTLY_OPENED_COMMENT,
+ INVALID_FIRST_CHARACTER_OF_TAG_NAME,
+ MISSING_ATTRIBUTE_VALUE,
+ MISSING_END_TAG_NAME,
+ MISSING_SEMICOLON_AFTER_CHARACTER_REFERENCE,
+ MISSING_WHITESPACE_BETWEEN_ATTRIBUTES,
+ NESTED_COMMENT,
+ NONCHARACTER_CHARACTER_REFERENCE,
+ NULL_CHARACTER_REFERENCE,
+ SURROGATE_CHARACTER_REFERENCE,
+ UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME,
+ UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE,
+ UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME,
+ UNEXPECTED_NULL_CHARACTER,
+ UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME,
+ UNEXPECTED_SOLIDUS_IN_TAG,
+ UNKNOWN_NAMED_CHARACTER_REFERENCE,
+ X_INVALID_END_TAG,
+ X_MISSING_END_TAG,
+ X_MISSING_INTERPOLATION_END,
+ X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END
+}
diff --git a/packages/compiler-core/src/index.ts b/packages/compiler-core/src/index.ts
index 70b786d1..2e25f608 100644
--- a/packages/compiler-core/src/index.ts
+++ b/packages/compiler-core/src/index.ts
@@ -1 +1,3 @@
-// TODO
+export { parse } from './parser'
+export * from './ast'
+export * from './errorTypes'
diff --git a/packages/compiler-core/src/parser.ts b/packages/compiler-core/src/parser.ts
new file mode 100644
index 00000000..abb7fa81
--- /dev/null
+++ b/packages/compiler-core/src/parser.ts
@@ -0,0 +1,918 @@
+import assert from 'assert'
+import { ParserErrorTypes } from './errorTypes'
+import {
+ Node,
+ AttributeNode,
+ CommentNode,
+ DirectiveNode,
+ ElementNode,
+ ElementTypes,
+ ExpressionNode,
+ Namespaces,
+ NodeTypes,
+ Position,
+ RootNode,
+ SourceLocation,
+ TextNode
+} from './ast'
+
+export interface ParserOptions {
+ isVoidTag: (tag: string) => boolean // e.g. img, br, hr
+ getNamespace: (tag: string, parent: ElementNode | undefined) => Namespaces
+ getTextMode: (tag: string, ns: Namespaces) => TextModes
+ delimiters: [string, string] // ['{{', '}}']
+ transform: (node: Node) => Node // --
+ ignoreSpaces: boolean
+
+ // Map to HTML entities. E.g., `{ "amp;": "&" }`
+ // The full set is https://html.spec.whatwg.org/multipage/named-characters.html#named-character-references
+ namedCharacterReferences: { [name: string]: string | undefined }
+
+ onError: (type: ParserErrorTypes, loc: Position) => void
+}
+
+export const enum TextModes {
+ // | Elements | Entities | End sign | Inside of
+ DATA, // | ✔ | ✔ | End tags of ancestors |
+ RCDATA, // | ✘ | ✔ | End tag of the parent |