From b1f2d7f9b953c3af1fd797a84b23f93ba800eb17 Mon Sep 17 00:00:00 2001 From: yosuke ota Date: Thu, 11 Jul 2024 11:04:39 +0900 Subject: [PATCH] fix: update svelte to 5.0.0-next.181 and fix for `{:else if}` --- package.json | 30 ++--- src/context/index.ts | 16 +-- src/parser/compat.ts | 2 +- src/parser/converts/attr.ts | 2 +- src/parser/converts/block.ts | 34 ++--- src/parser/converts/const.ts | 2 +- src/parser/converts/element.ts | 2 +- src/parser/converts/mustache.ts | 2 +- src/parser/converts/render.ts | 2 +- src/parser/converts/root.ts | 2 +- src/parser/html.ts | 2 +- src/parser/index.ts | 2 +- src/parser/svelte-ast-types-for-v5.ts | 116 ++++++++++++++++++ src/parser/svelte-parse-context.ts | 2 +- src/parser/template.ts | 2 +- .../10-typing-snippets-type-output.svelte | 10 +- .../11-typing-snippets-type-output.svelte | 10 +- .../generics01-snippets-type-output.svelte | 10 +- 18 files changed, 177 insertions(+), 71 deletions(-) create mode 100644 src/parser/svelte-ast-types-for-v5.ts diff --git a/package.json b/package.json index bc33f529..53698d05 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "version:ci": "env-cmd -e version-ci pnpm run build:meta && changeset version" }, "peerDependencies": { - "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0-next.115" + "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0-next.181" }, "peerDependenciesMeta": { "svelte": { @@ -58,13 +58,13 @@ "eslint-scope": "^7.2.2", "eslint-visitor-keys": "^3.4.3", "espree": "^9.6.1", - "postcss": "^8.4.38", + "postcss": "^8.4.39", "postcss-scss": "^4.0.9" }, "devDependencies": { "@changesets/changelog-github": "^0.5.0", - "@changesets/cli": "^2.27.5", - "@changesets/get-release-plan": "^4.0.2", + "@changesets/cli": "^2.27.7", + "@changesets/get-release-plan": "^4.0.3", "@ota-meshi/eslint-plugin": "^0.15.3", "@types/benchmark": "^2.1.5", "@types/chai": "^4.3.16", @@ -72,10 +72,10 @@ "@types/eslint-scope": "^3.7.7", "@types/eslint-visitor-keys": "^3.3.0", "@types/estree": "^1.0.5", - "@types/mocha": "^10.0.6", - "@types/node": "^20.14.4", + "@types/mocha": "^10.0.7", + "@types/node": "^20.14.10", "@types/semver": "^7.5.8", - "@typescript-eslint/eslint-plugin": "^7.13.1", + "@typescript-eslint/eslint-plugin": "^7.16.0", "@typescript-eslint/parser": "~7.13.1", "@typescript-eslint/types": "~7.13.1", "benchmark": "^2.1.4", @@ -86,28 +86,28 @@ "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-eslint-comments": "^3.2.0", - "eslint-plugin-json-schema-validator": "^5.1.0", + "eslint-plugin-json-schema-validator": "^5.1.2", "eslint-plugin-jsonc": "^2.16.0", "eslint-plugin-n": "^17.9.0", "eslint-plugin-node-dependencies": "^0.12.0", "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-regexp": "^2.6.0", - "eslint-plugin-svelte": "^2.40.0", + "eslint-plugin-svelte": "^2.41.0", "eslint-plugin-yml": "^1.14.0", "estree-walker": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.10", - "mocha": "^10.4.0", + "mocha": "^10.6.0", "mocha-chai-jest-snapshot": "^1.1.4", "nyc": "^17.0.0", "prettier": "~3.3.2", "prettier-plugin-pkg": "^0.18.1", - "prettier-plugin-svelte": "^3.2.4", - "rimraf": "^5.0.7", + "prettier-plugin-svelte": "^3.2.5", + "rimraf": "^5.0.9", "semver": "^7.6.2", - "svelte": "^5.0.0-next.158", - "svelte2tsx": "^0.7.10", - "typescript": "~5.5.0", + "svelte": "^5.0.0-next.181", + "svelte2tsx": "^0.7.13", + "typescript": "~5.5.3", "typescript-eslint-parser-for-extra-files": "^0.7.0" }, "publishConfig": { diff --git a/src/context/index.ts b/src/context/index.ts index e91a34d6..9dc8de3c 100644 --- a/src/context/index.ts +++ b/src/context/index.ts @@ -12,7 +12,7 @@ import type { } from "../ast"; import type ESTree from "estree"; import type * as SvAST from "../parser/svelte-ast-types"; -import type * as Compiler from "svelte/compiler"; +import type * as Compiler from "../parser/svelte-ast-types-for-v5"; import { ScriptLetContext } from "./script-let"; import { LetDirectiveCollections } from "./let-directive-collection"; import { parseAttributes } from "../parser/html"; @@ -169,19 +169,7 @@ export class Context { | SvAST.SlotTemplate | SvAST.Slot | SvAST.Title - | Compiler.RegularElement - | Compiler.Component - | Compiler.SvelteComponent - | Compiler.SvelteElement - | Compiler.SvelteWindow - | Compiler.SvelteBody - | Compiler.SvelteHead - | Compiler.SvelteDocument - | Compiler.SvelteFragment - | Compiler.SvelteSelf - | Compiler.SvelteOptionsRaw - | Compiler.SlotElement - | Compiler.TitleElement + | Compiler.ElementLike >(); public readonly snippets: SvelteSnippetBlock[] = []; diff --git a/src/parser/compat.ts b/src/parser/compat.ts index 9b00ff1f..13f24b1b 100644 --- a/src/parser/compat.ts +++ b/src/parser/compat.ts @@ -1,7 +1,7 @@ /** Compatibility for Svelte v4 <-> v5 */ import type ESTree from "estree"; import type * as SvAST from "./svelte-ast-types"; -import type * as Compiler from "svelte/compiler"; +import type * as Compiler from "./svelte-ast-types-for-v5"; export type Child = | Compiler.Text diff --git a/src/parser/converts/attr.ts b/src/parser/converts/attr.ts index cb03c7d0..d30e5b2b 100644 --- a/src/parser/converts/attr.ts +++ b/src/parser/converts/attr.ts @@ -24,7 +24,7 @@ import type { import type ESTree from "estree"; import type { Context } from "../../context"; import type * as SvAST from "../svelte-ast-types"; -import type * as Compiler from "svelte/compiler"; +import type * as Compiler from "../svelte-ast-types-for-v5"; import { getWithLoc, indexOf } from "./common"; import { convertMustacheTag } from "./mustache"; import { convertTextToLiteral } from "./text"; diff --git a/src/parser/converts/block.ts b/src/parser/converts/block.ts index 445ba8f1..b1ab2931 100644 --- a/src/parser/converts/block.ts +++ b/src/parser/converts/block.ts @@ -1,5 +1,5 @@ import type * as SvAST from "../svelte-ast-types"; -import type * as Compiler from "svelte/compiler"; +import type * as Compiler from "../svelte-ast-types-for-v5"; import type { SvelteAwaitBlock, SvelteAwaitBlockAwaitCatch, @@ -114,20 +114,21 @@ export function convertIfBlock( node: SvAST.IfBlock | Compiler.IfBlock, parent: SvelteIfBlock["parent"], ctx: Context, - elseif: true, + elseifContext?: { start: number }, ): SvelteIfBlockElseIf; /** Convert for IfBlock */ export function convertIfBlock( node: SvAST.IfBlock | Compiler.IfBlock, parent: SvelteIfBlock["parent"], ctx: Context, - elseif?: true, + elseifContext?: { start: number }, ): SvelteIfBlock { // {#if expr} {:else} {/if} // {:else if expr} {/if} + const elseif = Boolean(elseifContext); const nodeStart = startBlockIndex( ctx.code, - elseif ? node.start - 1 : node.start, + elseifContext?.start ?? node.start, elseif ? ":else" : "#if", ); const ifBlock: SvelteIfBlock = { @@ -188,7 +189,9 @@ export function convertIfBlock( }; ifBlock.else = elseBlock; - const elseIfBlock = convertIfBlock(c, elseBlock, ctx, true); + const elseIfBlock = convertIfBlock(c, elseBlock, ctx, { + start: elseStart, + }); // adjust loc elseBlock.range[1] = elseIfBlock.range[1]; elseBlock.loc.end = { @@ -238,22 +241,21 @@ function startBlockIndexForElse( lastExpression: ESTree.Node | { start: number; end: number }, ctx: Context, ) { - let baseStart: number; const elseChildren = getChildren(elseFragment); if (elseChildren.length > 0) { const c = elseChildren[0]; - baseStart = c.start; if (c.type === "IfBlock" && c.elseif) { - baseStart = Math.min(baseStart, getWithLoc(getTestFromIfBlock(c)).start); + const contentStart = getWithLoc(getTestFromIfBlock(c)).start; + if (contentStart <= c.start) { + return startBlockIndex(ctx.code, contentStart - 1, ":else"); + } } - } else { - const beforeEnd = endIndexFromFragment(beforeFragment, () => { - return ctx.code.indexOf("}", getWithLoc(lastExpression).end) + 1; - }); - baseStart = beforeEnd + 1; + return startBlockIndex(ctx.code, c.start, ":else"); } - - return startBlockIndex(ctx.code, baseStart - 1, ":else"); + const beforeEnd = endIndexFromFragment(beforeFragment, () => { + return ctx.code.indexOf("}", getWithLoc(lastExpression).end) + 1; + }); + return startBlockIndex(ctx.code, beforeEnd, ":else"); } /** Convert for EachBlock */ @@ -706,7 +708,7 @@ function extractMustacheBlockTokens( | SvelteKeyBlock | SvelteSnippetBlock, ctx: Context, - option?: { startOnly?: true }, + option?: { startOnly?: boolean }, ) { const startSectionNameStart = indexOf( ctx.code, diff --git a/src/parser/converts/const.ts b/src/parser/converts/const.ts index 3f9684c5..c236ae1c 100644 --- a/src/parser/converts/const.ts +++ b/src/parser/converts/const.ts @@ -2,7 +2,7 @@ import type { SvelteConstTag } from "../../ast"; import type { Context } from "../../context"; import { getDeclaratorFromConstTag } from "../compat"; import type * as SvAST from "../svelte-ast-types"; -import type * as Compiler from "svelte/compiler"; +import type * as Compiler from "../svelte-ast-types-for-v5"; /** Convert for ConstTag */ export function convertConstTag( diff --git a/src/parser/converts/element.ts b/src/parser/converts/element.ts index c89170ea..ef838c48 100644 --- a/src/parser/converts/element.ts +++ b/src/parser/converts/element.ts @@ -30,7 +30,7 @@ import type { import type ESTree from "estree"; import type { Context } from "../../context"; import type * as SvAST from "../svelte-ast-types"; -import type * as Compiler from "svelte/compiler"; +import type * as Compiler from "../svelte-ast-types-for-v5"; import { convertAwaitBlock, diff --git a/src/parser/converts/mustache.ts b/src/parser/converts/mustache.ts index 6057e7b9..60d74f94 100644 --- a/src/parser/converts/mustache.ts +++ b/src/parser/converts/mustache.ts @@ -7,7 +7,7 @@ import type { import type { Context } from "../../context"; import type * as SvAST from "../svelte-ast-types"; import { hasTypeInfo } from "../../utils"; -import type * as Compiler from "svelte/compiler"; +import type * as Compiler from "../svelte-ast-types-for-v5"; /** Convert for MustacheTag */ export function convertMustacheTag( diff --git a/src/parser/converts/render.ts b/src/parser/converts/render.ts index d64c1b90..ebe92805 100644 --- a/src/parser/converts/render.ts +++ b/src/parser/converts/render.ts @@ -2,7 +2,7 @@ import type * as ESTree from "estree"; import type { SvelteRenderTag } from "../../ast"; import type { Context } from "../../context"; import { getWithLoc } from "./common"; -import type * as Compiler from "svelte/compiler"; +import type * as Compiler from "../svelte-ast-types-for-v5"; /** Convert for RenderTag */ export function convertRenderTag( diff --git a/src/parser/converts/root.ts b/src/parser/converts/root.ts index ee5ffe12..aa713bd8 100644 --- a/src/parser/converts/root.ts +++ b/src/parser/converts/root.ts @@ -1,5 +1,5 @@ import type * as SvAST from "../svelte-ast-types"; -import type * as Compiler from "svelte/compiler"; +import type * as Compiler from "../svelte-ast-types-for-v5"; import type { SvelteAttribute, SvelteGenericsDirective, diff --git a/src/parser/html.ts b/src/parser/html.ts index 34851f24..72ff4030 100644 --- a/src/parser/html.ts +++ b/src/parser/html.ts @@ -1,4 +1,4 @@ -import type * as Compiler from "svelte/compiler"; +import type * as Compiler from "./svelte-ast-types-for-v5"; import type ESTree from "estree"; import { getEspree } from "./espree"; diff --git a/src/parser/index.ts b/src/parser/index.ts index 981f2f4f..01e4d96c 100644 --- a/src/parser/index.ts +++ b/src/parser/index.ts @@ -12,7 +12,7 @@ import type { ScopeManager } from "eslint-scope"; import { Variable } from "eslint-scope"; import { parseScript, parseScriptInSvelte } from "./script"; import type * as SvAST from "./svelte-ast-types"; -import type * as Compiler from "svelte/compiler"; +import type * as Compiler from "./svelte-ast-types-for-v5"; import { sortNodes } from "./sort"; import { parseTemplate } from "./template"; import { diff --git a/src/parser/svelte-ast-types-for-v5.ts b/src/parser/svelte-ast-types-for-v5.ts new file mode 100644 index 00000000..9dea265b --- /dev/null +++ b/src/parser/svelte-ast-types-for-v5.ts @@ -0,0 +1,116 @@ +// FIXME Since the node type is not provided by "svelte/compiler", +// we work around this by extracting the type from the parse function. +// See also https://github.com/sveltejs/svelte/issues/12292 + +import type { parse } from "svelte/compiler"; + +export type Root = ModernParseReturnType; +export type Fragment = Root["fragment"]; +export type SvelteOptions = Root["options"]; +export type Script = Root["instance"]; +type FragmentChild = Fragment["nodes"][number]; + +export type Text = Extract; + +export type ExpressionTag = Extract; +export type HtmlTag = Extract; +export type ConstTag = Extract; +export type DebugTag = Extract; +export type RenderTag = Extract; + +export type Component = Extract; +export type TitleElement = Extract; +export type SlotElement = Extract; +export type RegularElement = Extract; +export type SvelteBody = Extract; +export type SvelteComponent = Extract< + FragmentChild, + { type: "SvelteComponent" } +>; +export type SvelteDocument = Extract; +export type SvelteElement = Extract; +export type SvelteFragment = Extract; +export type SvelteHead = Extract; +export type SvelteOptionsRaw = Extract< + FragmentChild, + { type: "SvelteOptions" } +>; +export type SvelteSelf = Extract; +export type SvelteWindow = Extract; + +export type IfBlock = Extract; +export type EachBlock = Extract; +export type AwaitBlock = Extract; +export type KeyBlock = Extract; +export type SnippetBlock = Extract; + +export type Comment = Extract; +type ComponentAttribute = Component["attributes"][number]; +export type Attribute = Extract; +export type SpreadAttribute = Extract< + ComponentAttribute, + { type: "SpreadAttribute" } +>; +export type AnimateDirective = Extract< + ComponentAttribute, + { type: "AnimateDirective" } +>; +export type BindDirective = Extract< + ComponentAttribute, + { type: "BindDirective" } +>; +export type ClassDirective = Extract< + ComponentAttribute, + { type: "ClassDirective" } +>; +export type LetDirective = Extract< + ComponentAttribute, + { type: "LetDirective" } +>; +export type OnDirective = Extract; +export type StyleDirective = Extract< + ComponentAttribute, + { type: "StyleDirective" } +>; +export type TransitionDirective = Extract< + ComponentAttribute, + { type: "TransitionDirective" } +>; +export type UseDirective = Extract< + ComponentAttribute, + { type: "UseDirective" } +>; + +export type Tag = ExpressionTag | HtmlTag | ConstTag | DebugTag | RenderTag; +export type ElementLike = + | Component + | TitleElement + | SlotElement + | RegularElement + | SvelteBody + | SvelteComponent + | SvelteDocument + | SvelteElement + | SvelteFragment + | SvelteHead + | SvelteOptionsRaw + | SvelteSelf + | SvelteWindow; +export type Block = EachBlock | IfBlock | AwaitBlock | KeyBlock | SnippetBlock; + +export type Directive = + | AnimateDirective + | BindDirective + | ClassDirective + | LetDirective + | OnDirective + | StyleDirective + | TransitionDirective + | UseDirective; + +type ModernParseReturnType = T extends { + (source: string, options: { filename?: string; modern: true }): infer R; + (...args: any[]): any; +} + ? R + : any; diff --git a/src/parser/svelte-parse-context.ts b/src/parser/svelte-parse-context.ts index 71c8c353..18662040 100644 --- a/src/parser/svelte-parse-context.ts +++ b/src/parser/svelte-parse-context.ts @@ -1,4 +1,4 @@ -import type * as Compiler from "svelte/compiler"; +import type * as Compiler from "./svelte-ast-types-for-v5"; import type * as SvAST from "./svelte-ast-types"; import type { NormalizedParserOptions } from "./parser-options"; import { compilerVersion, svelteVersion } from "./svelte-version"; diff --git a/src/parser/template.ts b/src/parser/template.ts index 4cc891cb..55133547 100644 --- a/src/parser/template.ts +++ b/src/parser/template.ts @@ -1,6 +1,6 @@ import type {} from "svelte"; // FIXME: Workaround to get type information for "svelte/compiler" import { parse } from "svelte/compiler"; -import type * as Compiler from "svelte/compiler"; +import type * as Compiler from "./svelte-ast-types-for-v5"; import type * as SvAST from "./svelte-ast-types"; import type { Context } from "../context"; import { convertSvelteRoot } from "./converts/index"; diff --git a/tests/fixtures/parser/ast/svelte5/docs/snippets/10-typing-snippets-type-output.svelte b/tests/fixtures/parser/ast/svelte5/docs/snippets/10-typing-snippets-type-output.svelte index 2349866e..d992f19b 100644 --- a/tests/fixtures/parser/ast/svelte5/docs/snippets/10-typing-snippets-type-output.svelte +++ b/tests/fixtures/parser/ast/svelte5/docs/snippets/10-typing-snippets-type-output.svelte @@ -1,15 +1,15 @@ - {#if children} + {#if children} {@render children()} diff --git a/tests/fixtures/parser/ast/svelte5/docs/snippets/11-typing-snippets-type-output.svelte b/tests/fixtures/parser/ast/svelte5/docs/snippets/11-typing-snippets-type-output.svelte index 870bfb79..4c5b05d6 100644 --- a/tests/fixtures/parser/ast/svelte5/docs/snippets/11-typing-snippets-type-output.svelte +++ b/tests/fixtures/parser/ast/svelte5/docs/snippets/11-typing-snippets-type-output.svelte @@ -1,15 +1,15 @@
- {#if children} + {#if children} {@render children()} diff --git a/tests/fixtures/parser/ast/svelte5/generics01-snippets-type-output.svelte b/tests/fixtures/parser/ast/svelte5/generics01-snippets-type-output.svelte index d3648ad2..3490d02c 100644 --- a/tests/fixtures/parser/ast/svelte5/generics01-snippets-type-output.svelte +++ b/tests/fixtures/parser/ast/svelte5/generics01-snippets-type-output.svelte @@ -1,16 +1,16 @@
- {#if children} + {#if children} {@render children()}