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

Lines changed: 5 additions & 0 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 31 additions & 3 deletions
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

Lines changed: 59 additions & 21 deletions
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+
}
Lines changed: 8 additions & 0 deletions
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 -->
Lines changed: 8 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy