Skip to content

Commit 66375d9

Browse files
committed
Fixed inherited function generated
1 parent 3be36b7 commit 66375d9

1 file changed

Lines changed: 71 additions & 8 deletions

File tree

src/main.ts

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -370,13 +370,65 @@ function generateConstructor(
370370
const INHERITING_SYSTEM_URL =
371371
"https://docs.nanos-world.com/docs/core-concepts/scripting/inheriting-classes";
372372

373-
function hasInherit(classes: Record<string, DocClass>, cls: DocClass): boolean {
374-
if (cls.staticClass || cls.struct) return false;
373+
interface InheritSource {
374+
fun: DocFunction;
375+
owner: DocClass;
376+
}
375377

376-
return [cls, ...(cls.inheritance ?? []).map((name) => classes[name])].some(
377-
(candidate) =>
378-
candidate?.static_functions?.some((fun) => fun.name === "Inherit"),
379-
);
378+
/**
379+
* Finds the `Inherit` static function this class exposes, either declared on
380+
* itself or picked up from one of its parents.
381+
*/
382+
function findInherit(
383+
classes: Record<string, DocClass>,
384+
cls: DocClass,
385+
): InheritSource | undefined {
386+
if (cls.staticClass || cls.struct) return undefined;
387+
388+
for (const candidate of [
389+
cls,
390+
...(cls.inheritance ?? []).map((name) => classes[name]),
391+
]) {
392+
const fun = candidate?.static_functions?.find(
393+
(fun) => fun.name === "Inherit",
394+
);
395+
if (fun !== undefined) {
396+
return { fun, owner: candidate };
397+
}
398+
}
399+
400+
return undefined;
401+
}
402+
403+
/**
404+
* Redeclares `Inherit` on the class itself so it returns the class type instead
405+
* of the generic `table` from the parent declaration. Without this, `self` in an
406+
* inherited Class' methods is untyped and `self.Super` resolves to nothing.
407+
*
408+
* The return type is a subtype rather than the class itself, so that custom
409+
* fields and methods can still be freely added to the inherited Class table
410+
* without tripping the `inject-field`/`undefined-field` diagnostics.
411+
*/
412+
function generateInheritFunction(
413+
inherit: InheritSource,
414+
cls: DocClass,
415+
): string {
416+
const { fun, owner } = inherit;
417+
const params = generateParams(fun.parameters, owner.jsonFileName);
418+
const inheritedType = `${cls.name}.Inherited`;
419+
420+
return `
421+
422+
---A Class created from <code>${cls.name}.Inherit()</code> (see the <a href="${INHERITING_SYSTEM_URL}">Inheriting System</a>)
423+
---@class ${inheritedType} : ${cls.name}
424+
---@field [string] any @Custom values and methods declared on the inherited Class
425+
426+
---${generateAuthorityString(fun.authority)}
427+
---${generateDocsLink(owner.jsonFileName ?? owner.name, owner.name, "static-function-inherit")}
428+
---
429+
---${generateDocstring(fun, owner.jsonFileName)}${params.string}
430+
---@return ${inheritedType} @The new Class table, inheriting from ${cls.name}
431+
function ${cls.name}.Inherit(${params.names}) end`;
380432
}
381433

382434
function generateConstructorFunction(
@@ -420,6 +472,9 @@ function generateClassAnnotations(
420472
inheritance = ` : ${cls.inheritance.join(", ")}`;
421473
}
422474

475+
const inherit = findInherit(classes, cls);
476+
const isInheritable = inherit !== undefined;
477+
423478
const constructors =
424479
cls.constructors?.reduce(
425480
(prev, constructor) =>
@@ -439,6 +494,11 @@ function generateClassAnnotations(
439494
return;
440495
}
441496

497+
// Redeclared below with the class as its return type
498+
if (fun.name === "Inherit" && inherit?.owner === cls) {
499+
return;
500+
}
501+
442502
staticFunctions += generateFunction(
443503
jsonFileName,
444504
fun,
@@ -572,7 +632,6 @@ function ${cls.name}.Unsubscribe(event_name, callback) end
572632
}`;
573633
}
574634

575-
const isInheritable = hasInherit(classes, cls);
576635
let fields = !isInheritable
577636
? ""
578637
: `\n---@field Super ${cls.name} @Access to the original/native ${cls.name} methods from within an inherited Class (see the <a href="${INHERITING_SYSTEM_URL}">Inheriting System</a>)`;
@@ -610,14 +669,18 @@ function ${cls.name}.Unsubscribe(event_name, callback) end
610669
? ""
611670
: generateConstructorFunction(jsonFileName, cls.constructors, cls);
612671

672+
const inheritFunction = !isInheritable
673+
? ""
674+
: generateInheritFunction(inherit, cls);
675+
613676
return `
614677
615678
---${generateAuthorityString(cls.authority)}
616679
---${generateDocsLink(jsonFileName, cls.name)}${generateConstructorLinks(jsonFileName, cls)}
617680
---
618681
---${generateDocstring(cls, jsonFileName)}
619682
---@class ${cls.name}${inheritance}${fields}${operators}${constructors}
620-
${cls.name} = {}${staticFields}${constructorFunction}${staticFunctions}${functions}${events}`;
683+
${cls.name} = {}${staticFields}${constructorFunction}${inheritFunction}${staticFunctions}${functions}${events}`;
621684
}
622685

623686
function generateEnum(name: string, values: DocEnumValue[]): string {

0 commit comments

Comments
 (0)