Skip to content

Commit 5146962

Browse files
1 parent e949a3d commit 5146962

File tree

4 files changed

+153
-56
lines changed

4 files changed

+153
-56
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
3+
changeKind: feature
4+
packages:
5+
- "@typespec/html-program-viewer"
6+
---
7+
8+
Render `indexer` property on model

packages/html-program-viewer/src/react/inspect-type/inspect-type.tsx

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ import { useCallback, type FunctionComponent, type ReactElement, type ReactNode
44
import { isNamedUnion } from "../../utils.js";
55
import { Literal, Mono, TypeKind } from "../common.js";
66
import { JsValue } from "../js-inspector/js-value/js-value.js";
7-
import { getPropertyRendering, type EntityPropertyConfig } from "../type-config.js";
7+
import {
8+
getRenderingConfig,
9+
type PropertiesRendering,
10+
type PropertyRendering,
11+
} from "../type-config.js";
812
import { useTreeNavigatorOptional } from "../use-tree-navigation.js";
913
import style from "./inspect-type.module.css";
1014

@@ -152,11 +156,23 @@ const SimpleType = ({ type, children }: { type: Type; children: ReactNode }) =>
152156
);
153157
};
154158

155-
const EntityProperties = ({ entity: type }: { entity: Entity }) => {
156-
const props = Object.entries(type)
159+
const EntityProperties = ({ entity }: { entity: Entity }) => {
160+
return <InspectObject value={entity} config={getRenderingConfig(entity)} />;
161+
};
162+
const InspectObject = ({
163+
value,
164+
config,
165+
}: {
166+
value: object | undefined;
167+
config: PropertiesRendering<any> | null;
168+
}) => {
169+
if (value === undefined) {
170+
return null;
171+
}
172+
const props = Object.entries(value)
157173
.map(([key, value]) => {
158-
const action = getPropertyRendering(type as any, key);
159-
if (action === undefined || action === "skip") {
174+
const action = config?.[key];
175+
if (action === undefined || action === null || action.kind === "skip") {
160176
return undefined;
161177
}
162178
return <EntityProperty key={key} name={key} value={value} action={action} />;
@@ -169,7 +185,7 @@ const EntityProperties = ({ entity: type }: { entity: Entity }) => {
169185
interface EntityPropertyProps {
170186
name: string;
171187
value: any;
172-
action: EntityPropertyConfig;
188+
action: PropertyRendering<any>;
173189
}
174190
const EntityProperty = (props: EntityPropertyProps) => {
175191
return (
@@ -184,13 +200,17 @@ const EntityProperty = (props: EntityPropertyProps) => {
184200

185201
const EntityPropertyValue = ({ value, action }: EntityPropertyProps) => {
186202
const render = (x: Entity) => {
187-
if (action === "parent") {
203+
if (action.kind === "parent") {
188204
return x.entityKind === "Type" ? <ParentReference type={x} /> : null;
189205
}
190-
const renderRef = action === "ref";
206+
const renderRef = action.kind === "ref";
191207
return renderRef ? <EntityReference entity={x} /> : <EntityUI entity={x} />;
192208
};
193209

210+
if (action.kind === "nested") {
211+
return <InspectObject value={value} config={action.properties} />;
212+
}
213+
194214
if (value === undefined) {
195215
return null;
196216
} else if (value.entityKind) {
Lines changed: 116 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,90 @@
1-
import type { Type } from "@typespec/compiler";
1+
import type { Entity, Type } from "@typespec/compiler";
22

3-
export type EntityPropertyConfig = "parent" | "nested" | "ref" | "value" | "skip";
3+
export type PropertyRendering<T> =
4+
| { kind: "parent" | "nested-items" | "ref" | "value" | "skip" }
5+
| NestedPropertyRendering<T>;
6+
export type PropertyRenderingRaw<T> =
7+
| "parent"
8+
| "nested-items"
9+
| "ref"
10+
| "value"
11+
| "skip"
12+
| NestedPropertyRenderingRaw<T>;
413

5-
export const TypeConfig: TypeGraphConfig = {
14+
export type PropertiesRenderingRaw<T> = { [K in keyof T]: PropertyRenderingRaw<T[K]> };
15+
export type PropertiesRendering<T> = { [K in keyof T]: PropertyRendering<T[K]> };
16+
17+
export type NestedPropertyRendering<T> = {
18+
kind: "nested";
19+
properties: PropertiesRendering<T>;
20+
};
21+
export type NestedPropertyRenderingRaw<T> = {
22+
kind: "nested";
23+
properties: PropertiesRenderingRaw<T>;
24+
};
25+
26+
export const CommonPropsConfig = {
27+
namespace: "parent",
28+
name: "value",
29+
};
30+
31+
const HiddenProps = [
32+
"entityKind",
33+
"kind",
34+
"node",
35+
"symbol",
36+
"templateNode",
37+
"templateArguments",
38+
"templateMapper",
39+
"instantiationParameters",
40+
"decorators",
41+
"isFinished",
42+
] as const;
43+
44+
const HiddenPropsConfig = Object.fromEntries(HiddenProps.map((prop) => [prop, "skip"])) as Record<
45+
HiddenPropsType,
46+
"skip"
47+
>;
48+
49+
export const TypeConfig: TypeGraphConfig = buildConfig({
650
Namespace: {
751
namespaces: "skip",
8-
models: "nested",
9-
scalars: "nested",
10-
interfaces: "nested",
11-
operations: "nested",
12-
unions: "nested",
13-
enums: "nested",
14-
decoratorDeclarations: "nested",
52+
models: "nested-items",
53+
scalars: "nested-items",
54+
interfaces: "nested-items",
55+
operations: "nested-items",
56+
unions: "nested-items",
57+
enums: "nested-items",
58+
decoratorDeclarations: "nested-items",
1559
},
1660
Interface: {
17-
operations: "nested",
61+
operations: "nested-items",
1862
sourceInterfaces: "ref",
1963
},
2064
Operation: {
2165
interface: "parent",
22-
parameters: "nested",
66+
parameters: "nested-items",
2367
returnType: "ref",
2468
sourceOperation: "ref",
2569
},
2670
Model: {
27-
indexer: "skip",
71+
indexer: {
72+
kind: "nested",
73+
properties: {
74+
key: "ref",
75+
value: "ref",
76+
},
77+
},
2878
baseModel: "ref",
2979
derivedModels: "ref",
30-
properties: "nested",
80+
properties: "nested-items",
3181
sourceModel: "ref",
3282
sourceModels: "value",
3383
},
3484
Scalar: {
3585
baseScalar: "ref",
3686
derivedScalars: "ref",
37-
constructors: "nested",
87+
constructors: "nested-items",
3888
},
3989
ModelProperty: {
4090
model: "parent",
@@ -44,16 +94,16 @@ export const TypeConfig: TypeGraphConfig = {
4494
defaultValue: "value",
4595
},
4696
Enum: {
47-
members: "nested",
97+
members: "nested-items",
4898
},
4999
EnumMember: {
50100
enum: "parent",
51101
sourceMember: "ref",
52102
value: "value",
53103
},
54104
Union: {
55-
expression: "skip",
56-
variants: "nested",
105+
expression: "value",
106+
variants: "nested-items",
57107
},
58108
UnionVariant: {
59109
union: "parent",
@@ -63,13 +113,13 @@ export const TypeConfig: TypeGraphConfig = {
63113
value: "value",
64114
},
65115
Decorator: {
66-
parameters: "nested",
116+
parameters: "nested-items",
67117
implementation: "skip",
68118
target: "ref",
69119
},
70120
ScalarConstructor: {
71121
scalar: "parent",
72-
parameters: "nested",
122+
parameters: "nested-items",
73123
},
74124
FunctionParameter: null,
75125
Number: {
@@ -81,10 +131,10 @@ export const TypeConfig: TypeGraphConfig = {
81131
value: "value",
82132
},
83133
Tuple: {
84-
values: "nested",
134+
values: "nested-items",
85135
},
86136
StringTemplate: {
87-
spans: "nested",
137+
spans: "nested-items",
88138
stringValue: "value",
89139
},
90140
StringTemplateSpan: {
@@ -98,44 +148,63 @@ export const TypeConfig: TypeGraphConfig = {
98148

99149
// Don't want to expose those for now
100150
Intrinsic: null,
101-
};
151+
});
102152

103-
type PropsToDefine<T extends Type> = Exclude<
104-
keyof T,
105-
HiddenPropsType | keyof typeof CommonPropsConfig
106-
>;
107-
type TypeConfig<T extends Type> = Record<PropsToDefine<T>, EntityPropertyConfig> | null;
153+
type PropsToDefine<T extends Type> = Omit<T, HiddenPropsType | keyof typeof CommonPropsConfig>;
154+
type TypeRawConfig<T extends Type> = PropertiesRenderingRaw<PropsToDefine<T>> | null;
155+
type TypeGraphRawConfig = {
156+
[K in Type["kind"]]: TypeRawConfig<Extract<Type, { kind: K }>>;
157+
};
158+
type TypeConfig<T extends Type> = PropertiesRendering<T> | null;
108159
type TypeGraphConfig = {
109160
[K in Type["kind"]]: TypeConfig<Extract<Type, { kind: K }>>;
110161
};
111162

112-
export const CommonPropsConfig = {
113-
namespace: "parent",
114-
};
115-
116-
const HiddenProps = [
117-
"entityKind",
118-
"kind",
119-
"name",
120-
"node",
121-
"symbol",
122-
"templateNode",
123-
"templateArguments",
124-
"templateMapper",
125-
"instantiationParameters",
126-
"decorators",
127-
"projector",
128-
"isFinished",
129-
] as const;
130163
type HiddenPropsType = (typeof HiddenProps)[number];
131164

132165
export const HiddenPropsSet = new Set(HiddenProps);
133166

134167
export function getPropertyRendering<T extends Type, K extends keyof T>(
135168
type: T,
136169
key: K,
137-
): EntityPropertyConfig {
170+
): PropertyRenderingRaw<T> {
138171
const properties = (TypeConfig as any)[type.kind];
139172
const action = properties?.[key] ?? (CommonPropsConfig as any)[key];
140173
return action;
141174
}
175+
export function getRenderingConfig<T extends Entity>(type: T): PropertiesRendering<T> | null {
176+
return (TypeConfig as any)[(type as any).kind];
177+
}
178+
179+
function buildConfig(raw: TypeGraphRawConfig): TypeGraphConfig {
180+
return Object.fromEntries(
181+
Object.entries(raw).map(([kind, config]) => {
182+
return [kind, buildConfigForKind(config as any)];
183+
}),
184+
) as any;
185+
}
186+
187+
function buildConfigForKind<T extends Type>(config: TypeRawConfig<T> | null): TypeConfig<T> | null {
188+
if (config === null) {
189+
return null;
190+
}
191+
return Object.fromEntries(
192+
Object.entries({ ...CommonPropsConfig, ...HiddenPropsConfig, ...config }).map(
193+
([key, value]) => {
194+
return [key, buildConfigForProperty(value as any)];
195+
},
196+
),
197+
) as any;
198+
}
199+
200+
function buildConfigForProperty<T extends Type>(
201+
value: PropertyRenderingRaw<T>,
202+
): PropertyRendering<T> {
203+
if (typeof value === "string") {
204+
return { kind: value };
205+
}
206+
return {
207+
kind: "nested",
208+
properties: buildConfigForKind(value.properties) as PropertiesRendering<T>,
209+
};
210+
}

packages/html-program-viewer/src/react/use-tree-navigation.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ function computeTypeNode(parentPath: string, type: NamedType, name?: string): Ty
117117
function computeTypeNodeProps(path: string, type: NamedType, name?: string): TypeGraphTypeNode {
118118
const typeRendering = (TypeConfig as any)[type.kind];
119119
const children: TypeGraphNode[] = Object.entries(type)
120-
.filter(([key]) => typeRendering?.[key] === "nested")
120+
.filter(([key]) => typeRendering?.[key]?.kind === "nested-items")
121121
.map(([key, value]): TypeGraphNode => {
122122
const propPath = path + "." + key;
123123
if (isMapLike(value)) {

0 commit comments

Comments
 (0)