@open-resource-discovery/metadata-renderer 0.0.0 → 1.0.1

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.
Files changed (74) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +94 -1
  3. package/dist/a2a/index.d.ts +9 -0
  4. package/dist/a2a.js +2 -0
  5. package/dist/asyncApi/asyncapi-browser.d.ts +3 -0
  6. package/dist/asyncApi/customAttributes/attributeLink.d.ts +3 -0
  7. package/dist/asyncApi/customAttributes/autoDiscover.d.ts +4 -0
  8. package/dist/asyncApi/customAttributes/buildExtensionsConfig.d.ts +5 -0
  9. package/dist/asyncApi/customAttributes/context.d.ts +7 -0
  10. package/dist/asyncApi/customAttributes/genericRenderer.d.ts +4 -0
  11. package/dist/asyncApi/customAttributes/sapPreset.d.ts +2 -0
  12. package/dist/asyncApi/customAttributes/stateInfo.d.ts +3 -0
  13. package/dist/asyncApi/customAttributes/styles.d.ts +2 -0
  14. package/dist/asyncApi/customAttributes/types.d.ts +32 -0
  15. package/dist/asyncApi/index.d.ts +11 -0
  16. package/dist/asyncapi.js +2 -0
  17. package/dist/chunks/a2a-B5lkgqLU.js +29 -0
  18. package/dist/chunks/asyncApi-DtAXW7IY.js +502 -0
  19. package/dist/chunks/csn-3ek2O4d6.js +385 -0
  20. package/dist/chunks/mcp-qA5sYRAN.js +29 -0
  21. package/dist/chunks/openApi-BTb5yzun.js +783 -0
  22. package/dist/chunks/utils-BC3WF3-9.js +77 -0
  23. package/dist/core/ShadowRoot.d.ts +6 -0
  24. package/dist/core/dispatch.d.ts +3 -0
  25. package/dist/core/dispatch.test.d.ts +1 -0
  26. package/dist/core/index.d.ts +11 -0
  27. package/dist/core/utils.d.ts +7 -0
  28. package/dist/core/utils.test.d.ts +1 -0
  29. package/dist/csn/customAttributes/genericRenderer.d.ts +2 -0
  30. package/dist/csn/customAttributes/postProcess.d.ts +5 -0
  31. package/dist/csn/customAttributes/sapPreset.d.ts +2 -0
  32. package/dist/csn/customAttributes/types.d.ts +28 -0
  33. package/dist/csn/index.d.ts +11 -0
  34. package/dist/csn/styles.d.ts +2 -0
  35. package/dist/csn.js +2 -0
  36. package/dist/entries/a2a.d.ts +2 -0
  37. package/dist/entries/asyncapi.d.ts +2 -0
  38. package/dist/entries/csn.d.ts +2 -0
  39. package/dist/entries/mcp.d.ts +2 -0
  40. package/dist/entries/openapi.d.ts +2 -0
  41. package/dist/favicon.ico +0 -0
  42. package/dist/favicon.svg +29 -0
  43. package/dist/index.css +210782 -0
  44. package/dist/index.d.ts +23 -0
  45. package/dist/index.js +783 -0
  46. package/dist/mcp/index.d.ts +8 -0
  47. package/dist/mcp.js +2 -0
  48. package/dist/openApi/customAttributes/attributeLink.d.ts +3 -0
  49. package/dist/openApi/customAttributes/autoDiscover.d.ts +15 -0
  50. package/dist/openApi/customAttributes/genericRenderer.d.ts +3 -0
  51. package/dist/openApi/customAttributes/sapAttributes/operation/deprecatedOperation.d.ts +10 -0
  52. package/dist/openApi/customAttributes/sapAttributes/root/extOverview.d.ts +2 -0
  53. package/dist/openApi/customAttributes/sapAttributes/root/extensible.d.ts +10 -0
  54. package/dist/openApi/customAttributes/sapAttributes/root/ordId.d.ts +6 -0
  55. package/dist/openApi/customAttributes/sapAttributes/root/stateInfo.d.ts +11 -0
  56. package/dist/openApi/customAttributes/sapAttributes/root/typeCheckXxtOverview.d.ts +10 -0
  57. package/dist/openApi/customAttributes/sapAttributes/root/typeCheckXxtOverview.spec.d.ts +1 -0
  58. package/dist/openApi/customAttributes/sapAttributes/sapPreset.d.ts +2 -0
  59. package/dist/openApi/customAttributes/sapAttributes/schema/odmEntityName.d.ts +6 -0
  60. package/dist/openApi/customAttributes/sapAttributes/schema/odmSemanticKey.d.ts +10 -0
  61. package/dist/openApi/customAttributes/types.d.ts +31 -0
  62. package/dist/openApi/index.d.ts +9 -0
  63. package/dist/openApi/styles.d.ts +2 -0
  64. package/dist/openApi/utils/context.d.ts +7 -0
  65. package/dist/openApi/utils/context.test.d.ts +1 -0
  66. package/dist/openApi/utils/plugins.d.ts +3 -0
  67. package/dist/openApi/utils/scalarTheme.d.ts +11 -0
  68. package/dist/openapi.js +2 -0
  69. package/dist/styles.d.ts +0 -0
  70. package/dist/styles.js +4 -0
  71. package/dist/theme-builder.d.ts +28 -0
  72. package/dist/types.d.ts +46 -0
  73. package/dist/vendor.d.ts +2 -0
  74. package/package.json +135 -3
