Skip to content

Commit d560864

Browse files
authored
fix: parsing error when use with member expr (#249)
* fix: parsing error when use with member expr * add changeset * fix ts-parser version * refactor * fix comment
1 parent 46fd573 commit d560864

32 files changed

+4363
-206
lines changed

.changeset/swift-dolphins-complain.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte-eslint-parser": minor
3+
---
4+
5+
fix: parsing error when use with member expr

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
"@types/node": "^18.11.0",
6464
"@types/semver": "^7.3.9",
6565
"@typescript-eslint/eslint-plugin": "^5.4.0",
66-
"@typescript-eslint/parser": "^5.4.0",
66+
"@typescript-eslint/parser": "~5.43.0",
6767
"benchmark": "^2.1.4",
6868
"chai": "^4.3.4",
6969
"code-red": "^0.2.3",

src/ast/html.ts

+31-3
Original file line numberDiff line numberDiff line change
@@ -491,12 +491,30 @@ export type SvelteDirective =
491491
| SvelteLetDirective
492492
| SvelteRefDirective
493493
| SvelteTransitionDirective;
494-
export interface SvelteDirectiveKey extends BaseNode {
494+
495+
export type SvelteDirectiveKey =
496+
| SvelteDirectiveKeyTextName
497+
| SvelteDirectiveKeyFunctionName
498+
| SvelteDirectiveKeyForEventHandler
499+
| SvelteDirectiveKeyForAction
500+
| SvelteDirectiveKeyForStyleShorthand;
501+
interface BaseSvelteDirectiveKey<N extends ESTree.Expression | SvelteName>
502+
extends BaseNode {
495503
type: "SvelteDirectiveKey";
496-
name: ESTree.Identifier | SvelteName;
504+
name: N;
497505
modifiers: string[];
498506
parent: SvelteDirective | SvelteStyleDirective;
499507
}
508+
export type SvelteDirectiveKeyTextName = BaseSvelteDirectiveKey<SvelteName>;
509+
export type SvelteDirectiveKeyFunctionName =
510+
BaseSvelteDirectiveKey<ESTree.Identifier>;
511+
export type SvelteDirectiveKeyForEventHandler =
512+
BaseSvelteDirectiveKey<SvelteName>;
513+
export type SvelteDirectiveKeyForAction = BaseSvelteDirectiveKey<
514+
ESTree.Identifier | ESTree.MemberExpression | SvelteName
515+
>;
516+
export type SvelteDirectiveKeyForStyleShorthand =
517+
BaseSvelteDirectiveKey<ESTree.Identifier>;
500518

501519
interface BaseSvelteDirective extends BaseNode {
502520
type: "SvelteDirective";
@@ -506,36 +524,44 @@ interface BaseSvelteDirective extends BaseNode {
506524

507525
export interface SvelteActionDirective extends BaseSvelteDirective {
508526
kind: "Action";
527+
key: SvelteDirectiveKeyForAction;
509528
expression: null | ESTree.Expression;
510529
}
511530
export interface SvelteAnimationDirective extends BaseSvelteDirective {
512531
kind: "Animation";
532+
key: SvelteDirectiveKeyFunctionName;
513533
expression: null | ESTree.Expression;
514534
}
515535
export interface SvelteBindingDirective extends BaseSvelteDirective {
516536
kind: "Binding";
537+
key: SvelteDirectiveKeyTextName;
517538
shorthand: boolean;
518539
expression: null | ESTree.Expression;
519540
}
520541
export interface SvelteClassDirective extends BaseSvelteDirective {
521542
kind: "Class";
543+
key: SvelteDirectiveKeyTextName;
522544
shorthand: boolean;
523545
expression: null | ESTree.Expression;
524546
}
525547
export interface SvelteEventHandlerDirective extends BaseSvelteDirective {
526548
kind: "EventHandler";
549+
key: SvelteDirectiveKeyForEventHandler;
527550
expression: null | ESTree.Expression;
528551
}
529552
export interface SvelteLetDirective extends BaseSvelteDirective {
530553
kind: "Let";
554+
key: SvelteDirectiveKeyTextName;
531555
expression: null | ESTree.Pattern;
532556
}
533557
export interface SvelteRefDirective extends BaseSvelteDirective {
534558
kind: "Ref";
559+
key: SvelteDirectiveKeyTextName;
535560
expression: null | ESTree.Expression;
536561
}
537562
export interface SvelteTransitionDirective extends BaseSvelteDirective {
538563
kind: "Transition";
564+
key: SvelteDirectiveKeyFunctionName;
539565
intro: boolean;
540566
outro: boolean;
541567
expression: null | ESTree.Expression;
@@ -547,16 +573,18 @@ export type SvelteStyleDirective =
547573
| SvelteStyleDirectiveLongform;
548574
interface BaseSvelteStyleDirective extends BaseNode {
549575
type: "SvelteStyleDirective";
550-
key: SvelteDirectiveKey;
576+
key: SvelteDirectiveKeyTextName | SvelteDirectiveKeyForStyleShorthand;
551577
value: (SvelteLiteral | SvelteMustacheTagText)[];
552578
parent: SvelteStartTag;
553579
}
554580
export interface SvelteStyleDirectiveShorthand
555581
extends BaseSvelteStyleDirective {
582+
key: SvelteDirectiveKeyForStyleShorthand;
556583
shorthand: true;
557584
value: [];
558585
}
559586
export interface SvelteStyleDirectiveLongform extends BaseSvelteStyleDirective {
587+
key: SvelteDirectiveKeyTextName;
560588
shorthand: false;
561589
value: (SvelteLiteral | SvelteMustacheTagText)[];
562590
}

src/parser/converts/attr.ts

+59-21
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ function convertStyleDirective(
369369
parent: SvelteStyleDirective["parent"],
370370
ctx: Context
371371
): SvelteStyleDirective {
372-
const directive: SvelteStyleDirective = {
372+
const directive: SvelteStyleDirectiveLongform = {
373373
type: "SvelteStyleDirective",
374374
key: null as any,
375375
shorthand: false,
@@ -379,20 +379,27 @@ function convertStyleDirective(
379379
};
380380
processDirectiveKey(node, directive, ctx);
381381

382-
const keyName = directive.key.name as SvelteName;
382+
const keyName = directive.key.name;
383383
if (node.value === true) {
384-
(directive as unknown as SvelteStyleDirectiveShorthand).shorthand = true;
385-
ctx.scriptLet.addExpression(keyName, directive.key, null, (expression) => {
386-
if (expression.type !== "Identifier") {
387-
throw new ParseError(
388-
`Expected JS identifier or attribute value.`,
389-
expression.range![0],
390-
ctx
391-
);
384+
const shorthandDirective =
385+
directive as unknown as SvelteStyleDirectiveShorthand;
386+
shorthandDirective.shorthand = true;
387+
ctx.scriptLet.addExpression(
388+
keyName,
389+
shorthandDirective.key,
390+
null,
391+
(expression) => {
392+
if (expression.type !== "Identifier") {
393+
throw new ParseError(
394+
`Expected JS identifier or attribute value.`,
395+
expression.range![0],
396+
ctx
397+
);
398+
}
399+
shorthandDirective.key.name = expression;
392400
}
393-
directive.key.name = expression;
394-
});
395-
return directive;
401+
);
402+
return shorthandDirective;
396403
}
397404
ctx.addToken("HTMLIdentifier", {
398405
start: keyName.range[0],
@@ -426,7 +433,13 @@ function convertTransitionDirective(
426433
ctx,
427434
null
428435
),
429-
processName: (name) => ctx.scriptLet.addExpression(name, directive.key),
436+
processName: (name) =>
437+
ctx.scriptLet.addExpression(
438+
name,
439+
directive.key,
440+
null,
441+
buildExpressionTypeChecker(["Identifier"], ctx)
442+
),
430443
});
431444
return directive;
432445
}
@@ -451,7 +464,13 @@ function convertAnimationDirective(
451464
ctx,
452465
null
453466
),
454-
processName: (name) => ctx.scriptLet.addExpression(name, directive.key),
467+
processName: (name) =>
468+
ctx.scriptLet.addExpression(
469+
name,
470+
directive.key,
471+
null,
472+
buildExpressionTypeChecker(["Identifier"], ctx)
473+
),
455474
});
456475
return directive;
457476
}
@@ -476,7 +495,13 @@ function convertActionDirective(
476495
ctx,
477496
null
478497
),
479-
processName: (name) => ctx.scriptLet.addExpression(name, directive.key),
498+
processName: (name) =>
499+
ctx.scriptLet.addExpression(
500+
name,
501+
directive.key,
502+
null,
503+
buildExpressionTypeChecker(["Identifier", "MemberExpression"], ctx)
504+
),
480505
});
481506
return directive;
482507
}
@@ -529,7 +554,7 @@ type DirectiveProcessors<
529554
processPattern?: undefined;
530555
processName?: (
531556
expression: SvelteName
532-
) => ScriptLetCallback<ESTree.Identifier>[];
557+
) => ScriptLetCallback<Exclude<S["key"]["name"], SvelteName>>[];
533558
}
534559
| {
535560
processExpression?: undefined;
@@ -539,7 +564,7 @@ type DirectiveProcessors<
539564
) => ScriptLetCallback<NonNullable<E>>[];
540565
processName?: (
541566
expression: SvelteName
542-
) => ScriptLetCallback<ESTree.Identifier>[];
567+
) => ScriptLetCallback<Exclude<S["key"]["name"], SvelteName>>[];
543568
};
544569

