Skip to content

Commit 62cb73f

Browse files
committed
fix: add new proto/enums support
1 parent c7fcf08 commit 62cb73f

4 files changed

Lines changed: 116 additions & 22 deletions

File tree

components/content/Parameter.vue

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
<script setup lang="ts">
22
import {CardContent} from '@/components/ui/card';
33
import type {ParamType} from '~/lib/manifest';
4+
import {definitionOf} from '~/lib/manifest';
45
const props = defineProps<{
56
group: string | undefined;
67
param: ParamType | undefined;
78
}>()
9+
// A prototype/enum may be written as a name; resolveManifest has replaced those
10+
// with the definition, so anything still a string names nothing and is skipped.
11+
const prototype = computed(() => definitionOf(props.param?.prototype));
12+
const enumerator = computed(() => definitionOf(props.param?.enum));
813
</script>
914

1015
<template>
11-
<span v-if="param?.prototype">
12-
<a :href="`#/${group}/${param.prototype?.name}`" class="text-primary hover:underline" >
13-
{{ param.prototype?.name }}
16+
<span v-if="prototype">
17+
<a :href="`#/${group}/${prototype.name}`" class="text-primary hover:underline" >
18+
{{ prototype.name }}
1419
</a>
1520
</span>
16-
<span v-else-if="param?.enum">
17-
<a :href="`#/${group}/${param.enum?.name}`" class="text-primary hover:underline" >
18-
{{ param.enum?.name }}
21+
<span v-else-if="enumerator">
22+
<a :href="`#/${group}/${enumerator.name}`" class="text-primary hover:underline" >
23+
{{ enumerator.name }}
1924
</a>
2025
</span>
2126
<span v-else class="text-primary">

components/content/Signature.vue

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
11
<script setup lang="ts">
22
import type {ParamType} from '~/lib/manifest';
3+
import {definitionOf} from '~/lib/manifest';
34
const props = defineProps<{
45
group: string | undefined;
56
param: ParamType | undefined;
67
}>()
8+
// A prototype/enum may be written as a name; resolveManifest has replaced those
9+
// with the definition, so anything still a string names nothing and is skipped.
10+
const prototype = computed(() => definitionOf(props.param?.prototype));
11+
const enumerator = computed(() => definitionOf(props.param?.enum));
712
</script>
813

914
<template>
10-
<span v-if="param?.prototype">
11-
<a :href="`#/${group}/${param.prototype?.name}`" class="text-primary hover:underline" >
12-
{{ param.prototype?.name }}
15+
<span v-if="prototype">
16+
<a :href="`#/${group}/${prototype.name}`" class="text-primary hover:underline" >
17+
{{ prototype.name }}
1318
</a>
1419
</span>
15-
<span v-else-if="param?.enum">
16-
<a :href="`#/${group}/${param.enum?.name}`" class="text-primary hover:underline" >
17-
{{ param.enum?.name }}
20+
<span v-else-if="enumerator">
21+
<a :href="`#/${group}/${enumerator.name}`" class="text-primary hover:underline" >
22+
{{ enumerator.name }}
1823
</a>
1924
</span>
2025
<span v-else class="text-primary">

lib/docStore.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type {
1212

1313
ClassType,
1414
} from '~/lib/manifest';
15+
import { definitionOf, resolveManifest } from '~/lib/manifest';
1516

