@contractkit/explorer-ui 0.10.0
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/README.md +128 -0
- package/dist/assets/style.css +496 -0
- package/dist/constraints.d.ts +4 -0
- package/dist/constraints.d.ts.map +1 -0
- package/dist/html.d.ts +28 -0
- package/dist/html.d.ts.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +687 -0
- package/dist/index.js.map +1 -0
- package/dist/markdown.d.ts +10 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/render-item.d.ts +40 -0
- package/dist/render-item.d.ts.map +1 -0
- package/dist/render-model.d.ts +9 -0
- package/dist/render-model.d.ts.map +1 -0
- package/dist/render-operation.d.ts +17 -0
- package/dist/render-operation.d.ts.map +1 -0
- package/dist/render-tryit.d.ts +8 -0
- package/dist/render-tryit.d.ts.map +1 -0
- package/dist/render-type.d.ts +11 -0
- package/dist/render-type.d.ts.map +1 -0
- package/dist/render.d.ts +7 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/types.d.ts +65 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +48 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,687 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
4
|
+
// src/html.ts
|
|
5
|
+
var RAW = /* @__PURE__ */ Symbol("raw");
|
|
6
|
+
function raw(value) {
|
|
7
|
+
return {
|
|
8
|
+
[RAW]: true,
|
|
9
|
+
value
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
__name(raw, "raw");
|
|
13
|
+
function isRaw(value) {
|
|
14
|
+
return typeof value === "object" && value !== null && value[RAW] === true;
|
|
15
|
+
}
|
|
16
|
+
__name(isRaw, "isRaw");
|
|
17
|
+
function escapeHtml(value) {
|
|
18
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
19
|
+
}
|
|
20
|
+
__name(escapeHtml, "escapeHtml");
|
|
21
|
+
function renderValue(value) {
|
|
22
|
+
if (value === null || value === void 0 || value === false) return "";
|
|
23
|
+
if (isRaw(value)) return value.value;
|
|
24
|
+
if (Array.isArray(value)) return value.map(renderValue).join("");
|
|
25
|
+
return escapeHtml(String(value));
|
|
26
|
+
}
|
|
27
|
+
__name(renderValue, "renderValue");
|
|
28
|
+
function html(strings, ...values) {
|
|
29
|
+
let out = strings[0] ?? "";
|
|
30
|
+
for (let i = 0; i < values.length; i++) {
|
|
31
|
+
out += renderValue(values[i]) + (strings[i + 1] ?? "");
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
__name(html, "html");
|
|
36
|
+
function slug(value) {
|
|
37
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
38
|
+
}
|
|
39
|
+
__name(slug, "slug");
|
|
40
|
+
|
|
41
|
+
// src/markdown.ts
|
|
42
|
+
function renderMarkdown(input) {
|
|
43
|
+
if (!input) return "";
|
|
44
|
+
const lines = input.replace(/\r\n/g, "\n").split("\n");
|
|
45
|
+
const out = [];
|
|
46
|
+
let i = 0;
|
|
47
|
+
while (i < lines.length) {
|
|
48
|
+
const line = lines[i] ?? "";
|
|
49
|
+
const fence = /^```(\w*)\s*$/.exec(line);
|
|
50
|
+
if (fence) {
|
|
51
|
+
const lang = fence[1] ?? "";
|
|
52
|
+
const buf2 = [];
|
|
53
|
+
i++;
|
|
54
|
+
while (i < lines.length && !/^```\s*$/.test(lines[i] ?? "")) {
|
|
55
|
+
buf2.push(lines[i] ?? "");
|
|
56
|
+
i++;
|
|
57
|
+
}
|
|
58
|
+
i++;
|
|
59
|
+
const langAttr = lang ? ` data-lang="${escapeHtml(lang)}"` : "";
|
|
60
|
+
out.push(`<pre class="ce-code"${langAttr}><code>${escapeHtml(buf2.join("\n"))}</code></pre>`);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const heading = /^(#{1,6})\s+(.+)$/.exec(line);
|
|
64
|
+
if (heading) {
|
|
65
|
+
const level = heading[1].length;
|
|
66
|
+
out.push(`<h${level}>${renderInline(heading[2])}</h${level}>`);
|
|
67
|
+
i++;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (/^\s*[-*]\s+/.test(line)) {
|
|
71
|
+
const items = [];
|
|
72
|
+
while (i < lines.length && /^\s*[-*]\s+/.test(lines[i] ?? "")) {
|
|
73
|
+
items.push(renderInline((lines[i] ?? "").replace(/^\s*[-*]\s+/, "")));
|
|
74
|
+
i++;
|
|
75
|
+
}
|
|
76
|
+
out.push(`<ul>${items.map((t) => `<li>${t}</li>`).join("")}</ul>`);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (/^\s*\d+\.\s+/.test(line)) {
|
|
80
|
+
const items = [];
|
|
81
|
+
while (i < lines.length && /^\s*\d+\.\s+/.test(lines[i] ?? "")) {
|
|
82
|
+
items.push(renderInline((lines[i] ?? "").replace(/^\s*\d+\.\s+/, "")));
|
|
83
|
+
i++;
|
|
84
|
+
}
|
|
85
|
+
out.push(`<ol>${items.map((t) => `<li>${t}</li>`).join("")}</ol>`);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (line.trim() === "") {
|
|
89
|
+
i++;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const buf = [
|
|
93
|
+
line
|
|
94
|
+
];
|
|
95
|
+
i++;
|
|
96
|
+
while (i < lines.length) {
|
|
97
|
+
const next = lines[i] ?? "";
|
|
98
|
+
if (next.trim() === "" || /^```/.test(next) || /^#{1,6}\s/.test(next) || /^\s*[-*]\s/.test(next) || /^\s*\d+\.\s/.test(next)) break;
|
|
99
|
+
buf.push(next);
|
|
100
|
+
i++;
|
|
101
|
+
}
|
|
102
|
+
out.push(`<p>${renderInline(buf.join(" "))}</p>`);
|
|
103
|
+
}
|
|
104
|
+
return out.join("\n");
|
|
105
|
+
}
|
|
106
|
+
__name(renderMarkdown, "renderMarkdown");
|
|
107
|
+
function renderInline(text) {
|
|
108
|
+
let s = escapeHtml(text);
|
|
109
|
+
s = s.replace(/`([^`]+)`/g, (_m, code) => `<code>${code}</code>`);
|
|
110
|
+
s = s.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
|
|
111
|
+
s = s.replace(/(^|[^*])\*([^*\s][^*]*?)\*(?!\*)/g, (_m, before, body) => `${before}<em>${body}</em>`);
|
|
112
|
+
s = s.replace(/\[([^\]]+)\]\((https?:\/\/[^)\s]+)\)/g, (_m, label, url) => {
|
|
113
|
+
return `<a href="${url}" rel="noopener noreferrer">${label}</a>`;
|
|
114
|
+
});
|
|
115
|
+
return s;
|
|
116
|
+
}
|
|
117
|
+
__name(renderInline, "renderInline");
|
|
118
|
+
|
|
119
|
+
// src/render-tryit.ts
|
|
120
|
+
function renderTryIt(op, baseUrl) {
|
|
121
|
+
const id = operationAnchor(op);
|
|
122
|
+
const pathParams = extractParams(op.routeParams);
|
|
123
|
+
const queryParams = extractParams(op.op.query);
|
|
124
|
+
const headerParams = extractParams(op.op.headers);
|
|
125
|
+
const hasJsonBody = !!op.op.request?.bodies.some((b) => b.contentType === "application/json" || b.contentType.endsWith("+json"));
|
|
126
|
+
return `<details class="ce-tryit" data-tryit-id="${escapeHtml(id)}">
|
|
127
|
+
<summary>Try it</summary>
|
|
128
|
+
<form class="ce-tryit-form" onsubmit="return false;">
|
|
129
|
+
<label class="ce-tryit-row">
|
|
130
|
+
<span class="ce-tryit-label">Base URL</span>
|
|
131
|
+
<input type="text" name="baseUrl" value="${escapeHtml(baseUrl)}" placeholder="https://api.example.com" />
|
|
132
|
+
</label>
|
|
133
|
+
${renderInputSection("Path params", "path", pathParams)}
|
|
134
|
+
${renderInputSection("Query", "query", queryParams)}
|
|
135
|
+
${renderInputSection("Headers", "header", headerParams)}
|
|
136
|
+
${hasJsonBody ? `<label class="ce-tryit-row ce-tryit-col">
|
|
137
|
+
<span class="ce-tryit-label">Body (JSON)</span>
|
|
138
|
+
<textarea name="body" rows="6" placeholder="{}"></textarea>
|
|
139
|
+
</label>` : ""}
|
|
140
|
+
<div class="ce-tryit-actions">
|
|
141
|
+
<button type="button" class="ce-tryit-send" data-tryit-action="send" data-tryit-target="${escapeHtml(id)}">
|
|
142
|
+
Send ${escapeHtml(op.method.toUpperCase())} ${escapeHtml(op.routePath)}
|
|
143
|
+
</button>
|
|
144
|
+
</div>
|
|
145
|
+
<div class="ce-tryit-response" data-tryit-response="${escapeHtml(id)}"></div>
|
|
146
|
+
</form>
|
|
147
|
+
</details>`;
|
|
148
|
+
}
|
|
149
|
+
__name(renderTryIt, "renderTryIt");
|
|
150
|
+
function extractParams(source) {
|
|
151
|
+
if (!source || source.kind !== "params") return [];
|
|
152
|
+
return source.nodes;
|
|
153
|
+
}
|
|
154
|
+
__name(extractParams, "extractParams");
|
|
155
|
+
function renderInputSection(label, scope, params) {
|
|
156
|
+
if (params.length === 0) return "";
|
|
157
|
+
const rows = params.map((p) => `<label class="ce-tryit-row">
|
|
158
|
+
<span class="ce-tryit-label"><code>${escapeHtml(p.name)}</code>${p.optional ? "" : " *"}</span>
|
|
159
|
+
<input type="text"
|
|
160
|
+
name="${scope}.${escapeHtml(p.name)}"
|
|
161
|
+
placeholder="${escapeHtml(typeHint(p))}"
|
|
162
|
+
${p.default !== void 0 ? `value="${escapeHtml(String(p.default))}"` : ""} />
|
|
163
|
+
</label>`).join("");
|
|
164
|
+
return `<fieldset class="ce-tryit-section"><legend>${escapeHtml(label)}</legend>${rows}</fieldset>`;
|
|
165
|
+
}
|
|
166
|
+
__name(renderInputSection, "renderInputSection");
|
|
167
|
+
function typeHint(p) {
|
|
168
|
+
if (p.type.kind === "scalar") return p.type.name;
|
|
169
|
+
return p.type.kind;
|
|
170
|
+
}
|
|
171
|
+
__name(typeHint, "typeHint");
|
|
172
|
+
|
|
173
|
+
// src/constraints.ts
|
|
174
|
+
function constraintSummary(scalar) {
|
|
175
|
+
const parts = [];
|
|
176
|
+
if (scalar.min !== void 0) parts.push(`min=${scalar.min}`);
|
|
177
|
+
if (scalar.max !== void 0) parts.push(`max=${scalar.max}`);
|
|
178
|
+
if (scalar.len !== void 0) parts.push(`len=${scalar.len}`);
|
|
179
|
+
if (scalar.regex !== void 0) parts.push(`regex=/${scalar.regex}/`);
|
|
180
|
+
if (scalar.format !== void 0) parts.push(`format=${scalar.format}`);
|
|
181
|
+
return parts.length > 0 ? `(${parts.join(", ")})` : "";
|
|
182
|
+
}
|
|
183
|
+
__name(constraintSummary, "constraintSummary");
|
|
184
|
+
|
|
185
|
+
// src/render-model.ts
|
|
186
|
+
function modelAnchor(name) {
|
|
187
|
+
return `model-${encodeURIComponent(name)}`;
|
|
188
|
+
}
|
|
189
|
+
__name(modelAnchor, "modelAnchor");
|
|
190
|
+
function renderModel({ filePath, model }, ctx = {}) {
|
|
191
|
+
const badges = [];
|
|
192
|
+
if (model.deprecated) badges.push(badge("deprecated", "deprecated"));
|
|
193
|
+
if (model.mode) badges.push(badge(`mode=${model.mode}`, "mode"));
|
|
194
|
+
if (model.inputCase) badges.push(badge(`format(input=${model.inputCase})`, "format"));
|
|
195
|
+
if (model.outputCase) badges.push(badge(`format(output=${model.outputCase})`, "format"));
|
|
196
|
+
const fieldCtx = {
|
|
197
|
+
...ctx,
|
|
198
|
+
visited: /* @__PURE__ */ new Set([
|
|
199
|
+
...ctx.visited ?? [],
|
|
200
|
+
model.name
|
|
201
|
+
])
|
|
202
|
+
};
|
|
203
|
+
const inheritance = model.bases && model.bases.length > 0 ? `<p class="ce-extends">extends ${model.bases.map((b) => `<a class="ce-ref" href="#model-${encodeURIComponent(b)}" data-open-model="${escapeHtml(b)}">${escapeHtml(b)}</a>`).join(", ")}</p>` : "";
|
|
204
|
+
const description = model.description ? `<div class="ce-description ce-markdown">${renderMarkdown(model.description)}</div>` : "";
|
|
205
|
+
const body = model.type ? `<div class="ce-type-alias">= ${renderType(model.type, fieldCtx)}</div>` : renderFieldRows(model.fields, fieldCtx);
|
|
206
|
+
return html`<section id="${raw(modelAnchor(model.name))}" class="ce-card ce-model-card">
|
|
207
|
+
<header class="ce-card-header">
|
|
208
|
+
<h2>
|
|
209
|
+
${model.name}
|
|
210
|
+
${raw(badges.join(""))}
|
|
211
|
+
<button
|
|
212
|
+
class="ce-jump"
|
|
213
|
+
data-jump-file="${filePath}"
|
|
214
|
+
data-jump-line="${model.loc.line}"
|
|
215
|
+
title="Open in editor"
|
|
216
|
+
type="button"
|
|
217
|
+
>
|
|
218
|
+
↗
|
|
219
|
+
</button>
|
|
220
|
+
</h2>
|
|
221
|
+
</header>
|
|
222
|
+
${raw(inheritance)}
|
|
223
|
+
${raw(description)}
|
|
224
|
+
${raw(body)}
|
|
225
|
+
</section>`;
|
|
226
|
+
}
|
|
227
|
+
__name(renderModel, "renderModel");
|
|
228
|
+
function renderFieldRows(fields, ctx = {}) {
|
|
229
|
+
if (fields.length === 0) return `<p class="ce-empty">No fields.</p>`;
|
|
230
|
+
const rows = fields.map((f) => {
|
|
231
|
+
const modifiers = [];
|
|
232
|
+
if (f.optional) modifiers.push("optional");
|
|
233
|
+
if (f.nullable) modifiers.push("nullable");
|
|
234
|
+
if (f.visibility === "readonly") modifiers.push("readonly");
|
|
235
|
+
if (f.visibility === "writeonly") modifiers.push("writeonly");
|
|
236
|
+
if (f.deprecated) modifiers.push("deprecated");
|
|
237
|
+
if (f.override) modifiers.push("override");
|
|
238
|
+
const modifierHtml = modifiers.map((m) => badge(m, m)).join("");
|
|
239
|
+
const defaultHtml = f.default !== void 0 ? html`<code class="ce-default">= ${String(f.default)}</code>` : "";
|
|
240
|
+
const descHtml = f.description ? `<div class="ce-field-desc ce-markdown">${renderMarkdown(f.description)}</div>` : "";
|
|
241
|
+
return `<tr>
|
|
242
|
+
<td class="ce-field-name"><code>${escapeHtml(f.name)}</code>${modifierHtml}</td>
|
|
243
|
+
<td class="ce-field-type">${renderType(f.type, ctx)}${defaultHtml}${descHtml}</td>
|
|
244
|
+
</tr>`;
|
|
245
|
+
});
|
|
246
|
+
return `<table class="ce-fields"><tbody>${rows.join("")}</tbody></table>`;
|
|
247
|
+
}
|
|
248
|
+
__name(renderFieldRows, "renderFieldRows");
|
|
249
|
+
function badge(label, kind) {
|
|
250
|
+
return `<span class="ce-badge ce-badge-${escapeHtml(kind)}">${escapeHtml(label)}</span>`;
|
|
251
|
+
}
|
|
252
|
+
__name(badge, "badge");
|
|
253
|
+
|
|
254
|
+
// src/render-type.ts
|
|
255
|
+
var DEFAULT_MAX_DEPTH = 4;
|
|
256
|
+
function renderType(type, ctx = {}) {
|
|
257
|
+
switch (type.kind) {
|
|
258
|
+
case "scalar": {
|
|
259
|
+
const constraint = constraintSummary(type);
|
|
260
|
+
const constraintHtml = constraint ? `<span class="ce-type-constraint">${escapeHtml(constraint)}</span>` : "";
|
|
261
|
+
return `<span class="ce-type-scalar">${escapeHtml(type.name)}${constraintHtml}</span>`;
|
|
262
|
+
}
|
|
263
|
+
case "enum":
|
|
264
|
+
return `<span class="ce-type-enum">enum(${type.values.map(escapeHtml).join(", ")})</span>`;
|
|
265
|
+
case "literal":
|
|
266
|
+
return `<span class="ce-type-literal">${escapeHtml(typeof type.value === "string" ? `"${type.value}"` : String(type.value))}</span>`;
|
|
267
|
+
case "ref":
|
|
268
|
+
return renderRef(type.name, ctx);
|
|
269
|
+
case "array":
|
|
270
|
+
return `${tok("Array<")}${renderType(type.item, ctx)}${tok(">")}`;
|
|
271
|
+
case "tuple":
|
|
272
|
+
return `${tok("[")}${type.items.map((t) => renderType(t, ctx)).join(tok(", "))}${tok("]")}`;
|
|
273
|
+
case "record":
|
|
274
|
+
return `${tok("Record<")}${renderType(type.key, ctx)}${tok(", ")}${renderType(type.value, ctx)}${tok(">")}`;
|
|
275
|
+
case "union":
|
|
276
|
+
return type.members.map((m) => renderType(m, ctx)).join(tok(" | "));
|
|
277
|
+
case "discriminatedUnion":
|
|
278
|
+
return `${tok(`Union by ${escapeHtml(type.discriminator)}:`)} ` + type.members.map((m) => renderType(m, ctx)).join(tok(" | "));
|
|
279
|
+
case "intersection":
|
|
280
|
+
return type.members.map((m) => renderType(m, ctx)).join(tok(" & "));
|
|
281
|
+
case "lazy":
|
|
282
|
+
return `${tok("Lazy<")}${renderType(type.inner, ctx)}${tok(">")}`;
|
|
283
|
+
case "inlineObject":
|
|
284
|
+
return `<details class="ce-inline-object"><summary>${tok("{ \u2026 }")}</summary>${renderFieldRows(type.fields, ctx)}</details>`;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
__name(renderType, "renderType");
|
|
288
|
+
function renderRef(name, ctx) {
|
|
289
|
+
const encName = encodeURIComponent(name);
|
|
290
|
+
const safeName = escapeHtml(name);
|
|
291
|
+
const entry = ctx.models?.get(name);
|
|
292
|
+
const visited = ctx.visited ?? /* @__PURE__ */ new Set();
|
|
293
|
+
const depth = ctx.depth ?? 0;
|
|
294
|
+
const maxDepth = ctx.maxDepth ?? DEFAULT_MAX_DEPTH;
|
|
295
|
+
if (!entry) {
|
|
296
|
+
return `<a class="ce-ref" href="#model-${encName}">${safeName}</a>`;
|
|
297
|
+
}
|
|
298
|
+
if (visited.has(name)) {
|
|
299
|
+
return `<span class="ce-ref ce-ref-cycle" title="recursive reference">${safeName} \u21BA</span>`;
|
|
300
|
+
}
|
|
301
|
+
const model = entry.model;
|
|
302
|
+
const jumpAttrs = `data-jump-file="${escapeHtml(entry.filePath)}" data-jump-line="${model.loc.line}"`;
|
|
303
|
+
if (depth >= maxDepth) {
|
|
304
|
+
return `<a class="ce-ref" href="#model-${encName}" ${jumpAttrs} title="Jump to source">${safeName}</a>`;
|
|
305
|
+
}
|
|
306
|
+
const nextCtx = {
|
|
307
|
+
models: ctx.models,
|
|
308
|
+
visited: /* @__PURE__ */ new Set([
|
|
309
|
+
...visited,
|
|
310
|
+
name
|
|
311
|
+
]),
|
|
312
|
+
maxDepth,
|
|
313
|
+
depth: depth + 1
|
|
314
|
+
};
|
|
315
|
+
const bases = model.bases && model.bases.length > 0 ? `<p class="ce-extends">extends ${model.bases.map((b) => renderRef(b, nextCtx)).join(", ")}</p>` : "";
|
|
316
|
+
const body = model.type ? `<div class="ce-type-alias">= ${renderType(model.type, nextCtx)}</div>` : renderFieldRows(model.fields, nextCtx);
|
|
317
|
+
const openButton = `<button class="ce-ref-open" type="button" ${jumpAttrs} title="Jump to source">\u2197</button>`;
|
|
318
|
+
return `<details class="ce-ref-expand">
|
|
319
|
+
<summary><span class="ce-ref-name">${safeName}</span>${openButton}</summary>
|
|
320
|
+
<div class="ce-ref-body">${bases}${body}</div>
|
|
321
|
+
</details>`;
|
|
322
|
+
}
|
|
323
|
+
__name(renderRef, "renderRef");
|
|
324
|
+
function tok(text) {
|
|
325
|
+
return `<span class="ce-type-token">${text}</span>`;
|
|
326
|
+
}
|
|
327
|
+
__name(tok, "tok");
|
|
328
|
+
|
|
329
|
+
// src/render-operation.ts
|
|
330
|
+
function operationAnchor(op) {
|
|
331
|
+
const suffix = op.op.sdk ?? op.op.name ?? "";
|
|
332
|
+
const slug2 = `${op.method}-${op.routePath}-${suffix}`.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
333
|
+
return `op-${slug2}`;
|
|
334
|
+
}
|
|
335
|
+
__name(operationAnchor, "operationAnchor");
|
|
336
|
+
function renderOperation(op, options = {}) {
|
|
337
|
+
const ctx = options.ctx ?? {};
|
|
338
|
+
const badges = [];
|
|
339
|
+
for (const m of op.effectiveModifiers) {
|
|
340
|
+
badges.push(badge2(m, m));
|
|
341
|
+
}
|
|
342
|
+
const securityBadge = renderSecurityBadge(op.effectiveSecurity);
|
|
343
|
+
if (securityBadge) badges.push(securityBadge);
|
|
344
|
+
const description = op.op.description ? `<div class="ce-description ce-markdown">${renderMarkdown(op.op.description)}</div>` : "";
|
|
345
|
+
const service = op.op.service ? html`<p class="ce-meta"><strong>service:</strong> <code>${op.op.service}</code></p>` : "";
|
|
346
|
+
const signature = op.op.signature ? html`<p class="ce-meta"><strong>signature:</strong> <code>${op.op.signature}</code>${op.op.signatureDescription ? raw(` \u2014 ${escapeHtml(op.op.signatureDescription)}`) : ""}</p>` : "";
|
|
347
|
+
const pathParams = renderParamSection("Path params", op.routeParams, ctx);
|
|
348
|
+
const queryParams = renderParamSection("Query", op.op.query, ctx);
|
|
349
|
+
const headerParams = renderParamSection("Headers", op.op.headers, ctx);
|
|
350
|
+
const requestBody = renderRequest(op.op.request, ctx);
|
|
351
|
+
const responses = renderResponses(op.op.responses, ctx);
|
|
352
|
+
const pluginExt = renderPluginExtensions(op.op.pluginExtensions);
|
|
353
|
+
const tryIt = options.tryItBaseUrl !== void 0 ? renderTryIt(op, options.tryItBaseUrl) : "";
|
|
354
|
+
return html`<section id="${raw(operationAnchor(op))}" class="ce-card ce-op-card">
|
|
355
|
+
<header class="ce-card-header">
|
|
356
|
+
<h2>
|
|
357
|
+
<span class="ce-method ce-method-${raw(op.method)}">${op.method.toUpperCase()}</span>
|
|
358
|
+
<code class="ce-path">${op.routePath}</code>
|
|
359
|
+
${raw(badges.join(""))}
|
|
360
|
+
<button
|
|
361
|
+
class="ce-jump"
|
|
362
|
+
data-jump-file="${op.filePath}"
|
|
363
|
+
data-jump-line="${op.op.loc.line}"
|
|
364
|
+
title="Open in editor"
|
|
365
|
+
type="button"
|
|
366
|
+
>
|
|
367
|
+
↗
|
|
368
|
+
</button>
|
|
369
|
+
</h2>
|
|
370
|
+
${op.op.name ? raw(`<p class="ce-op-name">${escapeHtml(op.op.name)}</p>`) : ""}
|
|
371
|
+
</header>
|
|
372
|
+
${raw(description)}
|
|
373
|
+
${raw(service)}
|
|
374
|
+
${raw(signature)}
|
|
375
|
+
${raw(pathParams)}
|
|
376
|
+
${raw(queryParams)}
|
|
377
|
+
${raw(headerParams)}
|
|
378
|
+
${raw(requestBody)}
|
|
379
|
+
${raw(responses)}
|
|
380
|
+
${raw(pluginExt)}
|
|
381
|
+
${raw(tryIt)}
|
|
382
|
+
</section>`;
|
|
383
|
+
}
|
|
384
|
+
__name(renderOperation, "renderOperation");
|
|
385
|
+
function renderSecurityBadge(security) {
|
|
386
|
+
if (!security) return "";
|
|
387
|
+
if (security === "none") return badge2("security: none", "security-none");
|
|
388
|
+
if (security.policy === false) return badge2("security: bypassed", "security-bypassed");
|
|
389
|
+
if (typeof security.policy === "string") return badge2(`policy: ${security.policy}`, "security-policy");
|
|
390
|
+
return "";
|
|
391
|
+
}
|
|
392
|
+
__name(renderSecurityBadge, "renderSecurityBadge");
|
|
393
|
+
function renderParamSection(label, source, ctx) {
|
|
394
|
+
if (!source) return "";
|
|
395
|
+
if (source.kind === "params") {
|
|
396
|
+
if (source.nodes.length === 0) return "";
|
|
397
|
+
return html`<section class="ce-subsection">
|
|
398
|
+
<h3>${label}</h3>
|
|
399
|
+
${raw(renderParamTable(source.nodes, ctx))}
|
|
400
|
+
</section>`;
|
|
401
|
+
}
|
|
402
|
+
if (source.kind === "ref") {
|
|
403
|
+
return html`<section class="ce-subsection">
|
|
404
|
+
<h3>${label}</h3>
|
|
405
|
+
<div>${raw(renderType({
|
|
406
|
+
kind: "ref",
|
|
407
|
+
name: source.name
|
|
408
|
+
}, ctx))}</div>
|
|
409
|
+
</section>`;
|
|
410
|
+
}
|
|
411
|
+
return html`<section class="ce-subsection">
|
|
412
|
+
<h3>${label}</h3>
|
|
413
|
+
<div>${raw(renderType(source.node, ctx))}</div>
|
|
414
|
+
</section>`;
|
|
415
|
+
}
|
|
416
|
+
__name(renderParamSection, "renderParamSection");
|
|
417
|
+
function renderParamTable(params, ctx) {
|
|
418
|
+
const rows = params.map((p) => {
|
|
419
|
+
const modifiers = [];
|
|
420
|
+
if (p.optional) modifiers.push("optional");
|
|
421
|
+
if (p.nullable) modifiers.push("nullable");
|
|
422
|
+
const modifierHtml = modifiers.map((m) => badge2(m, m)).join("");
|
|
423
|
+
const defaultHtml = p.default !== void 0 ? html`<code class="ce-default">= ${String(p.default)}</code>` : "";
|
|
424
|
+
const descHtml = p.description ? `<div class="ce-field-desc ce-markdown">${renderMarkdown(p.description)}</div>` : "";
|
|
425
|
+
return `<tr>
|
|
426
|
+
<td class="ce-field-name"><code>${escapeHtml(p.name)}</code>${modifierHtml}</td>
|
|
427
|
+
<td class="ce-field-type">${renderType(p.type, ctx)}${defaultHtml}${descHtml}</td>
|
|
428
|
+
</tr>`;
|
|
429
|
+
});
|
|
430
|
+
return `<table class="ce-fields"><tbody>${rows.join("")}</tbody></table>`;
|
|
431
|
+
}
|
|
432
|
+
__name(renderParamTable, "renderParamTable");
|
|
433
|
+
function renderRequest(request, ctx) {
|
|
434
|
+
if (!request || request.bodies.length === 0) return "";
|
|
435
|
+
const blocks = request.bodies.map((body) => {
|
|
436
|
+
return `<div class="ce-body-block">
|
|
437
|
+
<p class="ce-content-type"><code>${escapeHtml(body.contentType)}</code></p>
|
|
438
|
+
<div>${renderType(body.bodyType, ctx)}</div>
|
|
439
|
+
</div>`;
|
|
440
|
+
});
|
|
441
|
+
return `<section class="ce-subsection"><h3>Request body</h3>${blocks.join("")}</section>`;
|
|
442
|
+
}
|
|
443
|
+
__name(renderRequest, "renderRequest");
|
|
444
|
+
function renderResponses(responses, ctx) {
|
|
445
|
+
if (responses.length === 0) return "";
|
|
446
|
+
const blocks = responses.map((r) => renderResponse(r, ctx));
|
|
447
|
+
return `<section class="ce-subsection"><h3>Responses</h3>${blocks.join("")}</section>`;
|
|
448
|
+
}
|
|
449
|
+
__name(renderResponses, "renderResponses");
|
|
450
|
+
function renderResponse(response, ctx) {
|
|
451
|
+
const statusClass = `ce-status-${Math.floor(response.statusCode / 100)}xx`;
|
|
452
|
+
const contentTypeHtml = response.contentType ? `<p class="ce-content-type"><code>${escapeHtml(response.contentType)}</code></p>` : "";
|
|
453
|
+
const bodyHtml = response.bodyType ? `<div>${renderType(response.bodyType, ctx)}</div>` : '<p class="ce-empty">No body.</p>';
|
|
454
|
+
const headersHtml = renderResponseHeaders(response.headers, ctx);
|
|
455
|
+
return `<div class="ce-response-block">
|
|
456
|
+
<h4><span class="ce-status ${statusClass}">${response.statusCode}</span></h4>
|
|
457
|
+
${contentTypeHtml}
|
|
458
|
+
${bodyHtml}
|
|
459
|
+
${headersHtml}
|
|
460
|
+
</div>`;
|
|
461
|
+
}
|
|
462
|
+
__name(renderResponse, "renderResponse");
|
|
463
|
+
function renderResponseHeaders(headers, ctx) {
|
|
464
|
+
if (!headers || headers.length === 0) return "";
|
|
465
|
+
const rows = headers.map((h) => {
|
|
466
|
+
const optional = h.optional ? badge2("optional", "optional") : "";
|
|
467
|
+
const desc = h.description ? `<div class="ce-field-desc ce-markdown">${renderMarkdown(h.description)}</div>` : "";
|
|
468
|
+
return `<tr>
|
|
469
|
+
<td class="ce-field-name"><code>${escapeHtml(h.name)}</code>${optional}</td>
|
|
470
|
+
<td class="ce-field-type">${renderType(h.type, ctx)}${desc}</td>
|
|
471
|
+
</tr>`;
|
|
472
|
+
});
|
|
473
|
+
return `<h5>Headers</h5><table class="ce-fields"><tbody>${rows.join("")}</tbody></table>`;
|
|
474
|
+
}
|
|
475
|
+
__name(renderResponseHeaders, "renderResponseHeaders");
|
|
476
|
+
function renderPluginExtensions(ext) {
|
|
477
|
+
if (!ext || Object.keys(ext).length === 0) return "";
|
|
478
|
+
const json = JSON.stringify(ext, null, 2);
|
|
479
|
+
return html`<section class="ce-subsection">
|
|
480
|
+
<h3>Plugin extensions</h3>
|
|
481
|
+
<details><summary>Show JSON</summary><pre class="ce-code">${json}</pre></details>
|
|
482
|
+
</section>`;
|
|
483
|
+
}
|
|
484
|
+
__name(renderPluginExtensions, "renderPluginExtensions");
|
|
485
|
+
function badge2(label, kind) {
|
|
486
|
+
return `<span class="ce-badge ce-badge-${escapeHtml(kind)}">${escapeHtml(label)}</span>`;
|
|
487
|
+
}
|
|
488
|
+
__name(badge2, "badge");
|
|
489
|
+
|
|
490
|
+
// src/render.ts
|
|
491
|
+
var METHOD_ORDER = [
|
|
492
|
+
"get",
|
|
493
|
+
"post",
|
|
494
|
+
"put",
|
|
495
|
+
"patch",
|
|
496
|
+
"delete"
|
|
497
|
+
];
|
|
498
|
+
function renderApp(data) {
|
|
499
|
+
const warnings = renderWarnings(data.warnings);
|
|
500
|
+
const overview = renderOverview(data);
|
|
501
|
+
const sidebar = renderSidebar(data);
|
|
502
|
+
const operations = sortOperations(data.operations);
|
|
503
|
+
const opsHtml = operations.map((op) => renderOperation(op)).join("");
|
|
504
|
+
const modelsHtml = [
|
|
505
|
+
...data.models
|
|
506
|
+
].sort((a, b) => a.model.name.localeCompare(b.model.name)).map((m) => renderModel(m)).join("");
|
|
507
|
+
return html`<div class="ce-layout">
|
|
508
|
+
${raw(sidebar)}
|
|
509
|
+
<main class="ce-detail">
|
|
510
|
+
${raw(warnings)}
|
|
511
|
+
${raw(overview)}
|
|
512
|
+
${operations.length > 0 ? raw(`<section class="ce-section"><h1 id="endpoints">Endpoints</h1>${opsHtml}</section>`) : ""}
|
|
513
|
+
${data.models.length > 0 ? raw(`<section class="ce-section"><h1 id="models">Models</h1>${modelsHtml}</section>`) : ""}
|
|
514
|
+
</main>
|
|
515
|
+
</div>`;
|
|
516
|
+
}
|
|
517
|
+
__name(renderApp, "renderApp");
|
|
518
|
+
function renderOverview(data) {
|
|
519
|
+
const { configMeta } = data;
|
|
520
|
+
const description = configMeta.description ? html`<p class="ce-description">${configMeta.description}</p>` : "";
|
|
521
|
+
const servers = configMeta.servers && configMeta.servers.length > 0 ? `<section class="ce-subsection"><h3>Servers</h3><ul>${configMeta.servers.map((s) => `<li><code>${escapeHtml(s.url)}</code>${s.description ? ` \u2014 ${escapeHtml(s.description)}` : ""}</li>`).join("")}</ul></section>` : "";
|
|
522
|
+
return html`<section id="overview" class="ce-section ce-overview">
|
|
523
|
+
<h1>${configMeta.title}</h1>
|
|
524
|
+
<p class="ce-version">v${configMeta.version}</p>
|
|
525
|
+
${raw(description)}
|
|
526
|
+
${raw(servers)}
|
|
527
|
+
</section>`;
|
|
528
|
+
}
|
|
529
|
+
__name(renderOverview, "renderOverview");
|
|
530
|
+
function renderSidebar(data) {
|
|
531
|
+
const operations = sortOperations(data.operations);
|
|
532
|
+
const groups = groupBy(operations, (op) => op.fileGroup);
|
|
533
|
+
const groupKeys = [
|
|
534
|
+
...groups.keys()
|
|
535
|
+
].sort();
|
|
536
|
+
const endpointGroups = groupKeys.map((key) => {
|
|
537
|
+
const items = groups.get(key).map((op) => `<li><a href="#${escapeHtml(operationAnchor(op))}">
|
|
538
|
+
<span class="ce-method ce-method-${escapeHtml(op.method)}">${escapeHtml(op.method.toUpperCase())}</span>
|
|
539
|
+
<span class="ce-sidebar-path">${escapeHtml(op.routePath)}</span>
|
|
540
|
+
</a></li>`).join("");
|
|
541
|
+
return `<details open class="ce-sidebar-group">
|
|
542
|
+
<summary>${escapeHtml(key)}</summary>
|
|
543
|
+
<ul>${items}</ul>
|
|
544
|
+
</details>`;
|
|
545
|
+
}).join("");
|
|
546
|
+
const modelLinks = [
|
|
547
|
+
...data.models
|
|
548
|
+
].sort((a, b) => a.model.name.localeCompare(b.model.name)).map((m) => `<li><a href="#${escapeHtml(modelAnchor(m.model.name))}">${escapeHtml(m.model.name)}</a></li>`).join("");
|
|
549
|
+
return `<aside class="ce-sidebar">
|
|
550
|
+
<nav>
|
|
551
|
+
<section>
|
|
552
|
+
<h4><a href="#overview">Overview</a></h4>
|
|
553
|
+
</section>
|
|
554
|
+
${operations.length > 0 ? `<section><h4><a href="#endpoints">Endpoints</a></h4>${endpointGroups}</section>` : ""}
|
|
555
|
+
${data.models.length > 0 ? `<section><h4><a href="#models">Models</a></h4><ul class="ce-model-list">${modelLinks}</ul></section>` : ""}
|
|
556
|
+
</nav>
|
|
557
|
+
</aside>`;
|
|
558
|
+
}
|
|
559
|
+
__name(renderSidebar, "renderSidebar");
|
|
560
|
+
function renderWarnings(warnings) {
|
|
561
|
+
if (warnings.length === 0) return "";
|
|
562
|
+
const items = warnings.map((w) => `<li>${escapeHtml(w.message)}${w.file ? ` <code>${escapeHtml(w.file)}${w.line ? `:${w.line}` : ""}</code>` : ""}</li>`).join("");
|
|
563
|
+
return `<div class="ce-warnings"><strong>${warnings.length} warning${warnings.length === 1 ? "" : "s"}</strong><ul>${items}</ul></div>`;
|
|
564
|
+
}
|
|
565
|
+
__name(renderWarnings, "renderWarnings");
|
|
566
|
+
function sortOperations(operations) {
|
|
567
|
+
return [
|
|
568
|
+
...operations
|
|
569
|
+
].sort((a, b) => {
|
|
570
|
+
const groupCmp = a.fileGroup.localeCompare(b.fileGroup);
|
|
571
|
+
if (groupCmp !== 0) return groupCmp;
|
|
572
|
+
const pathCmp = a.routePath.localeCompare(b.routePath);
|
|
573
|
+
if (pathCmp !== 0) return pathCmp;
|
|
574
|
+
return METHOD_ORDER.indexOf(a.method) - METHOD_ORDER.indexOf(b.method);
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
__name(sortOperations, "sortOperations");
|
|
578
|
+
function groupBy(items, keyFn) {
|
|
579
|
+
const out = /* @__PURE__ */ new Map();
|
|
580
|
+
for (const item of items) {
|
|
581
|
+
const key = keyFn(item);
|
|
582
|
+
const arr = out.get(key);
|
|
583
|
+
if (arr) arr.push(item);
|
|
584
|
+
else out.set(key, [
|
|
585
|
+
item
|
|
586
|
+
]);
|
|
587
|
+
}
|
|
588
|
+
return out;
|
|
589
|
+
}
|
|
590
|
+
__name(groupBy, "groupBy");
|
|
591
|
+
|
|
592
|
+
// src/render-item.ts
|
|
593
|
+
function renderItemPage(data, selection, options = {}) {
|
|
594
|
+
const body = renderBody(data, selection, options);
|
|
595
|
+
return html`<div class="ce-detail ce-detail-single">${raw(body)}</div>`;
|
|
596
|
+
}
|
|
597
|
+
__name(renderItemPage, "renderItemPage");
|
|
598
|
+
function renderBody(data, selection, options) {
|
|
599
|
+
if (selection.kind === "overview") return renderOverviewPage(data);
|
|
600
|
+
const ctx = {
|
|
601
|
+
models: buildModelMap(data)
|
|
602
|
+
};
|
|
603
|
+
if (selection.kind === "operation") {
|
|
604
|
+
const op = data.operations.find((o) => operationAnchor(o) === selection.id);
|
|
605
|
+
if (!op) return renderMissing(`Operation \`${selection.id}\` is not in the current workspace.`);
|
|
606
|
+
return renderOperation(op, {
|
|
607
|
+
tryItBaseUrl: options.tryItBaseUrl,
|
|
608
|
+
ctx
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
const model = data.models.find((m) => m.model.name === selection.name);
|
|
612
|
+
if (!model) return renderMissing(`Model \`${selection.name}\` is not in the current workspace.`);
|
|
613
|
+
return renderModel(model, ctx);
|
|
614
|
+
}
|
|
615
|
+
__name(renderBody, "renderBody");
|
|
616
|
+
function buildModelMap(data) {
|
|
617
|
+
const out = /* @__PURE__ */ new Map();
|
|
618
|
+
for (const entry of data.models) out.set(entry.model.name, entry);
|
|
619
|
+
return out;
|
|
620
|
+
}
|
|
621
|
+
__name(buildModelMap, "buildModelMap");
|
|
622
|
+
function renderOverviewPage(data) {
|
|
623
|
+
const { configMeta } = data;
|
|
624
|
+
const description = configMeta.description ? `<div class="ce-description ce-markdown">${renderMarkdown(configMeta.description)}</div>` : "";
|
|
625
|
+
const servers = renderServersList(configMeta.servers);
|
|
626
|
+
const stats = `<dl class="ce-stats">
|
|
627
|
+
<dt>Endpoints</dt><dd>${data.operations.length}</dd>
|
|
628
|
+
<dt>Models</dt><dd>${data.models.length}</dd>
|
|
629
|
+
</dl>`;
|
|
630
|
+
return html`<section id="overview" class="ce-section ce-overview">
|
|
631
|
+
<h1>${configMeta.title}</h1>
|
|
632
|
+
<p class="ce-version">v${configMeta.version}</p>
|
|
633
|
+
${raw(description)}
|
|
634
|
+
${raw(stats)}
|
|
635
|
+
${raw(servers)}
|
|
636
|
+
<p class="ce-hint">Pick an endpoint or model from the API Explorer in the sidebar to see details.</p>
|
|
637
|
+
</section>`;
|
|
638
|
+
}
|
|
639
|
+
__name(renderOverviewPage, "renderOverviewPage");
|
|
640
|
+
function renderServersList(servers) {
|
|
641
|
+
if (!servers || servers.length === 0) return "";
|
|
642
|
+
const items = servers.map((s) => `<li><code>${escapeHtml(s.url)}</code>${s.description ? ` \u2014 ${escapeHtml(s.description)}` : ""}</li>`).join("");
|
|
643
|
+
return `<section class="ce-subsection"><h3>Servers</h3><ul>${items}</ul></section>`;
|
|
644
|
+
}
|
|
645
|
+
__name(renderServersList, "renderServersList");
|
|
646
|
+
function renderMissing(message) {
|
|
647
|
+
return `<section class="ce-card ce-missing"><p class="ce-empty">${escapeHtml(message)}</p></section>`;
|
|
648
|
+
}
|
|
649
|
+
__name(renderMissing, "renderMissing");
|
|
650
|
+
var operationId = operationAnchor;
|
|
651
|
+
var modelId = /* @__PURE__ */ __name((name) => modelAnchor(name), "modelId");
|
|
652
|
+
function listSelections(data) {
|
|
653
|
+
return [
|
|
654
|
+
...data.operations.map((operation) => ({
|
|
655
|
+
kind: "operation",
|
|
656
|
+
id: operationId(operation),
|
|
657
|
+
operation
|
|
658
|
+
})),
|
|
659
|
+
...data.models.map((model) => ({
|
|
660
|
+
kind: "model",
|
|
661
|
+
name: model.model.name,
|
|
662
|
+
model
|
|
663
|
+
}))
|
|
664
|
+
];
|
|
665
|
+
}
|
|
666
|
+
__name(listSelections, "listSelections");
|
|
667
|
+
export {
|
|
668
|
+
constraintSummary,
|
|
669
|
+
escapeHtml,
|
|
670
|
+
html,
|
|
671
|
+
listSelections,
|
|
672
|
+
modelAnchor,
|
|
673
|
+
modelId,
|
|
674
|
+
operationAnchor,
|
|
675
|
+
operationId,
|
|
676
|
+
raw,
|
|
677
|
+
renderApp,
|
|
678
|
+
renderFieldRows,
|
|
679
|
+
renderItemPage,
|
|
680
|
+
renderMarkdown,
|
|
681
|
+
renderModel,
|
|
682
|
+
renderOperation,
|
|
683
|
+
renderTryIt,
|
|
684
|
+
renderType,
|
|
685
|
+
slug
|
|
686
|
+
};
|
|
687
|
+
//# sourceMappingURL=index.js.map
|