Skip to content

Commit

Permalink
fix: parsing error when use with member expr (#249)
Browse files Browse the repository at this point in the history
* fix: parsing error when use with member expr

* add changeset

* fix ts-parser version

* refactor

* fix comment
  • Loading branch information
ota-meshi authored Nov 24, 2022
1 parent 46fd573 commit d560864
Show file tree
Hide file tree
Showing 32 changed files with 4,363 additions and 206 deletions.
5 changes: 5 additions & 0 deletions .changeset/swift-dolphins-complain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"svelte-eslint-parser": minor
---

fix: parsing error when use with member expr
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"@types/node": "^18.11.0",
"@types/semver": "^7.3.9",
"@typescript-eslint/eslint-plugin": "^5.4.0",
"@typescript-eslint/parser": "^5.4.0",
"@typescript-eslint/parser": "~5.43.0",
"benchmark": "^2.1.4",
"chai": "^4.3.4",
"code-red": "^0.2.3",
Expand Down
34 changes: 31 additions & 3 deletions src/ast/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -491,12 +491,30 @@ export type SvelteDirective =
| SvelteLetDirective
| SvelteRefDirective
| SvelteTransitionDirective;
export interface SvelteDirectiveKey extends BaseNode {

export type SvelteDirectiveKey =
| SvelteDirectiveKeyTextName
| SvelteDirectiveKeyFunctionName
| SvelteDirectiveKeyForEventHandler
| SvelteDirectiveKeyForAction
| SvelteDirectiveKeyForStyleShorthand;
interface BaseSvelteDirectiveKey<N extends ESTree.Expression | SvelteName>
extends BaseNode {
type: "SvelteDirectiveKey";
name: ESTree.Identifier | SvelteName;
name: N;
modifiers: string[];
parent: SvelteDirective | SvelteStyleDirective;
}
export type SvelteDirectiveKeyTextName = BaseSvelteDirectiveKey<SvelteName>;
export type SvelteDirectiveKeyFunctionName =
BaseSvelteDirectiveKey<ESTree.Identifier>;
export type SvelteDirectiveKeyForEventHandler =
BaseSvelteDirectiveKey<SvelteName>;
export type SvelteDirectiveKeyForAction = BaseSvelteDirectiveKey<
ESTree.Identifier | ESTree.MemberExpression | SvelteName
>;
export type SvelteDirectiveKeyForStyleShorthand =
BaseSvelteDirectiveKey<ESTree.Identifier>;

interface BaseSvelteDirective extends BaseNode {
type: "SvelteDirective";
Expand All @@ -506,36 +524,44 @@ interface BaseSvelteDirective extends BaseNode {

export interface SvelteActionDirective extends BaseSvelteDirective {
kind: "Action";
key: SvelteDirectiveKeyForAction;
expression: null | ESTree.Expression;
}
export interface SvelteAnimationDirective extends BaseSvelteDirective {
kind: "Animation";
key: SvelteDirectiveKeyFunctionName;
expression: null | ESTree.Expression;
}
export interface SvelteBindingDirective extends BaseSvelteDirective {
kind: "Binding";
key: SvelteDirectiveKeyTextName;
shorthand: boolean;
expression: null | ESTree.Expression;
}
export interface SvelteClassDirective extends BaseSvelteDirective {
kind: "Class";
key: SvelteDirectiveKeyTextName;
shorthand: boolean;
expression: null | ESTree.Expression;
}
export interface SvelteEventHandlerDirective extends BaseSvelteDirective {
kind: "EventHandler";
key: SvelteDirectiveKeyForEventHandler;
expression: null | ESTree.Expression;
}
export interface SvelteLetDirective extends BaseSvelteDirective {
kind: "Let";
key: SvelteDirectiveKeyTextName;
expression: null | ESTree.Pattern;
}
export interface SvelteRefDirective extends BaseSvelteDirective {
kind: "Ref";
key: SvelteDirectiveKeyTextName;
expression: null | ESTree.Expression;
}
export interface SvelteTransitionDirective extends BaseSvelteDirective {
kind: "Transition";
key: SvelteDirectiveKeyFunctionName;
intro: boolean;
outro: boolean;
expression: null | ESTree.Expression;
Expand All @@ -547,16 +573,18 @@ export type SvelteStyleDirective =
| SvelteStyleDirectiveLongform;
interface BaseSvelteStyleDirective extends BaseNode {
type: "SvelteStyleDirective";
key: SvelteDirectiveKey;
key: SvelteDirectiveKeyTextName | SvelteDirectiveKeyForStyleShorthand;
value: (SvelteLiteral | SvelteMustacheTagText)[];
parent: SvelteStartTag;
}
export interface SvelteStyleDirectiveShorthand
extends BaseSvelteStyleDirective {
key: SvelteDirectiveKeyForStyleShorthand;
shorthand: true;
value: [];
}
export interface SvelteStyleDirectiveLongform extends BaseSvelteStyleDirective {
key: SvelteDirectiveKeyTextName;
shorthand: false;
value: (SvelteLiteral | SvelteMustacheTagText)[];
}
Expand Down
80 changes: 59 additions & 21 deletions src/parser/converts/attr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ function convertStyleDirective(
parent: SvelteStyleDirective["parent"],
ctx: Context
): SvelteStyleDirective {
const directive: SvelteStyleDirective = {
const directive: SvelteStyleDirectiveLongform = {
type: "SvelteStyleDirective",
key: null as any,
shorthand: false,
Expand All @@ -379,20 +379,27 @@ function convertStyleDirective(
};
processDirectiveKey(node, directive, ctx);

const keyName = directive.key.name as SvelteName;
const keyName = directive.key.name;
if (node.value === true) {
(directive as unknown as SvelteStyleDirectiveShorthand).shorthand = true;
ctx.scriptLet.addExpression(keyName, directive.key, null, (expression) => {
if (expression.type !== "Identifier") {
throw new ParseError(
`Expected JS identifier or attribute value.`,
expression.range![0],
ctx
);
const shorthandDirective =
directive as unknown as SvelteStyleDirectiveShorthand;
shorthandDirective.shorthand = true;
ctx.scriptLet.addExpression(
keyName,
shorthandDirective.key,
null,
(expression) => {
if (expression.type !== "Identifier") {
throw new ParseError(
`Expected JS identifier or attribute value.`,
expression.range![0],
ctx
);
}
shorthandDirective.key.name = expression;
}
directive.key.name = expression;
});
return directive;
);
return shorthandDirective;
}
ctx.addToken("HTMLIdentifier", {
start: keyName.range[0],
Expand Down Expand Up @@ -426,7 +433,13 @@ function convertTransitionDirective(
ctx,
null
),
processName: (name) => ctx.scriptLet.addExpression(name, directive.key),
processName: (name) =>
ctx.scriptLet.addExpression(
name,
directive.key,
null,
buildExpressionTypeChecker(["Identifier"], ctx)
),
});
return directive;
}
Expand All @@ -451,7 +464,13 @@ function convertAnimationDirective(
ctx,
null
),
processName: (name) => ctx.scriptLet.addExpression(name, directive.key),
processName: (name) =>
ctx.scriptLet.addExpression(
name,
directive.key,
null,
buildExpressionTypeChecker(["Identifier"], ctx)
),
});
return directive;
}
Expand All @@ -476,7 +495,13 @@ function convertActionDirective(
ctx,
null
),
processName: (name) => ctx.scriptLet.addExpression(name, directive.key),
processName: (name) =>
ctx.scriptLet.addExpression(
name,
directive.key,
null,
buildExpressionTypeChecker(["Identifier", "MemberExpression"], ctx)
),
});
return directive;
}
Expand Down Expand Up @@ -529,7 +554,7 @@ type DirectiveProcessors<
processPattern?: undefined;
processName?: (
expression: SvelteName
) => ScriptLetCallback<ESTree.Identifier>[];
) => ScriptLetCallback<Exclude<S["key"]["name"], SvelteName>>[];
}
| {
processExpression?: undefined;
Expand All @@ -539,7 +564,7 @@ type DirectiveProcessors<
) => ScriptLetCallback<NonNullable<E>>[];
processName?: (
expression: SvelteName
) => ScriptLetCallback<ESTree.Identifier>[];
) => ScriptLetCallback<Exclude<S["key"]["name"], SvelteName>>[];
};

