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
43 changes: 33 additions & 10 deletions packages/svelte2tsx/src/svelte2tsx/nodes/ExportedNames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ interface ExportedName {
export class ExportedNames {
private uses$$Props = false;
private exports = new Map<string, ExportedName>();
private possibleExports = new Map<string, ExportedName>();
private possibleExports = new Map<
string,
ExportedName & {
declaration: ts.VariableDeclarationList;
}
>();
private doneDeclarationTransformation = new Set<ts.VariableDeclarationList>();
private getters = new Set<string>();

constructor(private str: MagicString, private astOffset: number) {}
Expand All @@ -30,9 +36,8 @@ export class ExportedNames {
const isLet = node.declarationList.flags === ts.NodeFlags.Let;
const isConst = node.declarationList.flags === ts.NodeFlags.Const;

this.handleExportedVariableDeclarationList(
node.declarationList,
this.addExport.bind(this)
this.handleExportedVariableDeclarationList(node.declarationList, (_, ...args) =>
this.addExport(...args)
);
if (isLet) {
this.propTypeAssertToUserDefined(node.declarationList);
Expand Down Expand Up @@ -88,7 +93,16 @@ export class ExportedNames {
this.str.remove(exportStart, exportEnd);
}

/**
* Appends `prop = __sveltets_any(prop)` to given declaration in order to
* trick TS into widening the type. Else for example `let foo: string | undefined = undefined`
* is narrowed to `undefined` by TS.
*/
private propTypeAssertToUserDefined(node: ts.VariableDeclarationList) {
if (this.doneDeclarationTransformation.has(node)) {
return;
}

const hasInitializers = node.declarations.filter((declaration) => declaration.initializer);
const handleTypeAssertion = (declaration: ts.VariableDeclaration) => {
const identifier = declaration.name;
Expand Down Expand Up @@ -133,32 +147,33 @@ export class ExportedNames {
for (const declaration of hasInitializers) {
handleTypeAssertion(declaration);
}
this.doneDeclarationTransformation.add(node);
}

private handleExportedVariableDeclarationList(
list: ts.VariableDeclarationList,
add: ExportedNames['addExport']
add: ExportedNames['addPossibleExport']
) {
const isLet = list.flags === ts.NodeFlags.Let;
ts.forEachChild(list, (node) => {
if (ts.isVariableDeclaration(node)) {
if (ts.isIdentifier(node.name)) {
add(node.name, isLet, node.name, node.type, !node.initializer);
add(list, node.name, isLet, node.name, node.type, !node.initializer);
} else if (
ts.isObjectBindingPattern(node.name) ||
ts.isArrayBindingPattern(node.name)
) {
ts.forEachChild(node.name, (element) => {
if (ts.isBindingElement(element)) {
add(element.name, isLet);
add(list, element.name, isLet);
}
});
}
}
});
}

addGetter(node: ts.Identifier): void {
private addGetter(node: ts.Identifier): void {
if (!node) {
return;
}
Expand Down Expand Up @@ -203,7 +218,8 @@ export class ExportedNames {
* Marks a top level declaration as a possible export
* which could be exported through `export { .. }` later.
*/
addPossibleExport(
private addPossibleExport(
declaration: ts.VariableDeclarationList,
name: ts.BindingName,
isLet: boolean,
target: ts.BindingName = null,
Expand All @@ -216,6 +232,7 @@ export class ExportedNames {

if (target && ts.isIdentifier(target)) {
this.possibleExports.set(name.text, {
declaration,
isLet,
type: type?.getText(),
identifierText: (target as ts.Identifier).text,
Expand All @@ -224,6 +241,7 @@ export class ExportedNames {
});
} else {
this.possibleExports.set(name.text, {
declaration,
isLet
});
}
Expand All @@ -232,7 +250,7 @@ export class ExportedNames {
/**
* Adds export to map
*/
addExport(
private addExport(
name: ts.BindingName,
isLet: boolean,
target: ts.BindingName = null,
Expand All @@ -247,6 +265,7 @@ export class ExportedNames {
}

const existingDeclaration = this.possibleExports.get(name.text);

if (target) {
this.exports.set(name.text, {
isLet: isLet || existingDeclaration?.isLet,
Expand All @@ -263,6 +282,10 @@ export class ExportedNames {
doc: existingDeclaration?.doc
});
}

if (existingDeclaration?.isLet) {
this.propTypeAssertToUserDefined(existingDeclaration.declaration);
}
}

private getDoc(target: ts.BindingName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
let exported1: string;
let exported2: string = '';exported2 = __sveltets_any(exported2);;

let name1: string = "world"
let name1: string = "world";name1 = __sveltets_any(name1);
let name2: string;

let rename1: string = '';
let rename1: string = '';rename1 = __sveltets_any(rename1);;
let rename2: string;

class Foo {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
let exported1: string;
let exported2: string = '';exported2 = __sveltets_any(exported2);;

let name1: string = "world"
let name1: string = "world";name1 = __sveltets_any(name1);
let name2: string;

let rename1: string = '';
let rename1: string = '';rename1 = __sveltets_any(rename1);;
let rename2: string;

class Foo {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
///<reference types="svelte" />
<></>;function render() {

let name1: string = "world"
let name1: string = "world";name1 = __sveltets_any(name1);
let name2: string;
let name3: string = '';name3 = __sveltets_any(name3);;let name4: string;

let rename1: string = '';
let rename1: string = '';rename1 = __sveltets_any(rename1);;
let rename2: string;

class Foo {}
Expand All @@ -18,7 +19,7 @@

;
() => (<></>);
return { props: {name1: name1 , name2: name2 , renamed1: rename1 , renamed2: rename2 , Foo: Foo , bar: bar , baz: baz , RenamedFoo: RenameFoo , renamedbar: renamebar , renamedbaz: renamebaz} as {name1?: string, name2: string, renamed1?: string, renamed2: string, Foo?: typeof Foo, bar?: typeof bar, baz?: string, RenamedFoo?: typeof RenameFoo, renamedbar?: typeof renamebar, renamedbaz?: string}, slots: {}, getters: {}, events: {} }}
return { props: {name1: name1 , name2: name2 , name3: name3 , name4: name4 , renamed1: rename1 , renamed2: rename2 , Foo: Foo , bar: bar , baz: baz , RenamedFoo: RenameFoo , renamedbar: renamebar , renamedbaz: renamebaz} as {name1?: string, name2: string, name3?: string, name4: string, renamed1?: string, renamed2: string, Foo?: typeof Foo, bar?: typeof bar, baz?: string, RenamedFoo?: typeof RenameFoo, renamedbar?: typeof renamebar, renamedbaz?: string}, slots: {}, getters: {}, events: {} }}

export default class Input__SvelteComponent_ extends createSvelte2TsxComponent(__sveltets_with_any_event(render())) {
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script>
let name1: string = "world"
let name2: string;
let name3: string = '', name4: string;

let rename1: string = '';
let rename2: string;
Expand All @@ -13,5 +14,5 @@
function renamebar() {}
const renamebaz: string = '';

export { name1, name2, rename1 as renamed1, rename2 as renamed2, Foo, bar, baz, RenameFoo as RenamedFoo, renamebar as renamedbar, renamebaz as renamedbaz };
export { name1, name2, name3, name4, rename1 as renamed1, rename2 as renamed2, Foo, bar, baz, RenameFoo as RenamedFoo, renamebar as renamedbar, renamebaz as renamedbaz };
</script>