1617
// Add new constants for cache expiration (in milliseconds) and database version
1718
const CACHE_EXPIRATION_TIME = 24 * 60 * 60 * 1000; // 24 hours for example
@@ -30,14 +31,17 @@ function ProcessItem(
3031
delgs: MethodMap,
3132
enums: EnumMap
3233
): void {
33-
if (param.prototype && param.prototype.name) {
34-
if (!delgs[param.prototype.name]) {
35-
delgs[param.prototype.name] = param.prototype;
34+
const prototype = definitionOf(param.prototype);
35+
const enumerator = definitionOf(param.enum);
36+
37+
if (prototype && prototype.name) {
38+
if (!delgs[prototype.name]) {
39+
delgs[prototype.name] = prototype;
40+
ProcessMethod(prototype, delgs, enums);
3641
}
37-
ProcessMethod(param.prototype, delgs, enums);
38-
} else if (param.enum && param.enum.name) {
39-
if (!enums[param.enum.name] && param.enum.values) {
40-
enums[param.enum.name] = param.enum;
42+
} else if (enumerator && enumerator.name) {
43+
if (!enums[enumerator.name] && enumerator.values) {
44+
enums[enumerator.name] = enumerator;
4145
}
4246
}
4347
}
@@ -182,7 +186,9 @@ export const useDocStore = defineStore('docStore', {
182186
async refreshDocInBackground(url: string) {
183187
try {
184188
const response: Response = await fetch(url);
185-
const manifest: ManifestType = await response.json();
189+
// Link by-name prototype/enum references before anything reads the
190+
// manifest, so the rest of this store only ever sees definitions.
191+
const manifest: ManifestType = resolveManifest(await response.json());
186192

187193
let data: Document = {};
188194

lib/manifest.ts

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ export type ManifestType = {
33
name?: string;
44
methods?: MethodType[];
55
classes?: ClassType[];
6+
prototypes?: MethodType[];
7+
enums?: EnumType[];
68
}
79

810
export type BaseType = {
@@ -29,8 +31,8 @@ export type MethodType = BaseType & {
2931
export type ParamType = BaseType & {
3032
type?: string;
3133
ref?: boolean;
32-
prototype?: MethodType;
33-
enum?: EnumType;
34+
prototype?: MethodType | string;
35+
enum?: EnumType | string;
3436
};
3537

3638
export type AliasType = BaseType & {
@@ -56,3 +58,79 @@ export type MethodMap = Record<string, MethodType>;
5658
export type EnumMap = Record<string, EnumType>;
5759
export type ClassMap = Record<string, ClassType>;
5860

61+
/**
62+
* Links every by-name prototype/enum reference in a manifest to its definition,
63+
* and hoists inline definitions into the shared tables, so that afterwards every
64+
* `paramTypes`/`retType` entry carries a full object.
65+
*
66+
* Mirrors Manifest::Resolve in plugify core. Unlike the loader this is forgiving:
67+
* a reference that names nothing is left as it was rather than rejected, since a
68+
* viewer showing most of a page beats one showing an error.
69+
*/
70+
export function resolveManifest(manifest: ManifestType): ManifestType {
71+
const prototypes: MethodMap = {};
72+
const enums: EnumMap = {};
73+
74+
for (const prototype of manifest.prototypes ?? []) {
75+
if (prototype.name) prototypes[prototype.name] = prototype;
76+
}
77+
for (const enumerator of manifest.enums ?? []) {
78+
if (enumerator.name) enums[enumerator.name] = enumerator;
79+
}
80+
81+
// Pass one: collect the definitions written inline.
82+
const collect = (param: ParamType, seen: Set<MethodType>) => {
83+
const prototype = param.prototype;
84+
if (prototype && typeof prototype !== 'string' && prototype.name) {
85+
prototypes[prototype.name] ??= prototype;
86+
if (!seen.has(prototype)) {
87+
seen.add(prototype);
88+
for (const nested of prototype.paramTypes ?? []) collect(nested, seen);
89+
if (prototype.retType) collect(prototype.retType, seen);
90+
}
91+
}
92+
const enumerator = param.enum;
93+
if (enumerator && typeof enumerator !== 'string' && enumerator.name && enumerator.values?.length) {
94+
enums[enumerator.name] ??= enumerator;
95+
}
96+
};
97+
98+
const seen = new Set<MethodType>();
99+
for (const method of manifest.methods ?? []) {
100+
for (const param of method.paramTypes ?? []) collect(param, seen);
101+
if (method.retType) collect(method.retType, seen);
102+
}
103+
for (const prototype of manifest.prototypes ?? []) {
104+
for (const param of prototype.paramTypes ?? []) collect(param, seen);
105+
if (prototype.retType) collect(prototype.retType, seen);
106+
}
107+
108+
// Pass two: swap each reference for the definition it names. Every definition
109+
// is known by now, so references may point forwards.
110+
const link = (param: ParamType) => {
111+
if (typeof param.prototype === 'string') {
112+
param.prototype = prototypes[param.prototype] ?? param.prototype;
113+
}
114+
if (typeof param.enum === 'string') {
115+
param.enum = enums[param.enum] ?? param.enum;
116+
}
117+
};
118+
119+
const linkOwner = (owner: MethodType) => {
120+
for (const param of owner.paramTypes ?? []) link(param);
121+
if (owner.retType) link(owner.retType);
122+
};
123+
124+
for (const method of manifest.methods ?? []) linkOwner(method);
125+
for (const prototype of Object.values(prototypes)) linkOwner(prototype);
126+
127+
manifest.prototypes = Object.keys(prototypes).sort().map(name => prototypes[name]);
128+
manifest.enums = Object.keys(enums).sort().map(name => enums[name]);
129+
return manifest;
130+
}
131+
132+
/** Narrows a resolved prototype/enum field to its definition. */
133+
export function definitionOf<T extends BaseType>(value: T | string | undefined): T | undefined {
134+
return typeof value === 'string' ? undefined : value;
135+
}
136+

0 commit comments

Comments
 (0)