Skip to content

Commit

Permalink
fix: always set bindings/exports in Svelte 5 (#2423)
Browse files Browse the repository at this point in the history
Those two methods are needed in Svelte 5, but we don't always set them. That was fine until TS 5.5, which infers generics slightly differently and turns `Exports` and `Bindings` to `never` if they don't show up in the input (before they were not)
  • Loading branch information
dummdidumm authored Jun 26, 2024
1 parent 573d59c commit 00212c4
Show file tree
Hide file tree
Showing 52 changed files with 76 additions and 65 deletions.
35 changes: 21 additions & 14 deletions packages/svelte2tsx/src/svelte2tsx/nodes/ExportedNames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -709,26 +709,33 @@ export class ExportedNames {
const others = names.filter(([, { isLet }]) => !isLet);
const needsAccessors = this.usesAccessors && names.length > 0 && !this.usesRunes(); // runes mode doesn't support accessors

if (this.isSvelte5Plus && (others.length > 0 || this.usesRunes() || needsAccessors)) {
if (this.isSvelte5Plus) {
let str = '';

if (others.length > 0 || needsAccessors) {
if (this.isTsFile) {
str +=
', exports: {} as any as { ' +
this.createReturnElementsType(
needsAccessors ? names : others,
undefined,
true
).join(',') +
' }';
if (others.length > 0 || this.usesRunes() || needsAccessors) {
if (others.length > 0 || needsAccessors) {
if (this.isTsFile) {
str +=
', exports: {} as any as { ' +
this.createReturnElementsType(
needsAccessors ? names : others,
undefined,
true
).join(',') +
' }';
} else {
str += `, exports: /** @type {{${this.createReturnElementsType(needsAccessors ? names : others, false, true)}}} */ ({})`;
}
} else {
str += `, exports: /** @type {{${this.createReturnElementsType(needsAccessors ? names : others, false, true)}}} */ ({})`;
// Always add that, in TS5.5+ the type for Exports is infered to never when this is not present, which breaks types.
// Don't cast to `Record<string, never>` because that will break the union type we use elsewhere
str += ', exports: {}';
}
}

if (this.usesRunes()) {
str += `, bindings: ${this.createBindingsStr()}`;
} else {
// always add that, in TS5.5+ the type for Exports is infered to never when this is not present, which breaks types
str += `, exports: {}, bindings: ${this.createBindingsStr()}`;
}

return str;
Expand Down
6 changes: 5 additions & 1 deletion packages/svelte2tsx/test/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,11 @@ export function test_samples(dir: string, transform: TransformSampleFn, js: 'js'
// retry with the last part (the returned default export) stripped because it's always differing between old and new,
// and if that fails then we're going to rethrow the original error
const expectedModified = expected.substring(0, expectDefaultExportPosition);
const actualModified = actual.substring(0, actual.lastIndexOf('\nconst '));
const actualModified = actual
.substring(0, actual.lastIndexOf('\nconst '))
// not added in Svelte 4
.replace(', exports: {}', '')
.replace(', bindings: ""', '');
try {
assert.strictEqual(
actualModified,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
let foo: number = undefined/*Ωignore_startΩ*/;foo = __sveltets_2_any(foo);/*Ωignore_endΩ*/;
;
async () => {};
return { props: {foo: foo}, exports: /** @type {{foo: number}} */ ({}), slots: {}, events: {} }}
return { props: {foo: foo}, exports: /** @type {{foo: number}} */ ({}), bindings: "", slots: {}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(['foo'], __sveltets_2_with_any_event(render())));
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
async () => { { const $$_tneraP0C = __sveltets_2_ensureComponent(Parent); const $$_tneraP0 = new $$_tneraP0C({ target: __sveltets_2_any(), props: { children:() => { return __sveltets_2_any(0); },"propA":true,propB,"propC":`val1`,"propD":`val2`,"propE":`a${a}b${b}`,}});{const {/*Ωignore_startΩ*/$$_$$/*Ωignore_endΩ*/,foo,} = $$_tneraP0.$$slot_def.default;$$_$$;
{ __sveltets_createSlot("default", { foo,});}
}Parent}};
return { props: /** @type {Record<string, never>} */ ({}), slots: {'default': {foo:__sveltets_2_instanceOf(Parent).$$slot_def['default'].foo}}, events: {} }}
return { props: /** @type {Record<string, never>} */ ({}), exports: {}, bindings: "", slots: {'default': {foo:__sveltets_2_instanceOf(Parent).$$slot_def['default'].foo}}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component_slots(__sveltets_2_partial(__sveltets_2_with_any_event(render())));
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
async () => { { const $$_tnenopmoC0C = __sveltets_2_ensureComponent(Component); const $$_tnenopmoC0 = new $$_tnenopmoC0C({ target: __sveltets_2_any(), props: { children:() => { return __sveltets_2_any(0); },}});{const {/*Ωignore_startΩ*/$$_$$/*Ωignore_endΩ*/,name:n,thing,whatever:{ bla },} = $$_tnenopmoC0.$$slot_def.default;$$_$$;
{ __sveltets_createSlot("default", { n,thing,bla,});}
}Component}};
return { props: /** @type {Record<string, never>} */ ({}), slots: {'default': {n:__sveltets_2_instanceOf(Component).$$slot_def['default'].name, thing:__sveltets_2_instanceOf(Component).$$slot_def['default'].thing, bla:(({ bla }) => bla)(__sveltets_2_instanceOf(Component).$$slot_def['default'].whatever)}}, events: {} }}
return { props: /** @type {Record<string, never>} */ ({}), exports: {}, bindings: "", slots: {'default': {n:__sveltets_2_instanceOf(Component).$$slot_def['default'].name, thing:__sveltets_2_instanceOf(Component).$$slot_def['default'].thing, bla:(({ bla }) => bla)(__sveltets_2_instanceOf(Component).$$slot_def['default'].whatever)}}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component_slots(__sveltets_2_partial(__sveltets_2_with_any_event(render())));
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ async () => { for(let item of __sveltets_2_ensureArray(items)){
d;
}}
{ __sveltets_createSlot("third", { d,c,}); }};
return { props: /** @type {Record<string, never>} */ ({}), slots: {'default': {a:(({ a }) => a)(__sveltets_2_unwrapArr(__sveltets_2_unwrapArr(items)))}, 'second': {a:a}, 'third': {d:d, c:c}}, events: {} }}
return { props: /** @type {Record<string, never>} */ ({}), exports: {}, bindings: "", slots: {'default': {a:(({ a }) => a)(__sveltets_2_unwrapArr(__sveltets_2_unwrapArr(items)))}, 'second': {a:a}, 'third': {d:d, c:c}}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component_slots(__sveltets_2_partial(__sveltets_2_with_any_event(render())));
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function render() {
async () => {

{ svelteHTML.createElement("div", {}); { const $$_tseT1C = __sveltets_2_ensureComponent(Test); const $$_tseT1 = new $$_tseT1C({ target: __sveltets_2_any(), props: { children:() => { return __sveltets_2_any(0); },}});{const {/*Ωignore_startΩ*/$$_$$/*Ωignore_endΩ*/,t,} = $$_tseT1.$$slot_def.default;$$_$$; }Test} }};
return { props: /** @type {Record<string, never>} */ ({}), slots: {}, events: {} }}
return { props: /** @type {Record<string, never>} */ ({}), exports: {}, bindings: "", slots: {}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(__sveltets_2_with_any_event(render())));
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
async () => {

{ svelteHTML.createElement("main", {}); }};
return { props: /** @type {Record<string, never>} */ ({}), slots: {}, events: {} }}
return { props: /** @type {Record<string, never>} */ ({}), exports: {}, bindings: "", slots: {}, events: {} }}
/** This component does nothing at all */
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(__sveltets_2_with_any_event(render())));
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
async () => {

{ svelteHTML.createElement("main", {}); }};
return { props: /** @type {Record<string, never>} */ ({}), slots: {}, events: {} }}
return { props: /** @type {Record<string, never>} */ ({}), exports: {}, bindings: "", slots: {}, events: {} }}
/**
* This component has indented multiline documentation:
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
async () => {

{ svelteHTML.createElement("main", {}); }};
return { props: /** @type {Record<string, never>} */ ({}), slots: {}, events: {} }}
return { props: /** @type {Record<string, never>} */ ({}), exports: {}, bindings: "", slots: {}, events: {} }}
/**
* This component has multiline documentation:
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ async () => {
const [_width, _height, sum] = [width * constant, height, width * constant + height];
{ svelteHTML.createElement("div", {});area; volume; perimeter; _width; _height; sum; }
}Component}};
return { props: {box: box , constant: constant}, slots: {}, events: {} }}
return { props: {box: box , constant: constant}, exports: {}, bindings: "", slots: {}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(['box','constant'], __sveltets_2_with_any_event(render())));
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ async () => {
{ svelteHTML.createElement("button", { "on:click":undefined,}); }
{ __sveltets_createSlot("default", {bar,}); }};
return { props: {
/** @type {boolean} */bar: bar , foobar: foobar}, slots: {'default': {bar:bar}}, events: {'click':__sveltets_2_mapElementEvent('click'), 'hi': __sveltets_2_customEvent} }}
/** @type {boolean} */bar: bar , foobar: foobar}, exports: {}, bindings: "", slots: {'default': {bar:bar}}, events: {'click':__sveltets_2_mapElementEvent('click'), 'hi': __sveltets_2_customEvent} }}
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & { $$bindings?: Bindings } & Exports;
(internal: unknown, props: Props & {$$events?: Events, $$slots?: Slots}): Exports;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ async () => { { svelteHTML.createElement("button", { "on:click":undefined,}); {
{ const $$_value = await (Promise.resolve(0));{ const n = $$_value;
n;
}}};
return { props: /** @type {Record<string, never>} */ ({}), slots: {'default': {}}, events: {'click':__sveltets_2_mapElementEvent('click')} }}
return { props: /** @type {Record<string, never>} */ ({}), exports: {}, bindings: "", slots: {'default': {}}, events: {'click':__sveltets_2_mapElementEvent('click')} }}
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & { $$bindings?: Bindings } & Exports;
(internal: unknown, props: {$$events?: Events, $$slots?: Slots}): Exports;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
class Foo {};
;
async () => {};
return { props: {Foo: Foo}, exports: /** @type {{Foo: typeof Foo}} */ ({}), slots: {}, events: {} }}
return { props: {Foo: Foo}, exports: /** @type {{Foo: typeof Foo}} */ ({}), bindings: "", slots: {}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(['Foo'], __sveltets_2_with_any_event(render())));
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const array = [1, 2, 3, [4]];
const [a, b, c, [d]] = array;
;
async () => {};
return { props: {a: a , b: b , c: c , d: d}, exports: /** @type {{a: typeof a,b: typeof b,c: typeof c,d: typeof d}} */ ({}), slots: {}, events: {} }}
return { props: {a: a , b: b , c: c , d: d}, exports: /** @type {{a: typeof a,b: typeof b,c: typeof c,d: typeof d}} */ ({}), bindings: "", slots: {}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(['a','b','c','d'], __sveltets_2_with_any_event(render())));
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const obj = {
} = obj;
;
async () => {};
return { props: {a: a , b: b , c: c , g: g}, exports: /** @type {{a: typeof a,b: typeof b,c: typeof c,g: typeof g}} */ ({}), slots: {}, events: {} }}
return { props: {a: a , b: b , c: c , g: g}, exports: /** @type {{a: typeof a,b: typeof b,c: typeof c,g: typeof g}} */ ({}), bindings: "", slots: {}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(['a','b','c','g'], __sveltets_2_with_any_event(render())));
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

