Repository navigation
Expand file tree
/
Copy pathschema-metadata.ts
More file actions
123 lines (104 loc) · 2.88 KB
/
Copy pathschema-metadata.ts
File metadata and controls
123 lines (104 loc) · 2.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
export type JsonObject = Record<string, unknown>;
export type JsonSchema = Record<string, unknown>;
export function isJsonObject(value: unknown): value is JsonObject {
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}
function decodeJsonPointerSegment(segment: string): string {
return segment.replaceAll("~1", "/").replaceAll("~0", "~");
}
export function resolveSchemaPointer(
rootSchema: JsonSchema,
pointer: string,
): unknown {
if (pointer === "#") {
return rootSchema;
}
if (!pointer.startsWith("#/")) {
return undefined;
}
let current: unknown = rootSchema;
for (const segment of pointer
.slice(2)
.split("/")
.map(decodeJsonPointerSegment)) {
if (!isJsonObject(current) || !(segment in current)) {
return undefined;
}
current = current[segment];
}
return current;
}
export function dereferenceSchema(
rootSchema: JsonSchema,
schema: unknown,
): JsonSchema | null {
if (!isJsonObject(schema)) {
return null;
}
let current: JsonSchema | null = schema;
const seenRefs = new Set<string>();
while (current && typeof current.$ref === "string") {
const ref = current.$ref;
if (seenRefs.has(ref)) {
return null;
}
seenRefs.add(ref);
const resolved = resolveSchemaPointer(rootSchema, ref);
current = isJsonObject(resolved) ? resolved : null;
}
return current;
}
export function getSchemaAtPointer(
schemaDocument: unknown,
pointer: string,
): JsonSchema | null {
if (!isJsonObject(schemaDocument)) {
return null;
}
return dereferenceSchema(
schemaDocument,
resolveSchemaPointer(schemaDocument, pointer),
);
}
export function getStringEnum(
schemaDocument: unknown,
pointer: string,
): string[] {
const schema = getSchemaAtPointer(schemaDocument, pointer);
if (!schema || !Array.isArray(schema.enum)) {
return [];
}
return schema.enum.filter(
(value): value is string => typeof value === "string",
);
}
export function requireStringEnum(
schemaDocument: unknown,
pointer: string,
): string[] {
const values = getStringEnum(schemaDocument, pointer);
if (values.length === 0) {
throw new Error(`Schema is missing a string enum at ${pointer}.`);
}
return values;
}
export function getSchemaProperties(
schemaDocument: unknown,
pointer: string,
): JsonObject | null {
const schema = getSchemaAtPointer(schemaDocument, pointer);
return schema && isJsonObject(schema.properties) ? schema.properties : null;
}
export function getSchemaPattern(
schemaDocument: unknown,
pointer: string,
): string | null {
const schema = getSchemaAtPointer(schemaDocument, pointer);
return schema && typeof schema.pattern === "string" ? schema.pattern : null;
}
export function getSchemaPropertyOrder(
schemaDocument: unknown,
pointer: string,
): string[] {
return Object.keys(getSchemaProperties(schemaDocument, pointer) ?? {});
}