Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support generics attribute for JSDoc #2624

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
24 changes: 18 additions & 6 deletions packages/svelte2tsx/src/svelte2tsx/addComponentExport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ function addGenericsComponentExport({
fileName,
mode,
usesAccessors,
isTsFile,
str,
generics,
usesSlots,
Expand All @@ -65,6 +66,8 @@ function addGenericsComponentExport({
return `ReturnType<__sveltets_Render${genericsRef}['${forPart}']>`;
}

// TODO once Svelte 4 compatibility is dropped, we can simplify this, because since TS 4.7 it is possible to use generics
// like this: `typeof render<T>` - which wasn't possibly before, hence the class + methods workaround.
let statement = `
class __sveltets_Render${genericsDef} {
props() {
Expand All @@ -76,14 +79,23 @@ class __sveltets_Render${genericsDef} {
slots() {
return render${genericsRef}().slots;
}
${
isSvelte5
`;

// For Svelte 5+ we assume TS > 4.7
if (isSvelte5 && !isTsFile && exportedNames.usesRunes()) {
statement = `
class __sveltets_Render${genericsDef} {
props(): ReturnType<typeof render${genericsRef}>['props'] { return null as any; }
events(): ReturnType<typeof render${genericsRef}>['events'] { return null as any; }
slots(): ReturnType<typeof render${genericsRef}>['slots'] { return null as any; }
`;
}

statement += isSvelte5
? ` bindings() { return ${exportedNames.createBindingsStr()}; }
exports() { return ${exportedNames.hasExports() ? `render${genericsRef}().exports` : '{}'}; }
}`
: '}'
}
`;
}\n`
: '}\n';

const svelteComponentClass = noSvelteComponentTyped
? 'SvelteComponent'
Expand Down
16 changes: 13 additions & 3 deletions packages/svelte2tsx/src/svelte2tsx/createRenderFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import MagicString from 'magic-string';
import { Node } from 'estree-walker';
import { ComponentEvents } from './nodes/ComponentEvents';
import { InstanceScriptProcessResult } from './processInstanceScriptContent';
import { surroundWithIgnoreComments } from '../utils/ignore';
import {
IGNORE_END_COMMENT,
IGNORE_START_COMMENT,
surroundWithIgnoreComments
} from '../utils/ignore';

export interface CreateRenderFunctionPara extends InstanceScriptProcessResult {
str: MagicString;
Expand All @@ -12,6 +16,7 @@ export interface CreateRenderFunctionPara extends InstanceScriptProcessResult {
events: ComponentEvents;
uses$$SlotsInterface: boolean;
svelte5Plus: boolean;
isTsFile: boolean;
mode?: 'ts' | 'dts';
}

Expand All @@ -27,6 +32,7 @@ export function createRenderFunction({
uses$$slots,
uses$$SlotsInterface,
generics,
isTsFile,
mode
}: CreateRenderFunctionPara) {
const htmlx = str.original;
Expand Down Expand Up @@ -70,8 +76,12 @@ export function createRenderFunction({
end--;
}
str.overwrite(scriptTag.start + 1, start - 1, `function render`);
str.overwrite(start - 1, start, `<`); // if the generics are unused, only this char is colored opaque
str.overwrite(end, scriptTagEnd, `>() {${propsDecl}\n`);
str.overwrite(start - 1, start, isTsFile ? '<' : `<${IGNORE_START_COMMENT}`); // if the generics are unused, only this char is colored opaque
str.overwrite(
end,
scriptTagEnd,
`>${isTsFile ? '' : IGNORE_END_COMMENT}() {${propsDecl}\n`
);
} else {
str.overwrite(
scriptTag.start + 1,
Expand Down
15 changes: 5 additions & 10 deletions packages/svelte2tsx/src/svelte2tsx/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export function svelte2tsx(
const str = new MagicString(svelte);
const basename = path.basename(options.filename || '');
const svelte5Plus = Number(options.version![0]) > 4;
const isTsFile = options?.isTsFile;

// process the htmlx as a svelte template
let {
Expand Down Expand Up @@ -95,14 +96,7 @@ export function svelte2tsx(
: instanceScriptTarget;
const implicitStoreValues = new ImplicitStoreValues(resolvedStores, renderFunctionStart);
//move the instance script and process the content
let exportedNames = new ExportedNames(
str,
0,
basename,
options?.isTsFile,
svelte5Plus,
isRunes
);
let exportedNames = new ExportedNames(str, 0, basename, isTsFile, svelte5Plus, isRunes);
let generics = new Generics(str, 0, { attributes: [] } as any);
let uses$$SlotsInterface = false;
if (scriptTag) {
Expand All @@ -117,7 +111,7 @@ export function svelte2tsx(
implicitStoreValues,
options.mode,
moduleAst,
options?.isTsFile,
isTsFile,
basename,
svelte5Plus,
isRunes
Expand Down Expand Up @@ -148,6 +142,7 @@ export function svelte2tsx(
uses$$SlotsInterface,
generics,
svelte5Plus,
isTsFile,
mode: options.mode
});

Expand Down Expand Up @@ -195,7 +190,7 @@ export function svelte2tsx(
str,
canHaveAnyProp: !exportedNames.uses$$Props && (uses$$props || uses$$restProps),
events,
isTsFile: options?.isTsFile,
isTsFile,
exportedNames,
usesAccessors,
usesSlots: slots.size > 0,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
///<reference types="svelte" />
;function render</*Ωignore_startΩ*/A, B extends keyof A, C extends boolean>/*Ωignore_endΩ*/() {

/** @typedef {{ a: A; b: B; c: C }} $$ComponentProps *//** @type {$$ComponentProps} */
const { a, b, c } = $props();

function getA() {
return a;
}
;
async () => {};
return { props: /** @type {$$ComponentProps} */({}), exports: /** @type {{getA: typeof getA}} */ ({}), bindings: __sveltets_$$bindings(''), slots: {}, events: {} }}
class __sveltets_Render<A,B extends keyof A,C extends boolean> {
props(): ReturnType<typeof render<A,B,C>>['props'] { return null as any; }
events(): ReturnType<typeof render<A,B,C>>['events'] { return null as any; }
slots(): ReturnType<typeof render<A,B,C>>['slots'] { return null as any; }
bindings() { return __sveltets_$$bindings(''); }
exports() { return render<A,B,C>().exports; }
}

interface $$IsomorphicComponent {
new <A,B extends keyof A,C extends boolean>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<A,B,C>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<A,B,C>['props']>, ReturnType<__sveltets_Render<A,B,C>['events']>, ReturnType<__sveltets_Render<A,B,C>['slots']>> & { $$bindings?: ReturnType<__sveltets_Render<A,B,C>['bindings']> } & ReturnType<__sveltets_Render<A,B,C>['exports']>;
<A,B extends keyof A,C extends boolean>(internal: unknown, props: ReturnType<__sveltets_Render<A,B,C>['props']> & {}): ReturnType<__sveltets_Render<A,B,C>['exports']>;
z_$$bindings?: ReturnType<__sveltets_Render<any,any,any>['bindings']>;
}
const Input__SvelteComponent_: $$IsomorphicComponent = null as any;
/*Ωignore_startΩ*/type Input__SvelteComponent_<A,B extends keyof A,C extends boolean> = InstanceType<typeof Input__SvelteComponent_<A,B,C>>;
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script generics="A, B extends keyof A, C extends boolean">
/** @type {{ a: A; b: B; c: C }} */
const { a, b, c } = $props();
export function getA() {
return a;
}
</script>
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}, exports: {}, bindings: "", slots: {}, events: {} }}
return { props: {items: items} as {items: T}, 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 items: T/*Ωignore_startΩ*/;items = __sveltets_2_any(items);/*Ωignore_endΩ*/;
;
async () => {};
return { props: {items: items}, slots: {}, events: {} }}
return { props: {items: items} as {items: T}, slots: {}, events: {} }}
class __sveltets_Render<const T extends readonly string[]> {
props() {
return render<T>().props;
Expand Down
Loading