;
async () => {};
return { props: {name1: name1 , name2: name2 , renamed1: rename1 , renamed2: rename2 , Foo: Foo , bar: bar , baz: baz , RenamedFoo: RenameFoo , renamedbar: renamebar , renamedbaz: renamebaz}, exports: /** @type {{Foo: typeof Foo,bar: typeof bar,baz: typeof baz,RenamedFoo: typeof RenameFoo,renamedbar: typeof renamebar,renamedbaz: typeof renamebaz}} */ ({}), slots: {}, events: {} }}
return { props: {name1: name1 , name2: name2 , renamed1: rename1 , renamed2: rename2 , Foo: Foo , bar: bar , baz: baz , RenamedFoo: RenameFoo , renamedbar: renamebar , renamedbaz: renamebaz}, exports: /** @type {{Foo: typeof Foo,bar: typeof bar,baz: typeof baz,RenamedFoo: typeof RenameFoo,renamedbar: typeof renamebar,renamedbaz: typeof renamebaz}} */ ({}), bindings: "", slots: {}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(['name1','renamed1','Foo','bar','baz','RenamedFoo','renamedbar','renamedbaz'], __sveltets_2_with_any_event(render())));
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
let items: T/*Ωignore_startΩ*/;items = __sveltets_2_any(items);/*Ωignore_endΩ*/;
;
async () => {};
return { props: {items: items}, slots: {}, events: {} }}
return { props: {items: items}, exports: {}, bindings: "", slots: {}, events: {} }}
class __sveltets_Render<const T extends readonly string[]> {
props() {
return render<T>().props;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
let/** @typedef {{ a: unknown, b?: boolean, c?: number, d?: string, e?: unknown, f?: unknown, g?: typeof foo }} $$ComponentProps *//** @type {$$ComponentProps} */ { a, b = true, c = 1, d = '', e = null, f = {}, g = foo } = $props();
;
async () => {};
return { props: /** @type {$$ComponentProps} */({}), bindings: __sveltets_$$bindings(''), slots: {}, events: {} }}
return { props: /** @type {$$ComponentProps} */({}), exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_with_any_event(render()));
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
let/** @typedef {{ a: unknown, b?: unknown }} $$ComponentProps *//** @type {$$ComponentProps} */ { a, b = $bindable() } = $props();
;
async () => {};
return { props: /** @type {$$ComponentProps} */({}), bindings: __sveltets_$$bindings('b'), slots: {}, events: {} }}
return { props: /** @type {$$ComponentProps} */({}), exports: {}, bindings: __sveltets_$$bindings('b'), slots: {}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_with_any_event(render()));
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
async () => {

state; derived;};
return { props: /** @type {$$ComponentProps} */({}), bindings: __sveltets_$$bindings(''), slots: {}, events: {} }}
return { props: /** @type {$$ComponentProps} */({}), exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_with_any_event(render()));
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
async () => {

{ __sveltets_createSlot("default", { x,y,});}};
return { props: /** @type {SomeType} */({}), bindings: __sveltets_$$bindings(''), slots: {'default': {x:x, y:y}}, events: {} }}
return { props: /** @type {SomeType} */({}), exports: {}, bindings: __sveltets_$$bindings(''), slots: {'default': {x:x, y:y}}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component_slots(__sveltets_2_with_any_event(render()));
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
let y = $derived(x * 2);
;
async () => {};
return { props: /** @type {$$ComponentProps} */({}), bindings: __sveltets_$$bindings(''), slots: {}, events: {} }}
return { props: /** @type {$$ComponentProps} */({}), exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_with_any_event(render()));
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ async () => {
{ svelteHTML.createElement("p", {}); }
Script}
{ const $$_elytS0C = __sveltets_2_ensureComponent(Style); new $$_elytS0C({ target: __sveltets_2_any(), props: {}});}};
return { props: /** @type {Record<string, never>} */ ({}), slots: {}, events: {} }}
return { props: /** @type {Record<string, never>} */ ({}), exports: {}, bindings: "", slots: {}, events: {} }}
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(__sveltets_2_with_any_event(render())));
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Loading

0 comments on commit 00212c4

Please sign in to comment.