Skip to content

Commit

Permalink
fix: deduplicate generate props/events/slot types correctly (#2269)
Browse files Browse the repository at this point in the history
Deduplication that took place when generating in dts mode was flawed
  • Loading branch information
dummdidumm authored Jan 24, 2024
1 parent 7d4f8a7 commit 38f448d
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 25 deletions.
74 changes: 52 additions & 22 deletions packages/svelte2tsx/src/svelte2tsx/addComponentExport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,18 @@ class __sveltets_Render${genericsDef} {
const svelteComponentClass = noSvelteComponentTyped
? 'SvelteComponent'
: 'SvelteComponentTyped';
const [PropsName] = addTypeExport(str, className, 'Props');
const [EventsName] = addTypeExport(str, className, 'Events');
const [SlotsName] = addTypeExport(str, className, 'Slots');

if (mode === 'dts') {
statement +=
`export type ${className}Props${genericsDef} = ${returnType('props')};\n` +
`export type ${className}Events${genericsDef} = ${returnType('events')};\n` +
`export type ${className}Slots${genericsDef} = ${returnType('slots')};\n` +
`export type ${PropsName}${genericsDef} = ${returnType('props')};\n` +
`export type ${EventsName}${genericsDef} = ${returnType('events')};\n` +
`export type ${SlotsName}${genericsDef} = ${returnType('slots')};\n` +
`\n${doc}export default class${
className ? ` ${className}` : ''
}${genericsDef} extends ${svelteComponentClass}<${className}Props${genericsRef}, ${className}Events${genericsRef}, ${className}Slots${genericsRef}> {` +
}${genericsDef} extends ${svelteComponentClass}<${PropsName}${genericsRef}, ${EventsName}${genericsRef}, ${SlotsName}${genericsRef}> {` +
exportedNames.createClassGetters() +
(usesAccessors ? exportedNames.createClassAccessors() : '') +
'\n}';
Expand Down Expand Up @@ -128,32 +131,21 @@ function addSimpleComponentExport({

let statement: string;
if (mode === 'dts' && isTsFile) {
const addTypeExport = (type: string) => {
const exportName = className + type;

if (!str.original.includes(exportName)) {
return `export type ${exportName} = typeof __propDef.${type.toLowerCase()};\n`;
}

let replacement = exportName + '_';
while (str.original.includes(replacement)) {
replacement += '_';
}
return `type ${replacement} = typeof __propDef.${type.toLowerCase()};\nexport { ${replacement} as ${exportName} };\n`;
};

const svelteComponentClass = noSvelteComponentTyped
? 'SvelteComponent'
: 'SvelteComponentTyped';
const [PropsName, PropsExport] = addTypeExport(str, className, 'Props');
const [EventsName, EventsExport] = addTypeExport(str, className, 'Events');
const [SlotsName, SlotsExport] = addTypeExport(str, className, 'Slots');

statement =
`\nconst __propDef = ${propDef};\n` +
addTypeExport('Props') +
addTypeExport('Events') +
addTypeExport('Slots') +
PropsExport +
EventsExport +
SlotsExport +
`\n${doc}export default class${
className ? ` ${className}` : ''
} extends ${svelteComponentClass}<${className}Props, ${className}Events, ${className}Slots> {` +
} extends ${svelteComponentClass}<${PropsName}, ${EventsName}, ${SlotsName}> {` +
exportedNames.createClassGetters() +
(usesAccessors ? exportedNames.createClassAccessors() : '') +
'\n}';
Expand Down Expand Up @@ -182,6 +174,44 @@ function addSimpleComponentExport({
str.append(statement);
}

function addTypeExport(
str: MagicString,
className: string,
type: string
): [name: string, exportstring: string] {
const exportName = className + type;

if (!new RegExp(`\\W${exportName}\\W`).test(str.original)) {
return [
exportName,
`export type ${exportName} = typeof __propDef.${type.toLowerCase()};\n`
];
}

let replacement = exportName + '_';
while (str.original.includes(replacement)) {
replacement += '_';
}

if (
// Check if there's already an export with the same name
!new RegExp(
`export ((const|let|var|class|interface|type) ${exportName}\\W|{[^}]*?${exportName}(}|\\W.*?}))`
).test(str.original)
) {
return [
replacement,
`type ${replacement} = typeof __propDef.${type.toLowerCase()};\nexport { ${replacement} as ${exportName} };\n`
];
} else {
return [
replacement,
// we assume that the author explicitly named the type the same and don't export the generated type (which has an unstable name)
`type ${replacement} = typeof __propDef.${type.toLowerCase()};\n`
];
}
}

function events(strictEvents: boolean, renderStr: string) {
return strictEvents ? renderStr : `__sveltets_2_with_any_event(${renderStr})`;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { SvelteComponentTyped } from "svelte";
export interface TestEvents {
foo: 'bar';
}
import { type TestProps } from './foo';
declare const __propDef: {
props: {
Expand All @@ -16,7 +19,8 @@ declare const __propDef: {
};
type TestProps_ = typeof __propDef.props;
export { TestProps_ as TestProps };
export type TestEvents = typeof __propDef.events;
export type TestSlots = typeof __propDef.slots;
export default class Test extends SvelteComponentTyped<TestProps, TestEvents, TestSlots> {
type TestEvents_ = typeof __propDef.events;
type TestSlots_ = typeof __propDef.slots;
export { TestSlots_ as TestSlots };
export default class Test extends SvelteComponentTyped<TestProps_, TestEvents_, TestSlots_> {
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
<script context="module" lang="ts">
export interface TestEvents {
foo: 'bar';
}
interface TestSlots {
foo: 'bar';
}
</script>

<script lang="ts">
import { eventProps, type TestProps } from './foo';
Expand Down

0 comments on commit 38f448d

Please sign in to comment.