@emeryld/rrroutes-contract 2.2.3 → 2.2.5

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/index.mjs CHANGED
@@ -516,6 +516,21 @@ body {
516
516
  box-shadow: 0 10px 30px -10px rgba(0,0,0,0.5);
517
517
  }
518
518
 
519
+ .schema-indent {
520
+ display: inline-block;
521
+ }
522
+
523
+ .schema-branch {
524
+ opacity: 0.6;
525
+ font-family: var(--font-mono);
526
+ margin-right: 2px;
527
+ }
528
+
529
+ .schema-meta code {
530
+ font-family: var(--font-mono);
531
+ font-size: 11px;
532
+ }
533
+
519
534
  /* Top Row: Filters */
520
535
  .filters-row {
521
536
  display: flex;
@@ -607,6 +622,15 @@ body {
607
622
  font-weight: 700;
608
623
  margin-right: 4px;
609
624
  }
625
+ .schema-indent {
626
+ display: inline-block;
627
+ }
628
+
629
+ .schema-branch {
630
+ opacity: 0.6;
631
+ font-family: var(--font-mono);
632
+ margin-right: 2px;
633
+ }
610
634
 
611
635
  /* Chips/Pills */
612
636
  .pill-checkbox { cursor: pointer; user-select: none; }
@@ -1141,30 +1165,209 @@ var DOCS_JS = `
1141
1165
  );
1142
1166
  }
1143
1167
 
1144
- function renderSchemaTable(node, title) {
1145
- let rows = '';
1146
- if (node.kind === 'object' && node.properties) {
1147
- Object.keys(node.properties).forEach(function(key) {
1148
- const prop = node.properties[key];
1149
- const reqClass = prop.optional ? 'req-false' : 'req-true';
1150
- const reqText = prop.optional ? 'OPT' : 'REQ';
1151
- rows +=
1152
- '<tr>' +
1153
- '<td class="col-name">' + escapeHtml(key) + '</td>' +
1154
- '<td class="col-type">' + escapeHtml(getTypeLabel(prop)) + '</td>' +
1155
- '<td><span class="req-badge ' + reqClass + '">' + reqText + '</span></td>' +
1156
- '<td>' + escapeHtml(prop.description || '') + '</td>' +
1157
- '</tr>';
1158
- });
1159
- } else {
1160
- rows = '<tr><td colspan="4">Type: ' + escapeHtml(getTypeLabel(node)) + '</td></tr>';
1168
+ // Recursive schema renderer with proper depth-based indentation.
1169
+
1170
+ function renderSchemaTable(node, title) {
1171
+ let rows = '';
1172
+
1173
+ if (node.kind === 'object' && node.properties) {
1174
+ // Start at depth -1 so first level of properties shows at depth 0
1175
+ rows = renderObjectChildren(node, -1);
1176
+ } else {
1177
+ rows = renderNodeRow('(root)', node, 0);
1178
+ }
1179
+
1180
+ return (
1181
+ (title
1182
+ ? '<div class="schema-subtitle">' + escapeHtml(title) + '</div>'
1183
+ : '') +
1184
+ '<table class="schema-table">' +
1185
+ rows +
1186
+ '</table>'
1187
+ );
1188
+ }
1189
+
1190
+ function renderObjectChildren(node, depth) {
1191
+ if (!node.properties) return '';
1192
+
1193
+ let rows = '';
1194
+ Object.keys(node.properties).forEach(function (key) {
1195
+ rows += renderNodeRow(key, node.properties[key], depth + 1);
1196
+ });
1197
+ return rows;
1198
+ }
1199
+
1200
+ function renderNodeRow(name, node, depth) {
1201
+ const reqClass = node.optional ? 'req-false' : 'req-true';
1202
+ const reqText = node.optional ? 'OPT' : 'REQ';
1203
+
1204
+ const indentPx = depth * 16; // increase this if you want more spacing per level
1205
+ const nameCell =
1206
+ '<span class="schema-indent" style="padding-left:' +
1207
+ indentPx +
1208
+ 'px;"></span>' +
1209
+ (depth > 0 ? '<span class="schema-branch">\u2514\u2500 </span>' : '') +
1210
+ escapeHtml(name);
1211
+
1212
+ const typeLabel = getTypeLabel(node);
1213
+ const descriptionHtml = renderNodeDescription(node);
1214
+
1215
+ let rows =
1216
+ '<tr>' +
1217
+ '<td class="col-name">' + nameCell + '</td>' +
1218
+ '<td class="col-type">' + escapeHtml(typeLabel) + '</td>' +
1219
+ '<td><span class="req-badge ' + reqClass + '">' + reqText + '</span></td>' +
1220
+ '<td>' + descriptionHtml + '</td>' +
1221
+ '</tr>';
1222
+
1223
+ // 1) Object properties
1224
+ if (node.kind === 'object' && node.properties) {
1225
+ rows += renderObjectChildren(node, depth);
1226
+ }
1227
+
1228
+ // 2) Array element type
1229
+ if (node.kind === 'array' && node.element) {
1230
+ const element = node.element;
1231
+ if (isComplexNode(element)) {
1232
+ // element rendered one level deeper than the array itself
1233
+ rows += renderNodeRow('[items]', element, depth + 1);
1161
1234
  }
1162
- return (
1163
- (title ? '<div class="schema-subtitle">' + escapeHtml(title) + '</div>' : '') +
1164
- '<table class="schema-table">' + rows + '</table>'
1235
+ }
1236
+
1237
+ // 3) Union variants
1238
+ if (node.kind === 'union' && Array.isArray(node.union)) {
1239
+ node.union.forEach(function (variant, index) {
1240
+ rows += renderNodeRow('option ' + (index + 1), variant, depth + 1);
1241
+ });
1242
+ }
1243
+
1244
+ return rows;
1245
+ }
1246
+
1247
+ /**
1248
+ * Decide if a node is \u201Ccomplex\u201D enough to warrant a nested expansion row.
1249
+ */
1250
+ function isComplexNode(node) {
1251
+ return (
1252
+ node.kind === 'object' ||
1253
+ node.kind === 'array' ||
1254
+ node.kind === 'union' ||
1255
+ node.kind === 'record' ||
1256
+ node.kind === 'tuple'
1257
+ );
1258
+ }
1259
+
1260
+ /**
1261
+ * Helper: simple vs complex node, for compact type labels.
1262
+ */
1263
+ function isSimpleNode(node) {
1264
+ return !isComplexNode(node);
1265
+ }
1266
+
1267
+ /**
1268
+ * Type label shown in the "Type" column.
1269
+ */
1270
+ function getTypeLabel(node) {
1271
+ let base;
1272
+
1273
+ switch (node.kind) {
1274
+ case 'object':
1275
+ base = 'object';
1276
+ break;
1277
+
1278
+ case 'array':
1279
+ if (!node.element) {
1280
+ base = 'array';
1281
+ } else if (isSimpleNode(node.element)) {
1282
+ base = 'array<' + getTypeLabel(node.element) + '>';
1283
+ } else {
1284
+ base = 'array<object>';
1285
+ }
1286
+ break;
1287
+
1288
+ case 'union':
1289
+ if (node.union && node.union.length) {
1290
+ const parts = node.union.map(function (u) {
1291
+ return isSimpleNode(u) ? getTypeLabel(u) : 'object';
1292
+ });
1293
+ base = parts.join(' | ');
1294
+ } else {
1295
+ base = 'union';
1296
+ }
1297
+ break;
1298
+
1299
+ case 'literal':
1300
+ base = 'literal';
1301
+ break;
1302
+
1303
+ case 'enum':
1304
+ base = 'enum';
1305
+ break;
1306
+
1307
+ case 'record':
1308
+ base = 'record';
1309
+ break;
1310
+
1311
+ case 'tuple':
1312
+ base = 'tuple';
1313
+ break;
1314
+
1315
+ default:
1316
+ base = node.kind || 'unknown';
1317
+ break;
1318
+ }
1319
+
1320
+ if (node.nullable) {
1321
+ base = base + ' | null';
1322
+ }
1323
+ return base;
1324
+ }
1325
+
1326
+ /**
1327
+ * Description cell content:
1328
+ * - main description text
1329
+ * - for enum: allowed values
1330
+ * - for literal: literal value
1331
+ */
1332
+ function renderNodeDescription(node) {
1333
+ const parts = [];
1334
+
1335
+ if (node.description) {
1336
+ parts.push(escapeHtml(node.description));
1337
+ }
1338
+
1339
+ if (node.kind === 'enum' && node.enumValues && node.enumValues.length) {
1340
+ const values = node.enumValues
1341
+ .map(function (v) {
1342
+ return '<code>' + escapeHtml(String(v)) + '</code>';
1343
+ })
1344
+ .join(' | ');
1345
+ parts.push('<div class="schema-meta">Allowed: ' + values + '</div>');
1346
+ }
1347
+
1348
+ if (node.kind === 'literal' && typeof node.literal !== 'undefined') {
1349
+ const valueStr = escapeHtml(JSON.stringify(node.literal));
1350
+ parts.push(
1351
+ '<div class="schema-meta">Literal: <code>' + valueStr + '</code></div>'
1165
1352
  );
1166
1353
  }
1167
1354
 
1355
+ return parts.join('<br>');
1356
+ }
1357
+
1358
+ /**
1359
+ * Escape HTML helper.
1360
+ */
1361
+ function escapeHtml(str) {
1362
+ return String(str)
1363
+ .replace(/&/g, '&amp;')
1364
+ .replace(/</g, '&lt;')
1365
+ .replace(/>/g, '&gt;')
1366
+ .replace(/"/g, '&quot;')
1367
+ .replace(/'/g, '&#39;');
1368
+ }
1369
+
1370
+
1168
1371
  function getTypeLabel(node) {
1169
1372
  if (!node) return 'any';
1170
1373
  if (node.kind === 'array') return getTypeLabel(node.element) + '[]';