Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .changeset/chubby-wasps-marry.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
"svelte-check": patch
"svelte2tsx": patch
'svelte-check': patch
'svelte2tsx': patch
---

fix: properly handle props with the name `slot` inside Svelte 5 snippets
6 changes: 6 additions & 0 deletions .changeset/metal-hotels-film.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'svelte-check': minor
'svelte2tsx': patch
---

feat: support Svelte 5 declaration tags
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
[
{
"range": {
"start": { "line": 11, "character": 9 },
"end": { "line": 11, "character": 14 }
},
"severity": 1,
"source": "ts",
"message": "Type 'string' is not assignable to type 'number'.",
"code": 2322,
"tags": []
},
{
"range": {
"start": { "line": 12, "character": 11 },
"end": { "line": 12, "character": 18 }
},
"severity": 1,
"source": "ts",
"message": "Type 'number' is not assignable to type 'string'.",
"code": 2322,
"tags": []
},
{
"range": {
"start": { "line": 14, "character": 8 },
"end": { "line": 14, "character": 21 }
},
"severity": 1,
"source": "ts",
"message": "This comparison appears to be unintentional because the types 'string' and 'number' have no overlap.",
"code": 2367,
"tags": []
},
{
"range": {
"start": { "line": 14, "character": 24 },
"end": { "line": 14, "character": 41 }
},
"severity": 1,
"source": "ts",
"message": "This comparison appears to be unintentional because the types 'number' and 'string' have no overlap.",
"code": 2367,
"tags": []
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script lang="ts">
type Box = { width: number; height: number };

let boxes: Box[] = [
{ width: 3, height: 4 },
{ width: 5, height: 7 }
];
</script>

{#each boxes as box}
{const area = box.width * box.height}
{let label: number = $state(`${area} square pixels`)}
{const doubled: string = area * 2}

<p>{doubled === 1} {label === 'large'}</p>
<div>
{const area = 'nested'}
{area}
</div>
{/each}
13 changes: 12 additions & 1 deletion packages/svelte2tsx/src/htmlxtojsx_v2/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ import MagicString from 'magic-string';
import { walk } from 'estree-walker';
// @ts-ignore
import { TemplateNode, Text } from 'svelte/types/compiler/interfaces';
import { Attribute, BaseNode, BaseDirective, StyleDirective, ConstTag } from '../interfaces';
import {
Attribute,
BaseNode,
BaseDirective,
StyleDirective,
ConstTag,
DeclarationTag
} from '../interfaces';
import { parseHtmlx } from '../utils/htmlxparser';
import { handleActionDirective } from './nodes/Action';
import { handleAnimateDirective } from './nodes/Animation';
Expand All @@ -16,6 +23,7 @@ import {
handleTrailingEndComment
} from './nodes/Comment';
import { handleConstTag } from './nodes/ConstTag';
import { handleDeclarationTag } from './nodes/DeclarationTag';
import { handleDebug } from './nodes/DebugTag';
import { handleEach } from './nodes/EachBlock';
import { Element } from './nodes/Element';
Expand Down Expand Up @@ -371,6 +379,9 @@ export function convertHtmlxToJsx(
case 'ConstTag':
handleConstTag(str, node as ConstTag);
break;
case 'DeclarationTag':
handleDeclarationTag(str, node as DeclarationTag);
break;
case 'RenderTag':
handleRenderTag(str, node);
break;
Expand Down
10 changes: 10 additions & 0 deletions packages/svelte2tsx/src/htmlxtojsx_v2/nodes/DeclarationTag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import MagicString from 'magic-string';
import { DeclarationTag } from '../../interfaces';

/**
* `{let x = y}` --> `let x = y;`
*/
export function handleDeclarationTag(str: MagicString, declarationTag: DeclarationTag): void {
str.remove(declarationTag.start, declarationTag.declaration.start);
str.overwrite(declarationTag.declaration.end, declarationTag.end, ';');
}
7 changes: 6 additions & 1 deletion packages/svelte2tsx/src/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ArrayPattern, Identifier, ObjectPattern, Node } from 'estree';
import { ArrayPattern, Identifier, ObjectPattern, Node, VariableDeclaration } from 'estree';
// @ts-ignore
import { DirectiveType, TemplateNode } from 'svelte/types/compiler/interfaces';

Expand All @@ -23,6 +23,11 @@ export interface ConstTag extends NodeRange {
expression: any;
}

export interface DeclarationTag extends NodeRange {
type: 'DeclarationTag';
declaration: VariableDeclaration & NodeRange & { kind: 'let' | 'const' };
}

// Copied from the Svelte type definitions
export interface BaseNode {
start: number;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
///<reference types="svelte" />
;function $$render() {

type Box = { width: number; height: number };

let boxes: Box[] = [
{ width: 3, height: 4 },
{ width: 5, height: 7 }
];
;
async () => {

for(let box of __sveltets_2_ensureArray(boxes)){
const foo/*Ωignore_positionΩ*/ = ()/*Ωignore_startΩ*/: ReturnType<import('svelte').Snippet>/*Ωignore_endΩ*/ => { async ()/*Ωignore_positionΩ*/ => {
const area = await 'snippet';
area;
};return __sveltets_2_any(0)};const area = box.width * box.height;
let label = $state(await `${area} square pixels`);

{ svelteHTML.createElement("p", {});label; }
{ svelteHTML.createElement("div", {});
const area = await 'nested';
area;
}


}};
return { props: /** @type {Record<string, never>} */ ({}), exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_fn_component($$render());
/*Ωignore_startΩ*/type Input__SvelteComponent_ = ReturnType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script lang="ts">
type Box = { width: number; height: number };

let boxes: Box[] = [
{ width: 3, height: 4 },
{ width: 5, height: 7 }
];
</script>

{#each boxes as box}
{const area = box.width * box.height}
{let label = $state(await `${area} square pixels`)}

<p>{label}</p>
<div>
{const area = await 'nested'}
{area}
</div>

{#snippet foo()}
{const area = await 'snippet'}
{area}
{/snippet}
{/each}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
///<reference types="svelte" />
;function $$render() {

type Box = { width: number; height: number };

let boxes: Box[] = [
{ width: 3, height: 4 },
{ width: 5, height: 7 }
];
;
async () => {

for(let box of __sveltets_2_ensureArray(boxes)){
const area = box.width * box.height;
let label = $state(`${area} square pixels`);
const doubled = area * 2;

{ svelteHTML.createElement("p", {});doubled; label; }
{ svelteHTML.createElement("div", {});
const area = 'nested';
area;
}
}};
return { props: {} as Record<string, never>, exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_fn_component($$render());
/*Ωignore_startΩ*/type Input__SvelteComponent_ = ReturnType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script lang="ts">
type Box = { width: number; height: number };

let boxes: Box[] = [
{ width: 3, height: 4 },
{ width: 5, height: 7 }
];
</script>

{#each boxes as box}
{const area = box.width * box.height}
{let label = $state(`${area} square pixels`)}
{const doubled = area * 2}

<p>{doubled} {label}</p>
<div>
{const area = 'nested'}
{area}
</div>
{/each}
Loading