Skip to content

Commit

Permalink
feat(component-parser): support generics
Browse files Browse the repository at this point in the history
  • Loading branch information
metonym committed Apr 20, 2024
1 parent a59e9f7 commit 7e664dc
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 5 deletions.
9 changes: 9 additions & 0 deletions src/ComponentParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ interface TypeDef {
ts: string;
}

type ComponentGenerics = [name: string, type: string];

interface ComponentInlineElement {
type: "InlineComponent";
name: string;
Expand Down Expand Up @@ -108,6 +110,7 @@ export interface ParsedComponent {
slots: ComponentSlot[];
events: ComponentEvent[];
typedefs: TypeDef[];
generics: null | ComponentGenerics;
rest_props: RestProps;
extends?: Extends;
componentComment?: string;
Expand All @@ -128,6 +131,7 @@ export default class ComponentParser {
private readonly slots: Map<ComponentSlotName, ComponentSlot> = new Map();
private readonly events: Map<ComponentEventName, ComponentEvent> = new Map();
private readonly typedefs: Map<TypeDefName, TypeDef> = new Map();
private readonly generics: ComponentGenerics = null;
private readonly bindings: Map<ComponentPropName, ComponentPropBindings> = new Map();

constructor(options?: ComponentParserOptions) {
Expand Down Expand Up @@ -311,6 +315,9 @@ export default class ComponentParser {
ts: /(\}|\};)$/.test(type) ? `interface ${name} ${type}` : `type ${name} = ${type}`,
});
break;
case "generics":
this.generics = [name, type];
break;
}
});
});
Expand All @@ -329,6 +336,7 @@ export default class ComponentParser {
this.slots.clear();
this.events.clear();
this.typedefs.clear();
this.generics = null;
this.bindings.clear();
}

Expand Down Expand Up @@ -732,6 +740,7 @@ export default class ComponentParser {
}),
events: ComponentParser.mapToArray(this.events),
typedefs: ComponentParser.mapToArray(this.typedefs),
generics: this.generics,
rest_props: this.rest_props,
extends: this.extends,
componentComment: this.componentComment,
Expand Down
21 changes: 16 additions & 5 deletions src/writer/writer-ts-definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function addCommentLine(value: any, returnValue?: any) {
return `* ${returnValue || value}\n`;
}

function genPropDef(def: Pick<ComponentDocApi, "props" | "rest_props" | "moduleName" | "extends">) {
function genPropDef(def: Pick<ComponentDocApi, "props" | "rest_props" | "moduleName" | "extends" | "generics">) {
const initial_props = def.props
.filter((prop) => !prop.isFunctionDeclaration && prop.kind !== "const")
.map((prop) => {
Expand Down Expand Up @@ -68,6 +68,8 @@ function genPropDef(def: Pick<ComponentDocApi, "props" | "rest_props" | "moduleN

let prop_def = EMPTY_STR;

const genericsName = def.generics ? `<${def.generics[0]}>` : "";

if (def.rest_props?.type === "Element") {
const extend_tag_map = def.rest_props.name
.split("|")
Expand All @@ -88,15 +90,19 @@ function genPropDef(def: Pick<ComponentDocApi, "props" | "rest_props" | "moduleN

prop_def = `
${extend_tag_map ? `type RestProps = ${extend_tag_map};\n` : ""}
export interface ${props_name} extends ${def.extends !== undefined ? `${def.extends.interface}, ` : ""}RestProps {
export interface ${props_name}${genericsName} extends ${
def.extends !== undefined ? `${def.extends.interface}, ` : ""
}RestProps {
${props}
${dataAttributes}
}
`;
} else {
prop_def = `
export interface ${props_name} ${def.extends !== undefined ? `extends ${def.extends.interface}` : ""} {
export interface ${props_name}${genericsName} ${
def.extends !== undefined ? `extends ${def.extends.interface}` : ""
} {
${props}
}
`;
Expand Down Expand Up @@ -203,6 +209,7 @@ export function writeTsDefinition(component: ComponentDocApi) {
const {
moduleName,
typedefs,
generics,
props,
moduleExports,
slots,
Expand All @@ -216,8 +223,12 @@ export function writeTsDefinition(component: ComponentDocApi) {
props,
rest_props,
extends: _extends,
generics,
});

const generic = generics ? `<${generics[1]}>` : "";
const genericProps = generics ? `${props_name}<${generics[0]}>` : props_name;

return `
import type { SvelteComponentTyped } from "svelte";${
rest_props?.type === "Element" ? `import type { SvelteHTMLElements } from "svelte/elements";\n` : ""
Expand All @@ -227,8 +238,8 @@ export function writeTsDefinition(component: ComponentDocApi) {
${getTypeDefs({ typedefs })}
${prop_def}
${genComponentComment({ componentComment })}
export default class ${moduleName === "default" ? "" : moduleName} extends SvelteComponentTyped<
${props_name},
export default class ${moduleName === "default" ? "" : moduleName}${generic} extends SvelteComponentTyped<
${genericProps},
${genEventDef({ events })},
{${genSlotDef({ slots })}}
> {
Expand Down

0 comments on commit 7e664dc

Please sign in to comment.