diff --git a/packages/svelte2tsx/src/svelte2tsx/nodes/ExportedNames.ts b/packages/svelte2tsx/src/svelte2tsx/nodes/ExportedNames.ts
index d2a11528a..3fd6269ee 100644
--- a/packages/svelte2tsx/src/svelte2tsx/nodes/ExportedNames.ts
+++ b/packages/svelte2tsx/src/svelte2tsx/nodes/ExportedNames.ts
@@ -1,3 +1,5 @@
+import ts from 'typescript';
+
export interface IExportedNames {
has(name: string): boolean;
}
@@ -9,9 +11,55 @@ export class ExportedNames
type?: string;
identifierText?: string;
required?: boolean;
+ doc?: string;
}
>
implements IExportedNames {
+ /**
+ * Adds export to map
+ */
+ addExport(
+ name: ts.BindingName,
+ target: ts.BindingName = null,
+ type: ts.TypeNode = null,
+ required = false,
+ ): void {
+ if (name.kind != ts.SyntaxKind.Identifier) {
+ throw Error('export source kind not supported ' + name);
+ }
+ if (target && target.kind != ts.SyntaxKind.Identifier) {
+ throw Error('export target kind not supported ' + target);
+ }
+
+ if (target) {
+ this.set(name.text, {
+ type: type?.getText(),
+ identifierText: (target as ts.Identifier).text,
+ required,
+ doc: this.getDoc(target),
+ });
+ } else {
+ this.set(name.text, {});
+ }
+ }
+
+ private getDoc(target: ts.BindingName) {
+ let doc = undefined;
+ // Traverse `a` up to `export let a`
+ const exportExpr = target?.parent?.parent?.parent;
+
+ if (exportExpr) {
+ const fileText = exportExpr.getSourceFile().getFullText();
+ const comment = ts.getLeadingCommentRanges(fileText, exportExpr.getFullStart());
+
+ if (comment) {
+ doc = fileText.substring(comment[0].pos, comment[0].end);
+ }
+ }
+
+ return doc;
+ }
+
/**
* Creates a string from the collected props
*
@@ -19,24 +67,28 @@ export class ExportedNames
*/
createPropsStr(isTsFile: boolean) {
const names = Array.from(this.entries());
+ const dontAddTypeDef =
+ !isTsFile ||
+ names.length === 0 ||
+ names.every(([_, value]) => !value.type && value.required);
const returnElements = names.map(([key, value]) => {
// Important to not use shorthand props for rename functionality
- return `${value.identifierText || key}: ${key}`;
+ return `${dontAddTypeDef && value.doc ? `\n${value.doc}` : ''}${
+ value.identifierText || key
+ }: ${key}`;
});
- if (
- !isTsFile ||
- names.length === 0 ||
- names.every(([_, value]) => !value.type && value.required)
- ) {
+ if (dontAddTypeDef) {
// No exports or only `typeof` exports -> omit the `as {...}` completely.
// If not TS, omit the types to not have a "cannot use types in jsx" error.
return `{${returnElements.join(' , ')}}`;
}
const returnElementsType = names.map(([key, value]) => {
- const identifier = `${value.identifierText || key}${value.required ? '' : '?'}`;
+ const identifier = `${value.doc ? `\n${value.doc}` : ''}${value.identifierText || key}${
+ value.required ? '' : '?'
+ }`;
if (!value.type) {
return `${identifier}: typeof ${key}`;
}
diff --git a/packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts b/packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts
index 5e214508e..1d9058528 100644
--- a/packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts
+++ b/packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts
@@ -58,28 +58,6 @@ export function processInstanceScriptContent(
const pushScope = () => (scope = new Scope(scope));
const popScope = () => (scope = scope.parent);
- const addExport = (
- name: ts.BindingName,
- target: ts.BindingName = null,
- type: ts.TypeNode = null,
- required = false,
- ) => {
- if (name.kind != ts.SyntaxKind.Identifier) {
- throw Error('export source kind not supported ' + name);
- }
- if (target && target.kind != ts.SyntaxKind.Identifier) {
- throw Error('export target kind not supported ' + target);
- }
- if (target) {
- exportedNames.set(name.text, {
- type: type?.getText(),
- identifierText: (target as ts.Identifier).text,
- required,
- });
- } else {
- exportedNames.set(name.text, {});
- }
- };
const addGetter = (node: ts.Identifier) => {
if (!node) {
return;
@@ -277,14 +255,14 @@ export function processInstanceScriptContent(
ts.forEachChild(list, (node) => {
if (ts.isVariableDeclaration(node)) {
if (ts.isIdentifier(node.name)) {
- addExport(node.name, node.name, node.type, !node.initializer);
+ exportedNames.addExport(node.name, 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)) {
- addExport(element.name);
+ exportedNames.addExport(element.name);
}
});
}
@@ -376,9 +354,9 @@ export function processInstanceScriptContent(
if (ts.isNamedExports(exportClause)) {
for (const ne of exportClause.elements) {
if (ne.propertyName) {
- addExport(ne.propertyName, ne.name);
+ exportedNames.addExport(ne.propertyName, ne.name);
} else {
- addExport(ne.name);
+ exportedNames.addExport(ne.name);
}
}
//we can remove entire statement
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/export-doc/expected.tsx b/packages/svelte2tsx/test/svelte2tsx/samples/export-doc/expected.tsx
new file mode 100644
index 000000000..194fbaf3c
--- /dev/null
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/export-doc/expected.tsx
@@ -0,0 +1,24 @@
+///
+<>>;function render() {
+
+ /**
+ * DOCS!
+ */
+ let a;
+ /**
+ * MORE DOCS!
+ */
+ let b;
+ let c;
+;
+() => (<>>);
+return { props: {
+/**
+ * DOCS!
+ */a: a ,
+/**
+ * MORE DOCS!
+ */b: b , c: c}, slots: {}, getters: {}, events: {} }}
+
+export default class Input__SvelteComponent_ extends createSvelte2TsxComponent(__sveltets_partial(__sveltets_with_any_event(render))) {
+}
\ No newline at end of file
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/export-doc/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/export-doc/input.svelte
new file mode 100644
index 000000000..da4d456b3
--- /dev/null
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/export-doc/input.svelte
@@ -0,0 +1,11 @@
+
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/export-with-default-multi/expected.tsx b/packages/svelte2tsx/test/svelte2tsx/samples/export-with-default-multi/expected.tsx
index 9df45baff..df5b73354 100644
--- a/packages/svelte2tsx/test/svelte2tsx/samples/export-with-default-multi/expected.tsx
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/export-with-default-multi/expected.tsx
@@ -6,7 +6,9 @@
world = '';
;
() => (<>>);
-return { props: {name: name , world: world}, slots: {}, getters: {}, events: {} }}
+return { props: {
+/**@type { string | number }*/name: name ,
+/**@type { string | number }*/world: world}, slots: {}, getters: {}, events: {} }}
export default class Input__SvelteComponent_ extends createSvelte2TsxComponent(__sveltets_partial(__sveltets_with_any_event(render))) {
}
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-export-doc/expected.tsx b/packages/svelte2tsx/test/svelte2tsx/samples/ts-export-doc/expected.tsx
new file mode 100644
index 000000000..b85854a12
--- /dev/null
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-export-doc/expected.tsx
@@ -0,0 +1,24 @@
+///
+<>>;function render() {
+
+ /**
+ * DOCS!
+ */
+ let a: string;
+ /**
+ * MORE DOCS!
+ */
+ let b = 1;
+ let c;
+;
+() => (<>>);
+return { props: {a: a , b: b , c: c} as {
+/**
+ * DOCS!
+ */a: string,
+/**
+ * MORE DOCS!
+ */b?: typeof b, c: typeof c}, slots: {}, getters: {}, events: {} }}
+
+export default class Input__SvelteComponent_ extends createSvelte2TsxComponent(__sveltets_partial(__sveltets_with_any_event(render))) {
+}
\ No newline at end of file
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-export-doc/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/ts-export-doc/input.svelte
new file mode 100644
index 000000000..7ef6b1241
--- /dev/null
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-export-doc/input.svelte
@@ -0,0 +1,11 @@
+