diff --git a/.changeset/itchy-toes-tell.md b/.changeset/itchy-toes-tell.md
new file mode 100644
index 00000000..6f2eabcf
--- /dev/null
+++ b/.changeset/itchy-toes-tell.md
@@ -0,0 +1,5 @@
+---
+"svelte-eslint-parser": patch
+---
+
+fix: crash with plain `this` attribute.
diff --git a/src/parser/converts/common.ts b/src/parser/converts/common.ts
index b04fa74d..a8c117e7 100644
--- a/src/parser/converts/common.ts
+++ b/src/parser/converts/common.ts
@@ -2,12 +2,14 @@ import type ESTree from "estree";
/** indexOf */
export function indexOf(
str: string,
- search: (c: string) => boolean,
- start: number
+ search: (c: string, index: number) => boolean,
+ start: number,
+ end?: number
): number {
- for (let index = start; index < str.length; index++) {
+ const endIndex = end ?? str.length;
+ for (let index = start; index < endIndex; index++) {
const c = str[index];
- if (search(c)) {
+ if (search(c, index)) {
return index;
}
}
diff --git a/src/parser/converts/element.ts b/src/parser/converts/element.ts
index 9373e409..9d230b80 100644
--- a/src/parser/converts/element.ts
+++ b/src/parser/converts/element.ts
@@ -1,4 +1,5 @@
import type {
+ SvelteAttribute,
SvelteAwaitBlock,
SvelteAwaitCatchBlock,
SvelteAwaitPendingBlock,
@@ -45,6 +46,7 @@ import { convertAttributes } from "./attr";
import { convertConstTag } from "./const";
import { sortNodes } from "../sort";
import type { ScriptLetBlockParam } from "../../context/script-let";
+import { ParseError } from "../..";
/* eslint-disable complexity -- X */
/** Convert for Fragment or Element or ... */
@@ -397,15 +399,113 @@ function convertSpecialElement(
node.expression) ||
(node.type === "Element" && elementName === "svelte:element" && node.tag);
if (thisExpression) {
- const eqIndex = ctx.code.lastIndexOf("=", getWithLoc(thisExpression).start);
+ processThisAttribute(node, thisExpression, element, ctx);
+ }
+
+ extractElementTags(element, ctx, {
+ buildNameNode: (openTokenRange) => {
+ ctx.addToken("HTMLIdentifier", openTokenRange);
+ const name: SvelteName = {
+ type: "SvelteName",
+ name: elementName,
+ parent: element,
+ ...ctx.getConvertLocation(openTokenRange),
+ };
+ return name;
+ },
+ });
+
+ return element;
+}
+
+/** process `this=` */
+function processThisAttribute(
+ node: SvAST.SvelteElement | SvAST.InlineSvelteComponent,
+ thisValue: string | ESTree.Expression,
+ element: SvelteSpecialElement,
+ ctx: Context
+) {
+ let thisNode: SvelteSpecialDirective | SvelteAttribute;
+ if (typeof thisValue === "string") {
+ // this="..."
+ const startIndex = findStartIndexOfThis(node, ctx);
+ const eqIndex = ctx.code.indexOf("=", startIndex + 4 /* t,h,i,s */);
+ const valueStartIndex = indexOf(
+ ctx.code,
+ (c) => Boolean(c.trim()),
+ eqIndex + 1
+ );
+ const quote = ctx.code.startsWith(thisValue, valueStartIndex)
+ ? null
+ : ctx.code[valueStartIndex];
+ const literalStartIndex = quote
+ ? valueStartIndex + quote.length
+ : valueStartIndex;
+ const literalEndIndex = literalStartIndex + thisValue.length;
+ const endIndex = quote ? literalEndIndex + quote.length : literalEndIndex;
+ const thisAttr: SvelteAttribute = {
+ type: "SvelteAttribute",
+ key: null as any,
+ boolean: false,
+ value: [],
+ parent: element.startTag,
+ ...ctx.getConvertLocation({ start: startIndex, end: endIndex }),
+ };
+ thisAttr.key = {
+ type: "SvelteName",
+ name: "this",
+ parent: thisAttr,
+ ...ctx.getConvertLocation({ start: startIndex, end: eqIndex }),
+ };
+ thisAttr.value.push({
+ type: "SvelteLiteral",
+ value: thisValue,
+ parent: thisAttr,
+ ...ctx.getConvertLocation({
+ start: literalStartIndex,
+ end: literalEndIndex,
+ }),
+ });
+ // this
+ ctx.addToken("HTMLIdentifier", {
+ start: startIndex,
+ end: startIndex + 4,
+ });
+ // =
+ ctx.addToken("Punctuator", {
+ start: eqIndex,
+ end: eqIndex + 1,
+ });
+ if (quote) {
+ // "
+ ctx.addToken("Punctuator", {
+ start: valueStartIndex,
+ end: literalStartIndex,
+ });
+ }
+ ctx.addToken("HTMLText", {
+ start: literalStartIndex,
+ end: literalEndIndex,
+ });
+ if (quote) {
+ // "
+ ctx.addToken("Punctuator", {
+ start: literalEndIndex,
+ end: endIndex,
+ });
+ }
+ thisNode = thisAttr;
+ } else {
+ // this={...}
+ const eqIndex = ctx.code.lastIndexOf("=", getWithLoc(thisValue).start);
const startIndex = ctx.code.lastIndexOf("this", eqIndex);
- const closeIndex = ctx.code.indexOf("}", getWithLoc(thisExpression).end);
+ const closeIndex = ctx.code.indexOf("}", getWithLoc(thisValue).end);
const endIndex = indexOf(
ctx.code,
(c) => c === ">" || !c.trim(),
closeIndex
);
- const thisAttr: SvelteSpecialDirective = {
+ const thisDir: SvelteSpecialDirective = {
type: "SvelteSpecialDirective",
kind: "this",
key: null as any,
@@ -413,43 +513,67 @@ function convertSpecialElement(
parent: element.startTag,
...ctx.getConvertLocation({ start: startIndex, end: endIndex }),
};
- thisAttr.key = {
+ thisDir.key = {
type: "SvelteSpecialDirectiveKey",
- parent: thisAttr,
+ parent: thisDir,
...ctx.getConvertLocation({ start: startIndex, end: eqIndex }),
};
+ // this
ctx.addToken("HTMLIdentifier", {
start: startIndex,
- end: eqIndex,
+ end: startIndex + 4,
});
- ctx.scriptLet.addExpression(thisExpression, thisAttr, null, (es) => {
- thisAttr.expression = es;
+ // =
+ ctx.addToken("Punctuator", {
+ start: eqIndex,
+ end: eqIndex + 1,
});
-
- const targetIndex = element.startTag.attributes.findIndex(
- (attr) => thisAttr.range[1] <= attr.range[0]
- );
- if (targetIndex === -1) {
- element.startTag.attributes.push(thisAttr);
- } else {
- element.startTag.attributes.splice(targetIndex, 0, thisAttr);
- }
+ ctx.scriptLet.addExpression(thisValue, thisDir, null, (es) => {
+ thisDir.expression = es;
+ });
+ thisNode = thisDir;
}
- extractElementTags(element, ctx, {
- buildNameNode: (openTokenRange) => {
- ctx.addToken("HTMLIdentifier", openTokenRange);
- const name: SvelteName = {
- type: "SvelteName",
- name: elementName,
- parent: element,
- ...ctx.getConvertLocation(openTokenRange),
- };
- return name;
- },
- });
+ const targetIndex = element.startTag.attributes.findIndex(
+ (attr) => thisNode.range[1] <= attr.range[0]
+ );
+ if (targetIndex === -1) {
+ element.startTag.attributes.push(thisNode);
+ } else {
+ element.startTag.attributes.splice(targetIndex, 0, thisNode);
+ }
+}
- return element;
+/** Find the start index of `this` */
+function findStartIndexOfThis(
+ node: SvAST.SvelteElement | SvAST.InlineSvelteComponent,
+ ctx: Context
+) {
+ // Get the end index of `svelte:element`
+ const startIndex = ctx.code.indexOf(node.name, node.start) + node.name.length;
+ const sortedAttrs = [...node.attributes].sort((a, b) => a.start - b.start);
+ // Find the start index of `this` from the end index of `svelte:element`.
+ // However, it only seeks to the start index of the first attribute (or the end index of element node).
+ let thisIndex = indexOf(
+ ctx.code,
+ (_c, index) => ctx.code.startsWith("this", index),
+ startIndex,
+ sortedAttrs[0]?.start ?? node.end
+ );
+ while (thisIndex < 0) {
+ if (sortedAttrs.length === 0)
+ throw new ParseError("Cannot resolved `this` attribute.", thisIndex, ctx);
+ // Step3: Find the start index of `this` from the end index of attribute.
+ // However, it only seeks to the start index of the first attribute (or the end index of element node).
+ const nextStartIndex = sortedAttrs.shift()!.end;
+ thisIndex = indexOf(
+ ctx.code,
+ (_c, index) => ctx.code.startsWith("this", index),
+ nextStartIndex,
+ sortedAttrs[0]?.start ?? node.end
+ );
+ }
+ return thisIndex;
}
/** Convert for ComponentElement */
diff --git a/src/parser/svelte-ast-types.ts b/src/parser/svelte-ast-types.ts
index 8c026db3..3125c887 100644
--- a/src/parser/svelte-ast-types.ts
+++ b/src/parser/svelte-ast-types.ts
@@ -117,11 +117,11 @@ export interface BaseElement extends BaseNode {
export interface BasicElement extends BaseElement {
tag?: undefined;
}
-export interface SvelteComponent extends BaseElement {
+export interface SvelteElement extends BaseElement {
name: "svelte:element";
- tag: ESTree.Expression;
+ tag: ESTree.Expression | string;
}
-export type Element = BasicElement | SvelteComponent;
+export type Element = BasicElement | SvelteElement;
export interface BaseInlineComponent extends BaseNode {
type: "InlineComponent";
diff --git a/tests/fixtures/parser/ast/this-attr04-input.svelte b/tests/fixtures/parser/ast/this-attr04-input.svelte
new file mode 100644
index 00000000..c56c9c83
--- /dev/null
+++ b/tests/fixtures/parser/ast/this-attr04-input.svelte
@@ -0,0 +1,2 @@
+
+
diff --git a/tests/fixtures/parser/ast/this-attr04-output.json b/tests/fixtures/parser/ast/this-attr04-output.json
new file mode 100644
index 00000000..eb18e9af
--- /dev/null
+++ b/tests/fixtures/parser/ast/this-attr04-output.json
@@ -0,0 +1,1193 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "SvelteElement",
+ "kind": "special",
+ "name": {
+ "type": "SvelteName",
+ "name": "svelte:element",
+ "range": [
+ 1,
+ 15
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 1
+ },
+ "end": {
+ "line": 1,
+ "column": 15
+ }
+ }
+ },
+ "startTag": {
+ "type": "SvelteStartTag",
+ "attributes": [
+ {
+ "type": "SvelteAttribute",
+ "key": {
+ "type": "SvelteName",
+ "name": "class",
+ "range": [
+ 16,
+ 21
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 16
+ },
+ "end": {
+ "line": 1,
+ "column": 21
+ }
+ }
+ },
+ "boolean": false,
+ "value": [
+ {
+ "type": "SvelteLiteral",
+ "value": "foo",
+ "range": [
+ 23,
+ 26
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 23
+ },
+ "end": {
+ "line": 1,
+ "column": 26
+ }
+ }
+ }
+ ],
+ "range": [
+ 16,
+ 27
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 16
+ },
+ "end": {
+ "line": 1,
+ "column": 27
+ }
+ }
+ },
+ {
+ "type": "SvelteAttribute",
+ "key": {
+ "type": "SvelteName",
+ "name": "this",
+ "range": [
+ 28,
+ 32
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 28
+ },
+ "end": {
+ "line": 1,
+ "column": 32
+ }
+ }
+ },
+ "boolean": false,
+ "value": [
+ {
+ "type": "SvelteLiteral",
+ "value": "input",
+ "range": [
+ 34,
+ 39
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 34
+ },
+ "end": {
+ "line": 1,
+ "column": 39
+ }
+ }
+ }
+ ],
+ "range": [
+ 28,
+ 40
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 28
+ },
+ "end": {
+ "line": 1,
+ "column": 40
+ }
+ }
+ },
+ {
+ "type": "SvelteAttribute",
+ "key": {
+ "type": "SvelteName",
+ "name": "type",
+ "range": [
+ 41,
+ 45
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 41
+ },
+ "end": {
+ "line": 1,
+ "column": 45
+ }
+ }
+ },
+ "boolean": false,
+ "value": [
+ {
+ "type": "SvelteLiteral",
+ "value": "number",
+ "range": [
+ 47,
+ 53
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 47
+ },
+ "end": {
+ "line": 1,
+ "column": 53
+ }
+ }
+ }
+ ],
+ "range": [
+ 41,
+ 54
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 41
+ },
+ "end": {
+ "line": 1,
+ "column": 54
+ }
+ }
+ }
+ ],
+ "selfClosing": true,
+ "range": [
+ 0,
+ 56
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 0
+ },
+ "end": {
+ "line": 1,
+ "column": 56
+ }
+ }
+ },
+ "children": [],
+ "endTag": null,
+ "range": [
+ 0,
+ 56
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 0
+ },
+ "end": {
+ "line": 1,
+ "column": 56
+ }
+ }
+ },
+ {
+ "type": "SvelteText",
+ "value": "\n",
+ "range": [
+ 56,
+ 57
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 56
+ },
+ "end": {
+ "line": 2,
+ "column": 0
+ }
+ }
+ },
+ {
+ "type": "SvelteElement",
+ "kind": "special",
+ "name": {
+ "type": "SvelteName",
+ "name": "svelte:element",
+ "range": [
+ 58,
+ 72
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 1
+ },
+ "end": {
+ "line": 2,
+ "column": 15
+ }
+ }
+ },
+ "startTag": {
+ "type": "SvelteStartTag",
+ "attributes": [
+ {
+ "type": "SvelteAttribute",
+ "key": {
+ "type": "SvelteName",
+ "name": "class",
+ "range": [
+ 73,
+ 78
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 16
+ },
+ "end": {
+ "line": 2,
+ "column": 21
+ }
+ }
+ },
+ "boolean": false,
+ "value": [
+ {
+ "type": "SvelteLiteral",
+ "value": "foo",
+ "range": [
+ 80,
+ 83
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 23
+ },
+ "end": {
+ "line": 2,
+ "column": 26
+ }
+ }
+ }
+ ],
+ "range": [
+ 73,
+ 84
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 16
+ },
+ "end": {
+ "line": 2,
+ "column": 27
+ }
+ }
+ },
+ {
+ "type": "SvelteSpecialDirective",
+ "kind": "this",
+ "key": {
+ "type": "SvelteSpecialDirectiveKey",
+ "range": [
+ 85,
+ 89
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 28
+ },
+ "end": {
+ "line": 2,
+ "column": 32
+ }
+ }
+ },
+ "expression": {
+ "type": "Literal",
+ "raw": "\"input\"",
+ "value": "input",
+ "range": [
+ 91,
+ 98
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 34
+ },
+ "end": {
+ "line": 2,
+ "column": 41
+ }
+ }
+ },
+ "range": [
+ 85,
+ 99
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 28
+ },
+ "end": {
+ "line": 2,
+ "column": 42
+ }
+ }
+ },
+ {
+ "type": "SvelteAttribute",
+ "key": {
+ "type": "SvelteName",
+ "name": "type",
+ "range": [
+ 100,
+ 104
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 43
+ },
+ "end": {
+ "line": 2,
+ "column": 47
+ }
+ }
+ },
+ "boolean": false,
+ "value": [
+ {
+ "type": "SvelteLiteral",
+ "value": "number",
+ "range": [
+ 106,
+ 112
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 49
+ },
+ "end": {
+ "line": 2,
+ "column": 55
+ }
+ }
+ }
+ ],
+ "range": [
+ 100,
+ 113
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 43
+ },
+ "end": {
+ "line": 2,
+ "column": 56
+ }
+ }
+ }
+ ],
+ "selfClosing": true,
+ "range": [
+ 57,
+ 115
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 0
+ },
+ "end": {
+ "line": 2,
+ "column": 58
+ }
+ }
+ },
+ "children": [],
+ "endTag": null,
+ "range": [
+ 57,
+ 115
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 0
+ },
+ "end": {
+ "line": 2,
+ "column": 58
+ }
+ }
+ }
+ ],
+ "sourceType": "module",
+ "comments": [],
+ "tokens": [
+ {
+ "type": "Punctuator",
+ "value": "<",
+ "range": [
+ 0,
+ 1
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 0
+ },
+ "end": {
+ "line": 1,
+ "column": 1
+ }
+ }
+ },
+ {
+ "type": "HTMLIdentifier",
+ "value": "svelte:element",
+ "range": [
+ 1,
+ 15
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 1
+ },
+ "end": {
+ "line": 1,
+ "column": 15
+ }
+ }
+ },
+ {
+ "type": "HTMLIdentifier",
+ "value": "class",
+ "range": [
+ 16,
+ 21
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 16
+ },
+ "end": {
+ "line": 1,
+ "column": 21
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "=",
+ "range": [
+ 21,
+ 22
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 21
+ },
+ "end": {
+ "line": 1,
+ "column": 22
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "\"",
+ "range": [
+ 22,
+ 23
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 22
+ },
+ "end": {
+ "line": 1,
+ "column": 23
+ }
+ }
+ },
+ {
+ "type": "HTMLText",
+ "value": "foo",
+ "range": [
+ 23,
+ 26
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 23
+ },
+ "end": {
+ "line": 1,
+ "column": 26
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "\"",
+ "range": [
+ 26,
+ 27
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 26
+ },
+ "end": {
+ "line": 1,
+ "column": 27
+ }
+ }
+ },
+ {
+ "type": "HTMLIdentifier",
+ "value": "this",
+ "range": [
+ 28,
+ 32
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 28
+ },
+ "end": {
+ "line": 1,
+ "column": 32
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "=",
+ "range": [
+ 32,
+ 33
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 32
+ },
+ "end": {
+ "line": 1,
+ "column": 33
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "\"",
+ "range": [
+ 33,
+ 34
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 33
+ },
+ "end": {
+ "line": 1,
+ "column": 34
+ }
+ }
+ },
+ {
+ "type": "HTMLText",
+ "value": "input",
+ "range": [
+ 34,
+ 39
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 34
+ },
+ "end": {
+ "line": 1,
+ "column": 39
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "\"",
+ "range": [
+ 39,
+ 40
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 39
+ },
+ "end": {
+ "line": 1,
+ "column": 40
+ }
+ }
+ },
+ {
+ "type": "HTMLIdentifier",
+ "value": "type",
+ "range": [
+ 41,
+ 45
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 41
+ },
+ "end": {
+ "line": 1,
+ "column": 45
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "=",
+ "range": [
+ 45,
+ 46
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 45
+ },
+ "end": {
+ "line": 1,
+ "column": 46
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "\"",
+ "range": [
+ 46,
+ 47
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 46
+ },
+ "end": {
+ "line": 1,
+ "column": 47
+ }
+ }
+ },
+ {
+ "type": "HTMLText",
+ "value": "number",
+ "range": [
+ 47,
+ 53
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 47
+ },
+ "end": {
+ "line": 1,
+ "column": 53
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "\"",
+ "range": [
+ 53,
+ 54
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 53
+ },
+ "end": {
+ "line": 1,
+ "column": 54
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "/",
+ "range": [
+ 54,
+ 55
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 54
+ },
+ "end": {
+ "line": 1,
+ "column": 55
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": ">",
+ "range": [
+ 55,
+ 56
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 55
+ },
+ "end": {
+ "line": 1,
+ "column": 56
+ }
+ }
+ },
+ {
+ "type": "HTMLText",
+ "value": "\n",
+ "range": [
+ 56,
+ 57
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 56
+ },
+ "end": {
+ "line": 2,
+ "column": 0
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "<",
+ "range": [
+ 57,
+ 58
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 0
+ },
+ "end": {
+ "line": 2,
+ "column": 1
+ }
+ }
+ },
+ {
+ "type": "HTMLIdentifier",
+ "value": "svelte:element",
+ "range": [
+ 58,
+ 72
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 1
+ },
+ "end": {
+ "line": 2,
+ "column": 15
+ }
+ }
+ },
+ {
+ "type": "HTMLIdentifier",
+ "value": "class",
+ "range": [
+ 73,
+ 78
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 16
+ },
+ "end": {
+ "line": 2,
+ "column": 21
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "=",
+ "range": [
+ 78,
+ 79
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 21
+ },
+ "end": {
+ "line": 2,
+ "column": 22
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "\"",
+ "range": [
+ 79,
+ 80
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 22
+ },
+ "end": {
+ "line": 2,
+ "column": 23
+ }
+ }
+ },
+ {
+ "type": "HTMLText",
+ "value": "foo",
+ "range": [
+ 80,
+ 83
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 23
+ },
+ "end": {
+ "line": 2,
+ "column": 26
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "\"",
+ "range": [
+ 83,
+ 84
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 26
+ },
+ "end": {
+ "line": 2,
+ "column": 27
+ }
+ }
+ },
+ {
+ "type": "HTMLIdentifier",
+ "value": "this",
+ "range": [
+ 85,
+ 89
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 28
+ },
+ "end": {
+ "line": 2,
+ "column": 32
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "=",
+ "range": [
+ 89,
+ 90
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 32
+ },
+ "end": {
+ "line": 2,
+ "column": 33
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "{",
+ "range": [
+ 90,
+ 91
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 33
+ },
+ "end": {
+ "line": 2,
+ "column": 34
+ }
+ }
+ },
+ {
+ "type": "String",
+ "value": "\"input\"",
+ "range": [
+ 91,
+ 98
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 34
+ },
+ "end": {
+ "line": 2,
+ "column": 41
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "}",
+ "range": [
+ 98,
+ 99
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 41
+ },
+ "end": {
+ "line": 2,
+ "column": 42
+ }
+ }
+ },
+ {
+ "type": "HTMLIdentifier",
+ "value": "type",
+ "range": [
+ 100,
+ 104
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 43
+ },
+ "end": {
+ "line": 2,
+ "column": 47
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "=",
+ "range": [
+ 104,
+ 105
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 47
+ },
+ "end": {
+ "line": 2,
+ "column": 48
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "\"",
+ "range": [
+ 105,
+ 106
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 48
+ },
+ "end": {
+ "line": 2,
+ "column": 49
+ }
+ }
+ },
+ {
+ "type": "HTMLText",
+ "value": "number",
+ "range": [
+ 106,
+ 112
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 49
+ },
+ "end": {
+ "line": 2,
+ "column": 55
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "\"",
+ "range": [
+ 112,
+ 113
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 55
+ },
+ "end": {
+ "line": 2,
+ "column": 56
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": "/",
+ "range": [
+ 113,
+ 114
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 56
+ },
+ "end": {
+ "line": 2,
+ "column": 57
+ }
+ }
+ },
+ {
+ "type": "Punctuator",
+ "value": ">",
+ "range": [
+ 114,
+ 115
+ ],
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 57
+ },
+ "end": {
+ "line": 2,
+ "column": 58
+ }
+ }
+ }
+ ],
+ "range": [
+ 0,
+ 116
+ ],
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 0
+ },
+ "end": {
+ "line": 3,
+ "column": 0
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/fixtures/parser/ast/this-attr04-scope-output.json b/tests/fixtures/parser/ast/this-attr04-scope-output.json
new file mode 100644
index 00000000..d392ca4b
--- /dev/null
+++ b/tests/fixtures/parser/ast/this-attr04-scope-output.json
@@ -0,0 +1,34 @@
+{
+ "type": "global",
+ "variables": [
+ {
+ "name": "$$slots",
+ "identifiers": [],
+ "defs": [],
+ "references": []
+ },
+ {
+ "name": "$$props",
+ "identifiers": [],
+ "defs": [],
+ "references": []
+ },
+ {
+ "name": "$$restProps",
+ "identifiers": [],
+ "defs": [],
+ "references": []
+ }
+ ],
+ "references": [],
+ "childScopes": [
+ {
+ "type": "module",
+ "variables": [],
+ "references": [],
+ "childScopes": [],
+ "through": []
+ }
+ ],
+ "through": []
+}
\ No newline at end of file