/** Common process for directive */
Expand Down Expand Up @@ -658,9 +683,6 @@ function processDirectiveExpression<
if (!shorthand) {
if (processors.processName) {
processors.processName(keyName).push((es) => {
if (es.type !== "Identifier") {
throw new ParseError(`Expected JS identifier.`, es.range![0], ctx);
}
key.name = es;
});
} else {
Expand All @@ -682,3 +704,19 @@ function buildProcessExpressionForExpression(
return ctx.scriptLet.addExpression(expression, directive, typing);
};
}

/** Build expression type checker to script let callbacks */
function buildExpressionTypeChecker<T extends ESTree.Expression>(
expected: T["type"][],
ctx: Context
): ScriptLetCallback<T> {
return (node) => {
if (!expected.includes(node.type)) {
throw new ParseError(
`Expected JS ${expected.join(", or ")}, but ${node.type} found.`,
node.range![0],
ctx
);
}
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script>
import Inner from './Inner.svelte'
const foo = { bar: () => alert('foo.bar') }
</script>

<Inner on:foo.bar/> <!-- bubble (not member) -->

<!-- https://svelte.dev/repl/d6f31e9c5b784f8bb6bc3abd2c7153a7?version=3.52.0 -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
{
"ruleId": "no-unused-vars",
"code": "foo",
"line": 3,
"column": 8
}
]
Loading

0 comments on commit d560864

Please sign in to comment.