Skip to content

Commit 00212c4

Browse files
authored
fix: always set bindings/exports in Svelte 5 (#2423)
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)
1 parent 573d59c commit 00212c4

File tree

52 files changed

+76
-65
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+76
-65
lines changed

packages/svelte2tsx/src/svelte2tsx/nodes/ExportedNames.ts

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -709,26 +709,33 @@ export class ExportedNames {
709709
const others = names.filter(([, { isLet }]) => !isLet);
710710
const needsAccessors = this.usesAccessors && names.length > 0 && !this.usesRunes(); // runes mode doesn't support accessors
711711

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

715-
if (others.length > 0 || needsAccessors) {
716-
if (this.isTsFile) {
717-
str +=
718-
', exports: {} as any as { ' +
719-
this.createReturnElementsType(
720-
needsAccessors ? names : others,
721-
undefined,
722-
true
723-
).join(',') +
724-
' }';
715+
if (others.length > 0 || this.usesRunes() || needsAccessors) {
716+
if (others.length > 0 || needsAccessors) {
717+
if (this.isTsFile) {
718+
str +=
719+
', exports: {} as any as { ' +
720+
this.createReturnElementsType(
721+
needsAccessors ? names : others,
722+
undefined,
723+
true
724+
).join(',') +
725+
' }';
726+
} else {
727+
str += `, exports: /** @type {{${this.createReturnElementsType(needsAccessors ? names : others, false, true)}}} */ ({})`;
728+
}
725729
} else {
726-
str += `, exports: /** @type {{${this.createReturnElementsType(needsAccessors ? names : others, false, true)}}} */ ({})`;
730+
// Always add that, in TS5.5+ the type for Exports is infered to never when this is not present, which breaks types.
731+
// Don't cast to `Record<string, never>` because that will break the union type we use elsewhere
732+
str += ', exports: {}';
727733
}
728-
}
729734

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

734741
return str;

packages/svelte2tsx/test/helpers.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,11 @@ export function test_samples(dir: string, transform: TransformSampleFn, js: 'js'
330330
// retry with the last part (the returned default export) stripped because it's always differing between old and new,
331331
// and if that fails then we're going to rethrow the original error
332332
const expectedModified = expected.substring(0, expectDefaultExportPosition);
333-
const actualModified = actual.substring(0, actual.lastIndexOf('\nconst '));
333+
const actualModified = actual
334+
.substring(0, actual.lastIndexOf('\nconst '))
335+
// not added in Svelte 4
336+
.replace(', exports: {}', '')
337+
.replace(', bindings: ""', '');
334338
try {
335339
assert.strictEqual(
336340
actualModified,

packages/svelte2tsx/test/svelte2tsx/samples/accessors-config/expected-svelte5.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
let foo: number = undefined/*Ωignore_startΩ*/;foo = __sveltets_2_any(foo);/*Ωignore_endΩ*/;
55
;
66
async () => {};
7-
return { props: {foo: foo}, exports: /** @type {{foo: number}} */ ({}), slots: {}, events: {} }}
7+
return { props: {foo: foo}, exports: /** @type {{foo: number}} */ ({}), bindings: "", slots: {}, events: {} }}
88
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(['foo'], __sveltets_2_with_any_event(render())));
99
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
1010
/*Ωignore_endΩ*/export default Input__SvelteComponent_;

packages/svelte2tsx/test/svelte2tsx/samples/component-slot-forward-with-props/expected-svelte5.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
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;$$_$$;
55
{ __sveltets_createSlot("default", { foo,});}
66
}Parent}};
7-
return { props: /** @type {Record<string, never>} */ ({}), slots: {'default': {foo:__sveltets_2_instanceOf(Parent).$$slot_def['default'].foo}}, events: {} }}
7+
return { props: /** @type {Record<string, never>} */ ({}), exports: {}, bindings: "", slots: {'default': {foo:__sveltets_2_instanceOf(Parent).$$slot_def['default'].foo}}, events: {} }}
88
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component_slots(__sveltets_2_partial(__sveltets_2_with_any_event(render())));
99
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
1010
/*Ωignore_endΩ*/export default Input__SvelteComponent_;

packages/svelte2tsx/test/svelte2tsx/samples/component-slot-let-forward/expected-svelte5.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
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;$$_$$;
55
{ __sveltets_createSlot("default", { n,thing,bla,});}
66
}Component}};
7-
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: {} }}
7+
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: {} }}
88
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component_slots(__sveltets_2_partial(__sveltets_2_with_any_event(render())));
99
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
1010
/*Ωignore_endΩ*/export default Input__SvelteComponent_;

packages/svelte2tsx/test/svelte2tsx/samples/component-slot-nest-scope/expected-svelte5.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ async () => { for(let item of __sveltets_2_ensureArray(items)){
1212
d;
1313
}}
1414
{ __sveltets_createSlot("third", { d,c,}); }};
15-
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: {} }}
15+
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: {} }}
1616
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component_slots(__sveltets_2_partial(__sveltets_2_with_any_event(render())));
1717
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
1818
/*Ωignore_endΩ*/export default Input__SvelteComponent_;

packages/svelte2tsx/test/svelte2tsx/samples/component-slot-no-space/expected-svelte5.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ function render() {
88
async () => {
99

1010
{ 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} }};
11-
return { props: /** @type {Record<string, never>} */ ({}), slots: {}, events: {} }}
11+
return { props: /** @type {Record<string, never>} */ ({}), exports: {}, bindings: "", slots: {}, events: {} }}
1212
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(__sveltets_2_with_any_event(render())));
1313
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
1414
/*Ωignore_endΩ*/export default Input__SvelteComponent_;

packages/svelte2tsx/test/svelte2tsx/samples/component-with-documentation/expected-svelte5.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
async () => {
44

55
{ svelteHTML.createElement("main", {}); }};
6-
return { props: /** @type {Record<string, never>} */ ({}), slots: {}, events: {} }}
6+
return { props: /** @type {Record<string, never>} */ ({}), exports: {}, bindings: "", slots: {}, events: {} }}
77
/** This component does nothing at all */
88
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(__sveltets_2_with_any_event(render())));
99
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;

packages/svelte2tsx/test/svelte2tsx/samples/component-with-indented-multiline-documentation/expected-svelte5.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
async () => {
44

55
{ svelteHTML.createElement("main", {}); }};
6-
return { props: /** @type {Record<string, never>} */ ({}), slots: {}, events: {} }}
6+
return { props: /** @type {Record<string, never>} */ ({}), exports: {}, bindings: "", slots: {}, events: {} }}
77
/**
88
* This component has indented multiline documentation:
99
*

packages/svelte2tsx/test/svelte2tsx/samples/component-with-multiline-documentation/expected-svelte5.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
async () => {
44

55
{ svelteHTML.createElement("main", {}); }};
6-
return { props: /** @type {Record<string, never>} */ ({}), slots: {}, events: {} }}
6+
return { props: /** @type {Record<string, never>} */ ({}), exports: {}, bindings: "", slots: {}, events: {} }}
77
/**
88
* This component has multiline documentation:
99
*

0 commit comments

Comments
 (0)