@@ -0,0 +1,385 @@
1
+ import { i as loadObject } from "./utils-BC3WF3-9.js";
2
+ import { useEffect, useState } from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { generateHtml } from "@sap/csn-interop-renderer";
5
+ //#region src/lib/csn/styles.ts
6
+ var styles_default = `
7
+ .csn-root {
8
+ color: var(--ord-foreground, #1a1a2e);
9
+ background-color: var(--ord-background, #ffffff);
10
+ container: csn / inline-size;
11
+ /* Single font source for the whole renderer so tables, headings, paragraphs and
12
+ custom fields stay consistent (they otherwise inherit the host page's font). */
13
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
14
+ }
15
+ /* Host frameworks (e.g. Docusaurus/Infima) set font-family directly on h1-h6, which
16
+ beats inheritance from .csn-root. Re-inherit so headings match the rest of the renderer. */
17
+ .csn-root h1,
18
+ .csn-root h2,
19
+ .csn-root h3,
20
+ .csn-root h4,
21
+ .csn-root h5,
22
+ .csn-root h6 {
23
+ font-family: inherit;
24
+ }
25
+ .csn-root table {
26
+ border-spacing: 0;
27
+ border-collapse: separate;
28
+ border: solid 1px var(--ord-border, #a6a6a6);
29
+ border-radius: calc(var(--ord-radius, 4)*1px);
30
+ /* display: table overrides Docusaurus/Infima's global "table { display: block }",
31
+ which otherwise breaks table-layout: fixed and the column widths below. */
32
+ display: table;
33
+ width: 100%;
34
+ table-layout: fixed;
35
+ overflow: hidden;
36
+ }
37
+ .csn-root table th {
38
+ text-align: left;
39
+ background-color: var(--ord-primary, #1a1a2e);
40
+ color: var(--ord-primary-foreground, #fafafa);
41
+ padding: 8px;
42
+ border: 1px solid var(--ord-border, #a6a6a6);
43
+ }
44
+ .csn-root table td {
45
+ text-align: start;
46
+ padding: 8px;
47
+ align-content: start;
48
+ font-size: 0.875em;
49
+ }
50
+ .csn-root table td strong {
51
+ font-weight: 500;
52
+ }
53
+ .csn-root table th:nth-child(1),
54
+ .csn-root table td:nth-child(1) {
55
+ width: clamp(10ch, 24cqi, 20ch);
56
+ }
57
+ .csn-root table th:nth-child(2),
58
+ .csn-root table td:nth-child(2) {
59
+ width: clamp(8ch, 19cqi, 16ch);
60
+ }
61
+ .csn-root table tbody td {
62
+ color: var(--ord-foreground, #636363);
63
+ border: 1px solid var(--ord-border, #dddfe1);
64
+ }
65
+ .csn-root table tbody tr {
66
+ background-color: var(--ord-card, #f9fafb);
67
+ }
68
+ .csn-root table tbody tr:nth-child(odd) {
69
+ background-color: var(--ord-background, #ffffff);
70
+ }
71
+ .csn-root code {
72
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
73
+ background-color: var(--ord-code-bg, #cccccc);
74
+ color: var(--ord-code-fg, #333333);
75
+ }
76
+ .csn-root a {
77
+ color: var(--ord-accent-foreground, #375eab)
78
+ }
79
+ .csn-root .csn-attr-row {
80
+ display: flex;
81
+ gap: 0;
82
+ margin: 6px 0;
83
+ font-size: 0.875em;
84
+ line-height: 1.5;
85
+ border: 1px solid var(--ord-border, #dddfe1);
86
+ border-radius: 4px;
87
+ overflow: hidden;
88
+ }
89
+ .csn-root .csn-attr-row + br { display: none; } /* Remove br's afte attribute rows */
90
+ .csn-root .csn-attr-label {
91
+ width: 25%;
92
+ min-width: 20ch;
93
+ flex-shrink: 0;
94
+ color: var(--ord-foreground, #1a1a2e);
95
+ background: var(--ord-muted, #f3f4f6);
96
+ padding: 4px 8px;
97
+ display: inline-flex;
98
+ align-items: center;
99
+ gap: 4px;
100
+ border-right: 1px solid var(--ord-border, #dddfe1);
101
+ font-weight: 500;
102
+ }
103
+ .csn-root .csn-attr-value {
104
+ color: var(--ord-muted-foreground, #6b7280);
105
+ padding: 3px 8px;
106
+ }
107
+ .csn-root .csn-attr-link {
108
+ color: var(--ord-primary, #375eab);
109
+ text-decoration: none;
110
+ }
111
+ .csn-root .csn-attr-doclink {
112
+ color: var(--ord-muted-foreground, #6b7280);
113
+ text-decoration: none;
114
+ font-size: 0.8em;
115
+ margin-left: 2px;
116
+ }
117
+ .csn-root .csn-attr-list {
118
+ display: flex;
119
+ flex-direction: column;
120
+ gap: 2px;
121
+ }
122
+ .csn-root .csn-attr-list-item {
123
+ display: block;
124
+ }
125
+ .csn-root .csn-attr-obj {
126
+ display: flex;
127
+ flex-direction: column;
128
+ gap: 2px;
129
+ }
130
+ .csn-root .csn-attr-kv {
131
+ display: flex;
132
+ gap: 4px;
133
+ }
134
+ .csn-root .csn-attr-kv-key {
135
+ font-weight: 600;
136
+ color: var(--ord-foreground, #1a1a2e);
137
+ }
138
+ .csn-root .csn-attr-kv-val {
139
+ color: var(--ord-muted-foreground, #6b7280);
140
+ }
141
+
142
+ /* Width-adaptive attribute rows. Trigger is the renderer's own width (container: csn).
143
+ Root-level annotations sit in <p> and get ~full renderer width, so they only flip to
144
+ vertical when the renderer itself is narrow. Element-level annotations sit in a <td>
145
+ (the Description cell) and only get the 3rd column's width, so they flip much earlier.
146
+ (A real container on the <td> is impossible: size containment is ignored on table cells.) */
147
+ @container csn (max-width: 420px) {
148
+ .csn-root p .csn-attr-row {
149
+ flex-direction: column;
150
+ }
151
+ .csn-root p .csn-attr-label {
152
+ width: 100%;
153
+ min-width: 0;
154
+ border-right: none;
155
+ border-bottom: 1px solid var(--ord-border, #dddfe1);
156
+ }
157
+ .csn-root p .csn-attr-value {
158
+ width: 100%;
159
+ }
160
+ }
161
+ @container csn (max-width: 700px) {
162
+ .csn-root td .csn-attr-row {
163
+ flex-direction: column;
164
+ }
165
+ .csn-root td .csn-attr-label {
166
+ width: 100%;
167
+ min-width: 0;
168
+ border-right: none;
169
+ border-bottom: 1px solid var(--ord-border, #dddfe1);
170
+ }
171
+ .csn-root td .csn-attr-value {
172
+ width: 100%;
173
+ }
174
+ }
175
+ `;
176
+ //#endregion
177
+ //#region src/lib/csn/customAttributes/genericRenderer.ts
178
+ function autoLabel(key, prefix) {
179
+ let name = key;
180
+ if (prefix && name.startsWith(prefix)) name = name.slice(prefix.length);
181
+ return name.split(".").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" · ");
182
+ }
183
+ function escapeHtml(str) {
184
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
185
+ }
186
+ function renderValue(value, def) {
187
+ if (value === null || value === void 0) return "";
188
+ if (def && "render" in def) return def.render(value);
189
+ if (def?.type === "link" && "callback" in def) {
190
+ const href = def.callback(value);
191
+ const text = escapeHtml(String(value));
192
+ return href ? `<a href="${escapeHtml(href)}" class="csn-attr-link" target="_blank" rel="noreferrer">${text}</a>` : text;
193
+ }
194
+ if (def?.type === "boolean" || typeof value === "boolean") return value ? "Yes" : "No";
195
+ if (def?.type === "number" || typeof value === "number") return escapeHtml(String(value));
196
+ if (def?.type === "array" || Array.isArray(value)) {
197
+ if (!Array.isArray(value)) return escapeHtml(String(value));
198
+ return `<span class="csn-attr-list">${value.map((item) => `<span class="csn-attr-list-item">${renderValue(item, void 0)}</span>`).join("")}</span>`;
199
+ }
200
+ if (def?.type === "object" || typeof value === "object" && value !== null) {
201
+ const entries = Object.entries(value);
202
+ if (entries.length === 1 && entries[0][0] === "#") return escapeHtml(String(entries[0][1]));
203
+ return `<span class="csn-attr-obj">${entries.map(([k, v]) => `<span class="csn-attr-kv"><span class="csn-attr-kv-key">${escapeHtml(k)}</span><span class="csn-attr-kv-val">${renderValue(v, void 0)}</span></span>`).join("")}</span>`;
204
+ }
205
+ if (def && "valueLinks" in def && def.valueLinks) {
206
+ const href = def.valueLinks[String(value)];
207
+ const text = escapeHtml(String(value));
208
+ return href ? `<a href="${escapeHtml(href)}" class="csn-attr-link" target="_blank" rel="noreferrer">${text}</a>` : text;
209
+ }
210
+ return escapeHtml(String(value));
211
+ }
212
+ function buildCsnAnnotationHtml(key, value, def, config) {
213
+ if (value === null || value === void 0) return "";
214
+ const label = def && !("render" in def) && "label" in def && def.label ? def.label : autoLabel(key, config.prefixStartsWith ?? "@");
215
+ const docUrl = config.documentationUrl?.(key);
216
+ const docLink = docUrl ? ` <a href="${escapeHtml(docUrl)}" class="csn-attr-doclink" target="_blank" rel="noreferrer" title="Documentation">↗</a>` : "";
217
+ const valueHtml = renderValue(value, def);
218
+ if (!valueHtml) return "";
219
+ return `<span class="csn-attr-row"><span class="csn-attr-label">${escapeHtml(label)}${docLink}</span><span class="csn-attr-value">${valueHtml}</span></span>`;
220
+ }
221
+ //#endregion
222
+ //#region src/lib/csn/customAttributes/postProcess.ts
223
+ function discoverAnnotationKeys(doc, prefix) {
224
+ const keys = /* @__PURE__ */ new Set();
225
+ const addFromObj = (obj) => {
226
+ if (!obj || typeof obj !== "object") return;
227
+ for (const k of Object.keys(obj)) if (k.startsWith(prefix)) keys.add(k);
228
+ };
229
+ const definitions = doc.definitions;
230
+ if (definitions) for (const def of Object.values(definitions)) {
231
+ addFromObj(def);
232
+ const elements = def?.elements;
233
+ if (elements) for (const el of Object.values(elements)) addFromObj(el);
234
+ }
235
+ return [...keys];
236
+ }
237
+ function parseCodeValue(decoded) {
238
+ try {
239
+ return JSON.parse(decoded);
240
+ } catch {
241
+ return decoded;
242
+ }
243
+ }
244
+ function replaceNodeRun(parentNode, startNode, endNode, replacementHtml) {
245
+ const tpl = parentNode.ownerDocument.createElement("template");
246
+ tpl.innerHTML = replacementHtml;
247
+ parentNode.insertBefore(tpl.content, startNode);
248
+ let cur = startNode;
249
+ while (cur) {
250
+ const next = cur.nextSibling;
251
+ const done = cur === endNode;
252
+ parentNode.removeChild(cur);
253
+ if (done) break;
254
+ cur = next;
255
+ }
256
+ }
257
+ function collectAnnotationPairs(td, renderers) {
258
+ const pairs = [];
259
+ const childNodes = Array.from(td.childNodes);
260
+ for (let i = 0; i < childNodes.length - 1; i++) {
261
+ const node = childNodes[i];
262
+ if (node.nodeType !== Node.TEXT_NODE) continue;
263
+ const text = (node.textContent ?? "").replace(/^\s+/, "");
264
+ const match = /^@([\w.]+):\s*$/.exec(text);
265
+ if (!match) continue;
266
+ const key = `@${match[1]}`;
267
+ const entry = renderers.get(key);
268
+ if (!entry) continue;
269
+ const valueNode = childNodes[i + 1];
270
+ if (!valueNode || valueNode.nodeType !== Node.ELEMENT_NODE) continue;
271
+ const el = valueNode;
272
+ let codeEl = null;
273
+ if (el.tagName === "CODE") codeEl = el;
274
+ else if (el.tagName === "A") codeEl = el.querySelector("code");
275
+ if (!codeEl) continue;
276
+ pairs.push({
277
+ textNode: node,
278
+ valueNode,
279
+ codeEl,
280
+ key,
281
+ entry
282
+ });
283
+ }
284
+ return pairs;
285
+ }
286
+ function applyAnnotationRenderers(html, configs, doc) {
287
+ const renderers = /* @__PURE__ */ new Map();
288
+ for (const config of configs) {
289
+ for (const [key, def] of Object.entries(config.annotations ?? {})) if (!renderers.has(key)) renderers.set(key, {
290
+ def,
291
+ config
292
+ });
293
+ if (config.prefixStartsWith && doc) {
294
+ for (const key of discoverAnnotationKeys(doc, config.prefixStartsWith)) if (!renderers.has(key)) renderers.set(key, {
295
+ def: void 0,
296
+ config
297
+ });
298
+ }
299
+ }
300
+ if (renderers.size === 0) return html;
301
+ const domDoc = new DOMParser().parseFromString(html, "text/html");
302
+ for (const td of Array.from(domDoc.querySelectorAll("td, p"))) {
303
+ const pairs = collectAnnotationPairs(td, renderers);
304
+ for (const { textNode, valueNode, codeEl, key, entry } of pairs) {
305
+ const rendered = buildCsnAnnotationHtml(key, parseCodeValue(codeEl.textContent ?? ""), entry.def, entry.config);
306
+ if (rendered) replaceNodeRun(td, textNode, valueNode, rendered);
307
+ }
308
+ }
309
+ return domDoc.body.innerHTML;
310
+ }
311
+ //#endregion
312
+ //#region src/lib/csn/index.tsx
313
+ function buildAnnotationLinkCallbacks(configs) {
314
+ const callbacks = {};
315
+ for (const config of configs) for (const [key, def] of Object.entries(config.annotations ?? {})) if ("type" in def && def.type === "link" && "callback" in def && !(key in callbacks)) {
316
+ const cb = def.callback;
317
+ callbacks[key] = (value) => cb(value) ?? "";
318
+ }
319
+ return callbacks;
320
+ }
321
+ function CsnRenderer({ content, config, customAttributes, className, theme }) {
322
+ const [state, setState] = useState({ kind: "idle" });
323
+ useEffect(() => {
324
+ if (!content) {
325
+ setState({ kind: "idle" });
326
+ return;
327
+ }
328
+ let cancelled = false;
329
+ setState({ kind: "loading" });
330
+ let parsed;
331
+ try {
332
+ parsed = JSON.parse(content);
333
+ } catch (e) {
334
+ setState({
335
+ kind: "error",
336
+ message: String(e)
337
+ });
338
+ return;
339
+ }
340
+ const activeConfigs = customAttributes ?? [];
341
+ const isEnabled = customAttributes !== void 0;
342
+ const parsedDoc = isEnabled ? loadObject(content) : null;
343
+ const linkCallbacks = isEnabled ? buildAnnotationLinkCallbacks(activeConfigs) : {};
344
+ const rendererConfig = {
345
+ ...config,
346
+ annotationLinkCallbacks: {
347
+ ...linkCallbacks,
348
+ ...config?.annotationLinkCallbacks
349
+ }
350
+ };
351
+ generateHtml(parsed, rendererConfig).then((html) => {
352
+ const processed = isEnabled ? applyAnnotationRenderers(html, activeConfigs, parsedDoc) : html;
353
+ if (!cancelled) setState({
354
+ kind: "ready",
355
+ html: processed
356
+ });
357
+ }).catch((e) => {
358
+ if (!cancelled) setState({
359
+ kind: "error",
360
+ message: String(e)
361
+ });
362
+ });
363
+ return () => {
364
+ cancelled = true;
365
+ };
366
+ }, [
367
+ content,
368
+ config,
369
+ customAttributes
370
+ ]);
371
+ return /* @__PURE__ */ jsxs("div", {
372
+ className: `csn-root${className ? ` ${className}` : ""}`,
373
+ style: theme,
374
+ children: [
375
+ /* @__PURE__ */ jsx("style", { children: styles_default }),
376
+ state.kind === "ready" && /* @__PURE__ */ jsx("div", {
377
+ className: "p-4",
378
+ dangerouslySetInnerHTML: { __html: state.html }
379
+ }),
380
+ state.kind === "error" && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h1", { children: "Invalid CSN" }), /* @__PURE__ */ jsx("div", { children: state.message })] })
381
+ ]
382
+ });
383
+ }
384
+ //#endregion
385
+ export { CsnRenderer as t };
@@ -0,0 +1,29 @@
1
+ import { t as buildShadcnThemeStyle } from "./utils-BC3WF3-9.js";
2
+ /* empty css */
3
+ import { useEffect, useId } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { MCPServerCardView, useServerCardStore } from "@open-resource-discovery/mcp-server-card-ui/card-view";
6
+ import { useTheme } from "@open-resource-discovery/mcp-server-card-ui";
7
+ //#region src/lib/mcp/index.tsx
8
+ function McpRenderer({ content, showValidation = false, className, theme }) {
9
+ const id = useId();
10
+ const { setTheme } = useTheme();
11
+ const isDark = className?.split(/\s+/).includes("dark") ?? false;
12
+ useEffect(() => {
13
+ useServerCardStore.getState().setRawJson(content);
14
+ }, [content]);
15
+ useEffect(() => {
16
+ setTheme(isDark ? "dark" : "light");
17
+ }, [isDark, setTheme]);
18
+ const themeStyle = theme ? buildShadcnThemeStyle("mcp-root", id, theme) : null;
19
+ return /* @__PURE__ */ jsxs("div", {
20
+ "data-renderer-id": id,
21
+ className: "h-full",
22
+ children: [themeStyle && /* @__PURE__ */ jsx("style", { children: themeStyle }), /* @__PURE__ */ jsx(MCPServerCardView, {
23
+ readOnly: true,
24
+ showValidation
25
+ })]
26
+ });
27
+ }
28
+ //#endregion
29
+ export { McpRenderer as t };