545570
/** Common process for directive */
@@ -658,9 +683,6 @@ function processDirectiveExpression<
658683
if (!shorthand) {
659684
if (processors.processName) {
660685
processors.processName(keyName).push((es) => {
661-
if (es.type !== "Identifier") {
662-
throw new ParseError(`Expected JS identifier.`, es.range![0], ctx);
663-
}
664686
key.name = es;
665687
});
666688
} else {
@@ -682,3 +704,19 @@ function buildProcessExpressionForExpression(
682704
return ctx.scriptLet.addExpression(expression, directive, typing);
683705
};
684706
}
707+
708+
/** Build expression type checker to script let callbacks */
709+
function buildExpressionTypeChecker<T extends ESTree.Expression>(
710+
expected: T["type"][],
711+
ctx: Context
712+
): ScriptLetCallback<T> {
713+
return (node) => {
714+
if (!expected.includes(node.type)) {
715+
throw new ParseError(
716+
`Expected JS ${expected.join(", or ")}, but ${node.type} found.`,
717+
node.range![0],
718+
ctx
719+
);
720+
}
721+
};
722+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<script>
2+
import Inner from './Inner.svelte'
3+
const foo = { bar: () => alert('foo.bar') }
4+
</script>
5+
6+
<Inner on:foo.bar/> <!-- bubble (not member) -->
7+
8+
<!-- https://svelte.dev/repl/d6f31e9c5b784f8bb6bc3abd2c7153a7?version=3.52.0 -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[
2+
{
3+
"ruleId": "no-unused-vars",
4+
"code": "foo",
5+
"line": 3,
6+
"column": 8
7+
}
8+
]

0 commit comments

Comments
 (0)