@emeryld/rrroutes-contract 2.1.12 → 2.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/routesV3.core.d.ts +9 -9
- package/dist/docs/schemaIntrospection.d.ts +15 -0
- package/dist/docs/serializer.d.ts +6 -1
- package/dist/index.cjs +398 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +388 -28
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { z,
|
|
1
|
+
import { z, ZodType } from 'zod';
|
|
2
2
|
/** Supported HTTP verbs for the routes DSL. */
|
|
3
3
|
export type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete';
|
|
4
4
|
/** Declarative description of a multipart upload field. */
|
|
@@ -16,13 +16,13 @@ export type NodeCfg = {
|
|
|
16
16
|
/** Per-method configuration merged with inherited node config. */
|
|
17
17
|
export type MethodCfg = {
|
|
18
18
|
/** Zod schema describing the request body. */
|
|
19
|
-
bodySchema?:
|
|
19
|
+
bodySchema?: ZodType;
|
|
20
20
|
/** Zod schema describing the query string. */
|
|
21
|
-
querySchema?:
|
|
21
|
+
querySchema?: ZodType;
|
|
22
22
|
/** Zod schema describing path params (overrides inferred params). */
|
|
23
|
-
paramsSchema?:
|
|
23
|
+
paramsSchema?: ZodType;
|
|
24
24
|
/** Zod schema describing the response payload. */
|
|
25
|
-
outputSchema?:
|
|
25
|
+
outputSchema?: ZodType;
|
|
26
26
|
/** Multipart upload definitions for the route. */
|
|
27
27
|
bodyFiles?: FileField[];
|
|
28
28
|
/** Marks the route as an infinite feed (enables cursor helpers). */
|
|
@@ -102,13 +102,13 @@ export declare function buildCacheKey<L extends AnyLeaf>(args: {
|
|
|
102
102
|
query?: InferQuery<L>;
|
|
103
103
|
}): readonly [HttpMethod, string, {}];
|
|
104
104
|
/** Infer params either from the explicit params schema or from the path literal. */
|
|
105
|
-
export type InferParams<L extends AnyLeaf> = L['cfg']['paramsSchema'] extends
|
|
105
|
+
export type InferParams<L extends AnyLeaf> = L['cfg']['paramsSchema'] extends ZodType ? z.infer<L['cfg']['paramsSchema']> : ExtractParamsFromPath<L['path']>;
|
|
106
106
|
/** Infer query shape from a Zod schema when present. */
|
|
107
|
-
export type InferQuery<L extends AnyLeaf> = L['cfg']['querySchema'] extends
|
|
107
|
+
export type InferQuery<L extends AnyLeaf> = L['cfg']['querySchema'] extends ZodType ? z.infer<L['cfg']['querySchema']> : never;
|
|
108
108
|
/** Infer request body shape from a Zod schema when present. */
|
|
109
|
-
export type InferBody<L extends AnyLeaf> = L['cfg']['bodySchema'] extends
|
|
109
|
+
export type InferBody<L extends AnyLeaf> = L['cfg']['bodySchema'] extends ZodType ? z.infer<L['cfg']['bodySchema']> : never;
|
|
110
110
|
/** Infer handler output shape from a Zod schema. Defaults to unknown. */
|
|
111
|
-
export type InferOutput<L extends AnyLeaf> = L['cfg']['outputSchema'] extends
|
|
111
|
+
export type InferOutput<L extends AnyLeaf> = L['cfg']['outputSchema'] extends ZodType ? z.infer<L['cfg']['outputSchema']> : unknown;
|
|
112
112
|
/** Render a type as if it were a simple object literal. */
|
|
113
113
|
export type Prettify<T> = {
|
|
114
114
|
[K in keyof T]: T[K];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
export type SerializableSchemaNode = {
|
|
3
|
+
kind: string;
|
|
4
|
+
optional?: boolean;
|
|
5
|
+
nullable?: boolean;
|
|
6
|
+
description?: string;
|
|
7
|
+
properties?: Record<string, SerializableSchemaNode>;
|
|
8
|
+
element?: SerializableSchemaNode;
|
|
9
|
+
union?: SerializableSchemaNode[];
|
|
10
|
+
literal?: unknown;
|
|
11
|
+
enumValues?: string[];
|
|
12
|
+
};
|
|
13
|
+
type ZodAny = z.ZodTypeAny;
|
|
14
|
+
export declare function introspectSchema(schema: ZodAny | undefined): SerializableSchemaNode | undefined;
|
|
15
|
+
export {};
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { AnyLeaf, MethodCfg } from "../core/routesV3.core";
|
|
2
|
-
|
|
2
|
+
import { SerializableSchemaNode } from "./schemaIntrospection";
|
|
3
|
+
type SerializableMethodCfg = Pick<MethodCfg, "description" | "summary" | "docsGroup" | "tags" | "deprecated" | "stability" | "feed" | "docsMeta"> & {
|
|
3
4
|
hasBody: boolean;
|
|
4
5
|
hasQuery: boolean;
|
|
5
6
|
hasParams: boolean;
|
|
6
7
|
hasOutput: boolean;
|
|
8
|
+
bodySchema?: SerializableSchemaNode;
|
|
9
|
+
querySchema?: SerializableSchemaNode;
|
|
10
|
+
paramsSchema?: SerializableSchemaNode;
|
|
11
|
+
outputSchema?: SerializableSchemaNode;
|
|
7
12
|
};
|
|
8
13
|
export type SerializableLeaf = {
|
|
9
14
|
method: string;
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -299,6 +309,130 @@ function defineSocketEvents(config, events) {
|
|
|
299
309
|
return { config, events };
|
|
300
310
|
}
|
|
301
311
|
|
|
312
|
+
// src/docs/schemaIntrospection.ts
|
|
313
|
+
var z3 = __toESM(require("zod"), 1);
|
|
314
|
+
function getDef(schema) {
|
|
315
|
+
if (!schema || typeof schema !== "object") return void 0;
|
|
316
|
+
const anySchema = schema;
|
|
317
|
+
return anySchema._zod?.def ?? anySchema._def;
|
|
318
|
+
}
|
|
319
|
+
function getDescription(schema) {
|
|
320
|
+
const anyZ = z3;
|
|
321
|
+
const registry = anyZ.globalRegistry?.get ? anyZ.globalRegistry.get(schema) : void 0;
|
|
322
|
+
if (registry && typeof registry.description === "string") {
|
|
323
|
+
return registry.description;
|
|
324
|
+
}
|
|
325
|
+
const def = getDef(schema);
|
|
326
|
+
if (def && typeof def.description === "string") {
|
|
327
|
+
return def.description;
|
|
328
|
+
}
|
|
329
|
+
return void 0;
|
|
330
|
+
}
|
|
331
|
+
function unwrap(schema) {
|
|
332
|
+
let s = schema;
|
|
333
|
+
let optional = false;
|
|
334
|
+
let nullable = false;
|
|
335
|
+
const ZodEffectsCtor = z3.ZodEffects;
|
|
336
|
+
while (true) {
|
|
337
|
+
if (ZodEffectsCtor && s instanceof ZodEffectsCtor) {
|
|
338
|
+
const def = getDef(s) || {};
|
|
339
|
+
const sourceType = typeof s.sourceType === "function" ? s.sourceType() : def.schema;
|
|
340
|
+
if (!sourceType) break;
|
|
341
|
+
s = sourceType;
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
if (s instanceof z3.ZodOptional) {
|
|
345
|
+
optional = true;
|
|
346
|
+
const def = getDef(s);
|
|
347
|
+
s = def && def.innerType || s;
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
if (s instanceof z3.ZodNullable) {
|
|
351
|
+
nullable = true;
|
|
352
|
+
const def = getDef(s);
|
|
353
|
+
s = def && def.innerType || s;
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
if (s instanceof z3.ZodDefault) {
|
|
357
|
+
const def = getDef(s);
|
|
358
|
+
s = def && def.innerType || s;
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
return { base: s, optional, nullable };
|
|
364
|
+
}
|
|
365
|
+
function introspectSchema(schema) {
|
|
366
|
+
if (!schema) return void 0;
|
|
367
|
+
const { base, optional, nullable } = unwrap(schema);
|
|
368
|
+
const def = getDef(base);
|
|
369
|
+
const node = {
|
|
370
|
+
kind: inferKind(base),
|
|
371
|
+
optional: optional || void 0,
|
|
372
|
+
nullable: nullable || void 0,
|
|
373
|
+
description: getDescription(base)
|
|
374
|
+
};
|
|
375
|
+
if (base instanceof z3.ZodObject) {
|
|
376
|
+
const rawShape = base.shape ?? (def && typeof def.shape === "function" ? def.shape() : def?.shape);
|
|
377
|
+
const shape = typeof rawShape === "function" ? rawShape() : rawShape ?? {};
|
|
378
|
+
const props = {};
|
|
379
|
+
for (const key of Object.keys(shape)) {
|
|
380
|
+
const child = shape[key];
|
|
381
|
+
const childNode = introspectSchema(child);
|
|
382
|
+
if (childNode) props[key] = childNode;
|
|
383
|
+
}
|
|
384
|
+
node.properties = props;
|
|
385
|
+
}
|
|
386
|
+
if (base instanceof z3.ZodArray) {
|
|
387
|
+
const inner = def && def.element || def && def.type || void 0;
|
|
388
|
+
if (inner) {
|
|
389
|
+
node.element = introspectSchema(inner);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
if (base instanceof z3.ZodUnion) {
|
|
393
|
+
const options = def && def.options || [];
|
|
394
|
+
node.union = options.map((opt) => introspectSchema(opt)).filter(Boolean);
|
|
395
|
+
}
|
|
396
|
+
if (base instanceof z3.ZodLiteral) {
|
|
397
|
+
if (def) {
|
|
398
|
+
if (Array.isArray(def.values)) {
|
|
399
|
+
node.literal = def.values.length === 1 ? def.values[0] : def.values.slice();
|
|
400
|
+
} else {
|
|
401
|
+
node.literal = def.value;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
if (base instanceof z3.ZodEnum) {
|
|
406
|
+
if (def) {
|
|
407
|
+
if (Array.isArray(def.values)) {
|
|
408
|
+
node.enumValues = def.values.slice();
|
|
409
|
+
} else if (def.entries && typeof def.entries === "object") {
|
|
410
|
+
node.enumValues = Object.values(def.entries).map(
|
|
411
|
+
(v) => String(v)
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return node;
|
|
417
|
+
}
|
|
418
|
+
function inferKind(schema) {
|
|
419
|
+
if (schema instanceof z3.ZodString) return "string";
|
|
420
|
+
if (schema instanceof z3.ZodNumber) return "number";
|
|
421
|
+
if (schema instanceof z3.ZodBoolean) return "boolean";
|
|
422
|
+
if (schema instanceof z3.ZodBigInt) return "bigint";
|
|
423
|
+
if (schema instanceof z3.ZodDate) return "date";
|
|
424
|
+
if (schema instanceof z3.ZodArray) return "array";
|
|
425
|
+
if (schema instanceof z3.ZodObject) return "object";
|
|
426
|
+
if (schema instanceof z3.ZodUnion) return "union";
|
|
427
|
+
if (schema instanceof z3.ZodLiteral) return "literal";
|
|
428
|
+
if (schema instanceof z3.ZodEnum) return "enum";
|
|
429
|
+
if (schema instanceof z3.ZodRecord) return "record";
|
|
430
|
+
if (schema instanceof z3.ZodTuple) return "tuple";
|
|
431
|
+
if (schema instanceof z3.ZodUnknown) return "unknown";
|
|
432
|
+
if (schema instanceof z3.ZodAny) return "any";
|
|
433
|
+
return "unknown";
|
|
434
|
+
}
|
|
435
|
+
|
|
302
436
|
// src/docs/serializer.ts
|
|
303
437
|
function serializeLeaf(leaf) {
|
|
304
438
|
const cfg = leaf.cfg;
|
|
@@ -319,7 +453,11 @@ function serializeLeaf(leaf) {
|
|
|
319
453
|
hasBody: !!cfg.bodySchema || !!cfg.bodyFiles?.length,
|
|
320
454
|
hasQuery: !!cfg.querySchema,
|
|
321
455
|
hasParams: !!cfg.paramsSchema,
|
|
322
|
-
hasOutput: !!cfg.outputSchema
|
|
456
|
+
hasOutput: !!cfg.outputSchema,
|
|
457
|
+
bodySchema: introspectSchema(cfg.bodySchema),
|
|
458
|
+
querySchema: introspectSchema(cfg.querySchema),
|
|
459
|
+
paramsSchema: introspectSchema(cfg.paramsSchema),
|
|
460
|
+
outputSchema: introspectSchema(cfg.outputSchema)
|
|
323
461
|
}
|
|
324
462
|
};
|
|
325
463
|
}
|
|
@@ -718,7 +856,104 @@ var styles = `
|
|
|
718
856
|
border-radius: 10px;
|
|
719
857
|
border: 1px dashed rgba(148, 163, 184, 0.5);
|
|
720
858
|
background: rgba(15, 23, 42, 0.9);
|
|
721
|
-
}
|
|
859
|
+
}
|
|
860
|
+
.schema-section {
|
|
861
|
+
margin-top: 8px;
|
|
862
|
+
font-size: 11px;
|
|
863
|
+
border-top: 1px dashed rgba(148, 163, 184, 0.5);
|
|
864
|
+
padding-top: 6px;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
.schema-details {
|
|
868
|
+
margin-top: 6px;
|
|
869
|
+
border-radius: 10px;
|
|
870
|
+
border: 1px solid rgba(148, 163, 184, 0.4);
|
|
871
|
+
background: rgba(15, 23, 42, 0.95);
|
|
872
|
+
padding: 8px 10px;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
.schema-details summary {
|
|
876
|
+
cursor: pointer;
|
|
877
|
+
list-style: none;
|
|
878
|
+
font-size: 11px;
|
|
879
|
+
color: var(--text-muted);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
.schema-details summary::-webkit-details-marker {
|
|
883
|
+
display: none;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
.schema-details summary::before {
|
|
887
|
+
content: "\u25B8";
|
|
888
|
+
display: inline-block;
|
|
889
|
+
margin-right: 6px;
|
|
890
|
+
font-size: 9px;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
.schema-details[open] summary::before {
|
|
894
|
+
content: "\u25BE";
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
.schema-table {
|
|
898
|
+
width: 100%;
|
|
899
|
+
border-collapse: collapse;
|
|
900
|
+
margin-top: 6px;
|
|
901
|
+
font-size: 11px;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
.schema-table th,
|
|
905
|
+
.schema-table td {
|
|
906
|
+
padding: 3px 4px;
|
|
907
|
+
border-bottom: 1px solid rgba(30, 64, 175, 0.35);
|
|
908
|
+
text-align: left;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
.schema-table th {
|
|
912
|
+
font-weight: 500;
|
|
913
|
+
color: var(--text-muted);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
.schema-field-name {
|
|
917
|
+
font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco,
|
|
918
|
+
Consolas, "Liberation Mono", "Courier New", monospace;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
.schema-type {
|
|
922
|
+
color: var(--accent);
|
|
923
|
+
font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco,
|
|
924
|
+
Consolas, "Liberation Mono", "Courier New", monospace;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
.schema-required {
|
|
928
|
+
font-size: 10px;
|
|
929
|
+
text-transform: uppercase;
|
|
930
|
+
letter-spacing: 0.12em;
|
|
931
|
+
padding: 1px 5px;
|
|
932
|
+
border-radius: 999px;
|
|
933
|
+
border: 1px solid rgba(52, 211, 153, 0.7);
|
|
934
|
+
color: #bbf7d0;
|
|
935
|
+
background: rgba(22, 163, 74, 0.1);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
.schema-optional {
|
|
939
|
+
font-size: 10px;
|
|
940
|
+
text-transform: uppercase;
|
|
941
|
+
letter-spacing: 0.12em;
|
|
942
|
+
padding: 1px 5px;
|
|
943
|
+
border-radius: 999px;
|
|
944
|
+
border: 1px solid rgba(148, 163, 184, 0.6);
|
|
945
|
+
color: var(--text-muted);
|
|
946
|
+
background: rgba(15, 23, 42, 0.95);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
.schema-meta {
|
|
950
|
+
margin-top: 6px;
|
|
951
|
+
font-size: 10px;
|
|
952
|
+
color: var(--text-muted);
|
|
953
|
+
white-space: pre-wrap;
|
|
954
|
+
word-break: break-word;
|
|
955
|
+
}
|
|
956
|
+
`;
|
|
722
957
|
function renderLeafDocsHTML(leaves, options = {}) {
|
|
723
958
|
const docsLeaves = leaves.map(serializeLeaf);
|
|
724
959
|
const leafJson = JSON.stringify(docsLeaves).replace(/</g, "\\u003c");
|
|
@@ -790,6 +1025,99 @@ ${styles}
|
|
|
790
1025
|
<script id="leaf-data" type="application/json"${nonceAttr}>${leafJson}</script>
|
|
791
1026
|
<script${nonceAttr}>
|
|
792
1027
|
(function () {
|
|
1028
|
+
|
|
1029
|
+
function typeLabel(node) {
|
|
1030
|
+
if (!node) return "unknown";
|
|
1031
|
+
var base = node.kind || "unknown";
|
|
1032
|
+
if (node.literal !== undefined) {
|
|
1033
|
+
return JSON.stringify(node.literal);
|
|
1034
|
+
}
|
|
1035
|
+
if (node.enumValues && node.enumValues.length) {
|
|
1036
|
+
return "enum[" + node.enumValues.join(" | ") + "]";
|
|
1037
|
+
}
|
|
1038
|
+
if (node.kind === "array" && node.element) {
|
|
1039
|
+
return "Array<" + typeLabel(node.element) + ">";
|
|
1040
|
+
}
|
|
1041
|
+
if (node.kind === "union" && node.union && node.union.length) {
|
|
1042
|
+
return node.union.map(typeLabel).join(" | ");
|
|
1043
|
+
}
|
|
1044
|
+
return base;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
function renderObjectRows(node, prefix) {
|
|
1048
|
+
if (!node || node.kind !== "object" || !node.properties) return "";
|
|
1049
|
+
var rows = "";
|
|
1050
|
+
Object.keys(node.properties).forEach(function (key) {
|
|
1051
|
+
var child = node.properties[key];
|
|
1052
|
+
var fullName = prefix ? prefix + "." + key : key;
|
|
1053
|
+
var required = !child.optional;
|
|
1054
|
+
rows +=
|
|
1055
|
+
"<tr>" +
|
|
1056
|
+
'<td class="schema-field-name">' +
|
|
1057
|
+
escapeHtml(fullName) +
|
|
1058
|
+
"</td>" +
|
|
1059
|
+
'<td class="schema-type">' +
|
|
1060
|
+
escapeHtml(typeLabel(child)) +
|
|
1061
|
+
"</td>" +
|
|
1062
|
+
"<td>" +
|
|
1063
|
+
(required
|
|
1064
|
+
? '<span class="schema-required">required</span>'
|
|
1065
|
+
: '<span class="schema-optional">optional</span>') +
|
|
1066
|
+
"</td>" +
|
|
1067
|
+
"<td>" +
|
|
1068
|
+
(child.description
|
|
1069
|
+
? escapeHtml(String(child.description))
|
|
1070
|
+
: "") +
|
|
1071
|
+
"</td>" +
|
|
1072
|
+
"</tr>";
|
|
1073
|
+
|
|
1074
|
+
// Recursively show nested objects, arrays-of-objects, etc.
|
|
1075
|
+
if (child.kind === "object") {
|
|
1076
|
+
rows += renderObjectRows(child, fullName);
|
|
1077
|
+
} else if (child.kind === "array" && child.element && child.element.kind === "object") {
|
|
1078
|
+
rows += renderObjectRows(
|
|
1079
|
+
child.element,
|
|
1080
|
+
fullName + "[]."
|
|
1081
|
+
);
|
|
1082
|
+
}
|
|
1083
|
+
});
|
|
1084
|
+
return rows;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
function renderSchemaSection(label, node) {
|
|
1088
|
+
if (!node) return "";
|
|
1089
|
+
// For non-object schemas, just show a one-line type.
|
|
1090
|
+
var isObject = node.kind === "object" && node.properties;
|
|
1091
|
+
var content = "";
|
|
1092
|
+
|
|
1093
|
+
if (isObject) {
|
|
1094
|
+
var rows = renderObjectRows(node, "");
|
|
1095
|
+
content =
|
|
1096
|
+
'<table class="schema-table">' +
|
|
1097
|
+
"<thead><tr>" +
|
|
1098
|
+
"<th>Field</th><th>Type</th><th></th><th>Description</th>" +
|
|
1099
|
+
"</tr></thead>" +
|
|
1100
|
+
"<tbody>" +
|
|
1101
|
+
rows +
|
|
1102
|
+
"</tbody></table>";
|
|
1103
|
+
} else {
|
|
1104
|
+
content =
|
|
1105
|
+
'<div class="schema-meta">' +
|
|
1106
|
+
"<strong>Type:</strong> " +
|
|
1107
|
+
escapeHtml(typeLabel(node)) +
|
|
1108
|
+
"</div>";
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
return (
|
|
1112
|
+
'<div class="schema-section">' +
|
|
1113
|
+
"<div><strong>" +
|
|
1114
|
+
escapeHtml(label) +
|
|
1115
|
+
"</strong></div>" +
|
|
1116
|
+
content +
|
|
1117
|
+
"</div>"
|
|
1118
|
+
);
|
|
1119
|
+
}
|
|
1120
|
+
|
|
793
1121
|
function escapeHtml(str) {
|
|
794
1122
|
return String(str)
|
|
795
1123
|
.replace(/&/g, '&')
|
|
@@ -885,40 +1213,40 @@ ${styles}
|
|
|
885
1213
|
}
|
|
886
1214
|
|
|
887
1215
|
function routeToHTML(route) {
|
|
888
|
-
var method = String(route.method ||
|
|
889
|
-
var methodClass =
|
|
1216
|
+
var method = String(route.method || "").toUpperCase();
|
|
1217
|
+
var methodClass = "method-" + String(route.method || "").toLowerCase();
|
|
890
1218
|
|
|
891
1219
|
var cfg = route.cfg || {};
|
|
892
|
-
var group = cfg.docsGroup ||
|
|
1220
|
+
var group = cfg.docsGroup || "Ungrouped";
|
|
893
1221
|
|
|
894
|
-
var summary = cfg.summary || cfg.description ||
|
|
1222
|
+
var summary = cfg.summary || cfg.description || "";
|
|
895
1223
|
var description =
|
|
896
1224
|
cfg.description && cfg.summary !== cfg.description
|
|
897
1225
|
? cfg.description
|
|
898
|
-
:
|
|
1226
|
+
: "";
|
|
899
1227
|
|
|
900
1228
|
var tags = Array.isArray(cfg.tags) ? cfg.tags : [];
|
|
901
1229
|
var tagHtml = tags
|
|
902
1230
|
.map(function (tag) {
|
|
903
1231
|
var t = String(tag);
|
|
904
|
-
var extraClass = t ===
|
|
905
|
-
return '<span class="tag' + extraClass + '">' + escapeHtml(t) +
|
|
1232
|
+
var extraClass = t === "not-implemented" ? " tag-not-impl" : "";
|
|
1233
|
+
return '<span class="tag' + extraClass + '">' + escapeHtml(t) + "</span>";
|
|
906
1234
|
})
|
|
907
|
-
.join(
|
|
1235
|
+
.join("");
|
|
908
1236
|
|
|
909
|
-
var metaBadges =
|
|
1237
|
+
var metaBadges = "";
|
|
910
1238
|
if (cfg.feed) {
|
|
911
1239
|
metaBadges += '<span class="badge badge-feed">Feed</span>';
|
|
912
1240
|
}
|
|
913
|
-
if (cfg.deprecated || cfg.stability ===
|
|
1241
|
+
if (cfg.deprecated || cfg.stability === "deprecated") {
|
|
914
1242
|
metaBadges += '<span class="badge badge-deprecated">Deprecated</span>';
|
|
915
|
-
} else if (cfg.stability && cfg.stability !==
|
|
1243
|
+
} else if (cfg.stability && cfg.stability !== "stable") {
|
|
916
1244
|
metaBadges +=
|
|
917
1245
|
'<span class="badge badge-' +
|
|
918
1246
|
escapeHtml(cfg.stability) +
|
|
919
1247
|
'">' +
|
|
920
1248
|
escapeHtml(String(cfg.stability)) +
|
|
921
|
-
|
|
1249
|
+
"</span>";
|
|
922
1250
|
}
|
|
923
1251
|
|
|
924
1252
|
var schemaPills = [];
|
|
@@ -929,8 +1257,48 @@ ${styles}
|
|
|
929
1257
|
|
|
930
1258
|
var schemaHtml =
|
|
931
1259
|
schemaPills.length > 0
|
|
932
|
-
? '<div class="schema-row">' + schemaPills.join(
|
|
933
|
-
:
|
|
1260
|
+
? '<div class="schema-row">' + schemaPills.join("") + "</div>"
|
|
1261
|
+
: "";
|
|
1262
|
+
|
|
1263
|
+
// NEW: full expandable details including field-level schemas + docsMeta
|
|
1264
|
+
var hasDetailedSchemas =
|
|
1265
|
+
cfg.bodySchema || cfg.querySchema || cfg.paramsSchema || cfg.outputSchema;
|
|
1266
|
+
var detailsInner = "";
|
|
1267
|
+
|
|
1268
|
+
if (cfg.bodySchema) {
|
|
1269
|
+
detailsInner += renderSchemaSection("Request body", cfg.bodySchema);
|
|
1270
|
+
}
|
|
1271
|
+
if (cfg.querySchema) {
|
|
1272
|
+
detailsInner += renderSchemaSection("Query params", cfg.querySchema);
|
|
1273
|
+
}
|
|
1274
|
+
if (cfg.paramsSchema) {
|
|
1275
|
+
detailsInner += renderSchemaSection("Path params", cfg.paramsSchema);
|
|
1276
|
+
}
|
|
1277
|
+
if (cfg.outputSchema) {
|
|
1278
|
+
detailsInner += renderSchemaSection("Response", cfg.outputSchema);
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
if (cfg.docsMeta) {
|
|
1282
|
+
try {
|
|
1283
|
+
var metaJson = JSON.stringify(cfg.docsMeta, null, 2);
|
|
1284
|
+
detailsInner +=
|
|
1285
|
+
'<div class="schema-section">' +
|
|
1286
|
+
"<div><strong>Metadata</strong></div>" +
|
|
1287
|
+
'<div class="schema-meta">' +
|
|
1288
|
+
escapeHtml(metaJson) +
|
|
1289
|
+
"</div>" +
|
|
1290
|
+
"</div>";
|
|
1291
|
+
} catch (e) {}
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
var detailsHtml = "";
|
|
1295
|
+
if (hasDetailedSchemas || cfg.docsMeta) {
|
|
1296
|
+
detailsHtml =
|
|
1297
|
+
'<details class="schema-details">' +
|
|
1298
|
+
"<summary>Inspect schemas & metadata</summary>" +
|
|
1299
|
+
detailsInner +
|
|
1300
|
+
"</details>";
|
|
1301
|
+
}
|
|
934
1302
|
|
|
935
1303
|
return (
|
|
936
1304
|
'<article class="route-card">' +
|
|
@@ -939,31 +1307,33 @@ ${styles}
|
|
|
939
1307
|
methodClass +
|
|
940
1308
|
'">' +
|
|
941
1309
|
method +
|
|
942
|
-
|
|
1310
|
+
"</span>" +
|
|
943
1311
|
'<code class="route-path">' +
|
|
944
|
-
escapeHtml(route.path ||
|
|
945
|
-
|
|
1312
|
+
escapeHtml(route.path || "") +
|
|
1313
|
+
"</code>" +
|
|
946
1314
|
(group
|
|
947
|
-
? '<span class="group-label">' + escapeHtml(String(group)) +
|
|
948
|
-
:
|
|
949
|
-
|
|
1315
|
+
? '<span class="group-label">' + escapeHtml(String(group)) + "</span>"
|
|
1316
|
+
: "") +
|
|
1317
|
+
"</header>" +
|
|
950
1318
|
'<div class="route-tags">' +
|
|
951
1319
|
tagHtml +
|
|
952
1320
|
metaBadges +
|
|
953
|
-
|
|
1321
|
+
"</div>" +
|
|
954
1322
|
(summary
|
|
955
|
-
? '<p class="route-summary">' + escapeHtml(String(summary)) +
|
|
956
|
-
:
|
|
1323
|
+
? '<p class="route-summary">' + escapeHtml(String(summary)) + "</p>"
|
|
1324
|
+
: "") +
|
|
957
1325
|
(description
|
|
958
1326
|
? '<p class="route-description">' +
|
|
959
1327
|
escapeHtml(String(description)) +
|
|
960
|
-
|
|
961
|
-
:
|
|
1328
|
+
"</p>"
|
|
1329
|
+
: "") +
|
|
962
1330
|
schemaHtml +
|
|
963
|
-
|
|
1331
|
+
(detailsHtml ? detailsHtml : "") +
|
|
1332
|
+
"</article>"
|
|
964
1333
|
);
|
|
965
1334
|
}
|
|
966
1335
|
|
|
1336
|
+
|
|
967
1337
|
function applyFilters() {
|
|
968
1338
|
var query = searchInput.value.toLowerCase().trim();
|
|
969
1339
|
|