@rapidoc/prerender 0.1.2 → 0.1.3

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 (2) hide show
  1. package/dist/index.js +169 -62
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1335,20 +1335,128 @@ function mergePropertyExamples(obj, propertyName, propExamples) {
1335
1335
  for (const exampleKey in obj) if (obj[exampleKey] && typeof obj[exampleKey] === "object") obj[exampleKey][propertyName] = propVal;
1336
1336
  return obj;
1337
1337
  }
1338
+ var ANY_TRUE_KEYWORDS = /* @__PURE__ */ new Set([
1339
+ "readOnly",
1340
+ "writeOnly",
1341
+ "deprecated",
1342
+ "nullable"
1343
+ ]);
1344
+ var FIRST_WINS_KEYWORDS = /* @__PURE__ */ new Set(["title", "description"]);
1345
+ var CONTENT_KEYWORDS = [
1346
+ "type",
1347
+ "properties",
1348
+ "patternProperties",
1349
+ "additionalProperties",
1350
+ "items",
1351
+ "enum",
1352
+ "const",
1353
+ "format"
1354
+ ];
1355
+ var flattenedAllOf = /* @__PURE__ */ new WeakMap();
1356
+ function withoutKeys(obj, keys) {
1357
+ const copy = { ...obj };
1358
+ keys.forEach((key) => delete copy[key]);
1359
+ return copy;
1360
+ }
1361
+ function pickKeys(obj, keys) {
1362
+ const picked = {};
1363
+ keys.forEach((key) => {
1364
+ if (obj[key] !== void 0) picked[key] = obj[key];
1365
+ });
1366
+ return picked;
1367
+ }
1368
+ var allOfInProgress = /* @__PURE__ */ new Set();
1369
+ function mergeTwoSchemas(a, b) {
1370
+ if (a === b || !a || typeof a !== "object") return b;
1371
+ if (!b || typeof b !== "object") return a;
1372
+ return flattenAllOf({ allOf: [a, b] });
1373
+ }
1374
+ function mergeSchemaKeywords(into, from, isOwn) {
1375
+ for (const key in from) {
1376
+ const value = from[key];
1377
+ if (key === "allOf" || value === void 0 || key === "x-ref" && !isOwn) continue;
1378
+ if (key === "required") {
1379
+ if (Array.isArray(value)) into.required = [.../* @__PURE__ */ new Set([...into.required || [], ...value])];
1380
+ } else if (key === "properties" || key === "patternProperties") {
1381
+ const merged = { ...into[key] };
1382
+ for (const name in value) merged[name] = name in merged ? mergeTwoSchemas(merged[name], value[name]) : value[name];
1383
+ into[key] = merged;
1384
+ } else if (key === "items" || key === "additionalProperties") into[key] = typeof into[key] === "object" && typeof value === "object" ? mergeTwoSchemas(into[key], value) : value;
1385
+ else if (ANY_TRUE_KEYWORDS.has(key)) into[key] = Boolean(into[key] || value);
1386
+ else if (FIRST_WINS_KEYWORDS.has(key)) {
1387
+ if (value !== "" && (isOwn || into[key] === void 0)) into[key] = value;
1388
+ } else into[key] = value;
1389
+ }
1390
+ }
1391
+ /**
1392
+ * Applies an allOf the way JSON Schema does: every member, and the schema's own keywords, hold for the
1393
+ * value. Members are merged in order (nested allOf first), the schema's own keywords last, so they win.
1394
+ * A property defined more than once becomes one property (later keywords win), `required` is the union,
1395
+ * and readOnly/writeOnly/deprecated/nullable are set when any member sets them. title and description
1396
+ * come from the schema itself, otherwise from the first member that has them.
1397
+ *
1398
+ * oneOf/anyOf members stay options. A single one with nothing else to merge becomes the result's
1399
+ * oneOf/anyOf. Otherwise the result keeps an allOf of the merged object part followed by those
1400
+ * members, and none of them has an allOf of its own.
1401
+ * @param {object} schema - OpenAPI/JSON Schema object
1402
+ * @returns {object} The schema itself when it has no allOf, otherwise a new merged schema (cached)
1403
+ */
1404
+ function flattenAllOf(schema) {
1405
+ if (!schema || typeof schema !== "object" || !Array.isArray(schema.allOf)) return schema;
1406
+ const cached = flattenedAllOf.get(schema);
1407
+ if (cached) return cached;
1408
+ if (allOfInProgress.has(schema)) return withoutKeys(schema, ["allOf"]);
1409
+ allOfInProgress.add(schema);
1410
+ try {
1411
+ const merged = {};
1412
+ const unions = [];
1413
+ const members = [...schema.allOf, withoutKeys(schema, ["allOf"])];
1414
+ members.forEach((member, i) => {
1415
+ if (!member || typeof member !== "object") return;
1416
+ const isOwn = i === members.length - 1;
1417
+ const flat = flattenAllOf(member);
1418
+ if (flat.allOf) {
1419
+ mergeSchemaKeywords(merged, flat, isOwn);
1420
+ unions.push(...flat.allOf.slice(1));
1421
+ } else if (flat.oneOf || flat.anyOf) {
1422
+ const optionKeys = [flat.oneOf ? "oneOf" : "anyOf", "discriminator"];
1423
+ mergeSchemaKeywords(merged, withoutKeys(flat, optionKeys), isOwn);
1424
+ unions.push(pickKeys(flat, [
1425
+ ...optionKeys,
1426
+ "title",
1427
+ "description"
1428
+ ]));
1429
+ } else mergeSchemaKeywords(merged, flat, isOwn);
1430
+ });
1431
+ const hasContent = CONTENT_KEYWORDS.some((key) => merged[key] !== void 0);
1432
+ if (merged.$ref && hasContent) delete merged.$ref;
1433
+ let result = merged;
1434
+ if (unions.length > 0) {
1435
+ if (unions.length === 1 && !hasContent) result = {
1436
+ ...unions[0],
1437
+ ...merged
1438
+ };
1439
+ else result = {
1440
+ ...merged,
1441
+ allOf: [pickKeys(merged, [...CONTENT_KEYWORDS, "required"]), ...unions]
1442
+ };
1443
+ }
1444
+ flattenedAllOf.set(schema, result);
1445
+ return result;
1446
+ } finally {
1447
+ allOfInProgress.delete(schema);
1448
+ }
1449
+ }
1450
+ function isObjectLikeSchema(schema) {
1451
+ return Boolean(schema.allOf || schema.type === "object" || schema.properties || schema.patternProperties || schema.additionalProperties && typeof schema.additionalProperties === "object");
1452
+ }
1338
1453
  function schemaToSampleObj(schema, config = {}, level = 0) {
1339
1454
  let obj = {};
1340
1455
  if (!schema || level > 8) return;
1456
+ if (schema.allOf && !isObjectLikeSchema(flattenAllOf(schema))) schema = flattenAllOf(schema);
1341
1457
  if (schema.allOf) {
1342
1458
  const mergedObj = {};
1343
- if (schema.allOf.length === 1 && !schema.allOf[0]?.properties && !schema.allOf[0]?.items) {
1344
- if (schema.allOf[0].$ref) return { "example-0": {} };
1345
- if (schema.allOf[0].readOnly && config.includeReadOnly) {
1346
- const tempSchema = schema.allOf[0];
1347
- return { "example-0": getSampleValueByType(tempSchema) };
1348
- }
1349
- return;
1350
- }
1351
- schema.allOf.forEach((v) => {
1459
+ [...schema.allOf, withoutKeys(schema, ["allOf"])].forEach((v) => {
1352
1460
  if (!v) return;
1353
1461
  if (v.type === "object" || v.properties || v.allOf || v.anyOf || v.oneOf) {
1354
1462
  const partialSamples = schemaToSampleObj(v, config, level + 1);
@@ -1368,9 +1476,10 @@ function schemaToSampleObj(schema, config = {}, level = 0) {
1368
1476
  } else if (schema.oneOf) {
1369
1477
  const objWithSchemaProps = {};
1370
1478
  if (schema.properties) for (const propertyName in schema.properties) {
1371
- const propSchema = schema.properties[propertyName];
1479
+ const rawPropSchema = schema.properties[propertyName];
1480
+ const propSchema = flattenAllOf(rawPropSchema);
1372
1481
  if (propSchema?.properties || propSchema?.items) {
1373
- const propSamples = schemaToSampleObj(propSchema, config, level + 1);
1482
+ const propSamples = schemaToSampleObj(rawPropSchema, config, level + 1);
1374
1483
  objWithSchemaProps[propertyName] = propSamples?.["example-0"] ?? propSamples;
1375
1484
  } else objWithSchemaProps[propertyName] = getSampleValueByType(propSchema);
1376
1485
  }
@@ -1396,13 +1505,14 @@ function schemaToSampleObj(schema, config = {}, level = 0) {
1396
1505
  } else if (schema.anyOf) {
1397
1506
  let commonObj = { "example-0": {} };
1398
1507
  if (schema.type === "object" || schema.properties) for (const propertyName in schema.properties) {
1399
- const propSchema = schema.properties[propertyName];
1508
+ const rawPropSchema = schema.properties[propertyName];
1509
+ const propSchema = flattenAllOf(rawPropSchema);
1400
1510
  if (propSchema?.deprecated && !config.includeDeprecated) continue;
1401
1511
  if (propSchema?.readOnly && !config.includeReadOnly) continue;
1402
1512
  if (propSchema?.writeOnly && !config.includeWriteOnly) continue;
1403
- const propExample = getFirstExample(propSchema);
1513
+ const propExample = getFirstExample(rawPropSchema);
1404
1514
  if (propExample !== void 0) commonObj["example-0"][propertyName] = propExample;
1405
- else mergePropertyExamples(commonObj, propertyName, schemaToSampleObj(propSchema, config, level + 1));
1515
+ else mergePropertyExamples(commonObj, propertyName, schemaToSampleObj(rawPropSchema, config, level + 1));
1406
1516
  }
1407
1517
  if (schema.anyOf.length > 0) {
1408
1518
  const variantsToProcess = level === 0 ? schema.anyOf : [schema.anyOf[0]];
@@ -1430,7 +1540,8 @@ function schemaToSampleObj(schema, config = {}, level = 0) {
1430
1540
  if (firstExample !== void 0) obj["example-0"] = firstExample;
1431
1541
  else {
1432
1542
  for (const propertyName in schema.properties) {
1433
- const propSchema = schema.properties[propertyName];
1543
+ const rawPropSchema = schema.properties[propertyName];
1544
+ const propSchema = flattenAllOf(rawPropSchema);
1434
1545
  if (!propSchema) continue;
1435
1546
  if (propSchema.deprecated && !config.includeDeprecated) continue;
1436
1547
  if (propSchema.readOnly && !config.includeReadOnly) continue;
@@ -1450,7 +1561,7 @@ function schemaToSampleObj(schema, config = {}, level = 0) {
1450
1561
  }
1451
1562
  continue;
1452
1563
  }
1453
- mergePropertyExamples(obj, propertyName, schemaToSampleObj(propSchema, config, level + 1));
1564
+ mergePropertyExamples(obj, propertyName, schemaToSampleObj(rawPropSchema, config, level + 1));
1454
1565
  }
1455
1566
  if (typeof schema.additionalProperties === "object" && schema.additionalProperties !== null) {
1456
1567
  const propName = schema.additionalProperties["x-additionalPropertiesName"] || "property";
@@ -1633,16 +1744,9 @@ function nodeToAST(schema, level, name, isRequired, suffix) {
1633
1744
  }
1634
1745
  function composeSchemaAST(schema, level, name, isRequired, suffix) {
1635
1746
  if (schema.allOf) {
1636
- if (schema.allOf.length === 1 && !schema.allOf[0].properties && !schema.allOf[0].items) {
1637
- const mergedSchema = {
1638
- ...schema.allOf[0],
1639
- ...schema,
1640
- title: schema.title || schema.allOf[0].title || "",
1641
- description: schema.description || schema.allOf[0].description || ""
1642
- };
1643
- delete mergedSchema.allOf;
1644
- return schemaToAST(mergedSchema, level, name, isRequired);
1645
- }
1747
+ const flat = flattenAllOf(schema);
1748
+ if (!flat.allOf) return schemaToAST(flat, level, name, isRequired, suffix);
1749
+ schema = flat;
1646
1750
  const mergedProps = [];
1647
1751
  const mergedPatternProps = [];
1648
1752
  let mergedAdditionalProps = null;
@@ -1954,23 +2058,14 @@ function getSchemaFromParam(param) {
1954
2058
  ];
1955
2059
  }
1956
2060
  var EMPTY_ARRAY = Object.freeze([]);
1957
- function getMergedProperties(schema, visited = /* @__PURE__ */ new Set()) {
1958
- if (!schema || typeof schema !== "object" || visited.has(schema)) return {};
1959
- visited.add(schema);
1960
- const properties = { ...schema.properties };
1961
- if (Array.isArray(schema.allOf)) schema.allOf.forEach((sub) => {
1962
- Object.assign(properties, getMergedProperties(sub, visited));
1963
- });
1964
- return properties;
1965
- }
1966
- function getMergedRequired(schema, visited = /* @__PURE__ */ new Set()) {
1967
- if (!schema || typeof schema !== "object" || visited.has(schema)) return [];
1968
- visited.add(schema);
1969
- const required = Array.isArray(schema.required) ? [...schema.required] : [];
1970
- if (Array.isArray(schema.allOf)) schema.allOf.forEach((sub) => {
1971
- required.push(...getMergedRequired(sub, visited));
1972
- });
1973
- return [...new Set(required)];
2061
+ function getMergedProperties(schema) {
2062
+ if (!schema || typeof schema !== "object") return {};
2063
+ return { ...flattenAllOf(schema).properties };
2064
+ }
2065
+ function getMergedRequired(schema) {
2066
+ if (!schema || typeof schema !== "object") return [];
2067
+ const { required } = flattenAllOf(schema);
2068
+ return Array.isArray(required) ? [...required] : [];
1974
2069
  }
1975
2070
  // ../rapidoc/src/utils/url-utils.js
1976
2071
  /**
@@ -9443,10 +9538,10 @@ function expandCollapseNavBarTag(navLinkEl, action = "toggle") {
9443
9538
  const isExpanded = tagAndPathEl.classList.contains("expanded");
9444
9539
  if (isExpanded && (action === "toggle" || action === "collapse")) {
9445
9540
  tagAndPathEl.classList.replace("expanded", "collapsed");
9446
- tagAndPathEl.querySelector(".nav-bar-tag")?.setAttribute("aria-expanded", "false");
9541
+ tagAndPathEl.querySelector(".nav-bar-tag-icon")?.setAttribute("aria-expanded", "false");
9447
9542
  } else if (!isExpanded && (action === "toggle" || action === "expand")) {
9448
9543
  tagAndPathEl.classList.replace("collapsed", "expanded");
9449
- tagAndPathEl.querySelector(".nav-bar-tag")?.setAttribute("aria-expanded", "true");
9544
+ tagAndPathEl.querySelector(".nav-bar-tag-icon")?.setAttribute("aria-expanded", "true");
9450
9545
  }
9451
9546
  }
9452
9547
  }
@@ -9497,9 +9592,11 @@ function expandCollapseAll$1(event, action = "expand-all") {
9497
9592
  const elList = [...navEl.querySelectorAll(".nav-bar-tag-and-paths")];
9498
9593
  if (action === "expand-all") elList.forEach((el) => {
9499
9594
  el.classList.replace("collapsed", "expanded");
9595
+ el.querySelector(".nav-bar-tag-icon")?.setAttribute("aria-expanded", "true");
9500
9596
  });
9501
9597
  else elList.forEach((el) => {
9502
9598
  el.classList.replace("expanded", "collapsed");
9599
+ el.querySelector(".nav-bar-tag-icon")?.setAttribute("aria-expanded", "false");
9503
9600
  });
9504
9601
  }
9505
9602
  function navBarClickAndEnterHandler(event) {
@@ -9694,14 +9791,20 @@ function navbarTemplate() {
9694
9791
  class="nav-bar-tag"
9695
9792
  part="section-navbar-item section-navbar-tag"
9696
9793
  id="link-${tag.elementId}"
9697
- data-action="expand-collapse-tag"
9794
+ data-action="navigate"
9795
+ data-content-id="${tag.elementId}"
9698
9796
  data-first-path-id="${firstPathId}"
9699
9797
  tabindex="0"
9700
- role="button"
9701
- aria-expanded="${tag.expanded ? "true" : "false"}"
9702
9798
  >
9703
9799
  <div class="nav-bar-tag-title">${tag.displayName || tag.name}</div>
9704
- <div class="nav-bar-tag-icon" tabindex="0" data-action="expand-collapse-tag"></div>
9800
+ <div
9801
+ class="nav-bar-tag-icon"
9802
+ tabindex="0"
9803
+ role="button"
9804
+ aria-label="Expand or collapse ${tag.displayName || tag.name}"
9805
+ aria-expanded="${tag.expanded ? "true" : "false"}"
9806
+ data-action="expand-collapse-tag"
9807
+ ></div>
9705
9808
  </div>
9706
9809
  ${this.infoDescriptionHeadingsInNavBar === "true" ? html` <div class="tag-headers">
9707
9810
  ${(() => {
@@ -13442,7 +13545,7 @@ function bindNavBar(sidebar, rapiDoc, options = {}) {
13442
13545
  else if (action === "navigate" || navEl.classList.contains("nav-bar-path") || navEl.classList.contains("nav-bar-info")) {
13443
13546
  const href = navEl.getAttribute("href") || navEl.getAttribute("data-tag-href");
13444
13547
  const hashIdx = href ? href.indexOf("#") : -1;
13445
- const elementId = (hashIdx !== -1 ? href.substring(hashIdx + 1) : href) || navEl.getAttribute("data-content-id") || navEl.getAttribute("data-op-slug") || navEl.id?.replace(/^link-/, "");
13548
+ const elementId = (hashIdx !== -1 ? href.substring(hashIdx + 1) : "") || navEl.getAttribute("data-content-id") || navEl.getAttribute("data-op-slug") || navEl.id?.replace(/^link-/, "");
13446
13549
  if (elementId && rapiDocEl && typeof rapiDocEl.scrollToPath === "function") {
13447
13550
  e.preventDefault();
13448
13551
  setActiveNavId(elementId, false);
@@ -13704,9 +13807,8 @@ function renderTag(tag, ctx) {
13704
13807
  const isExpanded = tag.expanded !== false;
13705
13808
  const pathsHtml = visiblePaths.map((op) => renderOperation(op, tagSlug, ctx)).join("");
13706
13809
  const tagHref = ctx.routingMode === "tag-pages" && tagSlug && tagSlug !== "general" ? `${ctx.cleanBase}/${tagSlug}` : `${ctx.basePath}#${elementId}`;
13707
- if (tag.descriptionOnly) {
13708
- const isActive = Boolean(ctx.activeHref && (ctx.activeHref === tagHref || ctx.activeHref.endsWith(`#${elementId}`)));
13709
- return `
13810
+ const isActive = Boolean(ctx.activeHref && (ctx.activeHref === tagHref || ctx.activeHref.endsWith(`#${elementId}`)));
13811
+ if (tag.descriptionOnly) return `
13710
13812
  <div class="nav-bar-tag-and-paths description-only">
13711
13813
  <a
13712
13814
  href="${escapeHtml(tagHref)}"
@@ -13720,21 +13822,26 @@ function renderTag(tag, ctx) {
13720
13822
  <span class="nav-bar-tag-title">${escapeHtml(title)}</span>
13721
13823
  </a>
13722
13824
  </div>`;
13723
- }
13724
13825
  return `
13725
- <div class="nav-bar-tag-and-paths ${isExpanded ? "expanded" : "collapsed"}" id="link-${elementId}">
13826
+ <div class="nav-bar-tag-and-paths ${isExpanded ? "expanded" : "collapsed"}">
13726
13827
  <div
13727
- class="nav-bar-tag"
13828
+ class="nav-bar-tag${isActive ? " active" : ""}"
13728
13829
  part="section-navbar-item section-navbar-tag"
13729
- id="link-${elementId}-header"
13730
- data-action="expand-collapse-tag"
13830
+ id="link-${elementId}"
13831
+ data-action="navigate"
13832
+ data-content-id="${elementId}"
13731
13833
  data-tag-href="${escapeHtml(tagHref)}"
13732
13834
  tabindex="0"
13733
- role="button"
13734
- aria-expanded="${isExpanded ? "true" : "false"}"
13735
13835
  >
13736
- <div class="nav-bar-tag-title" data-tag-href="${escapeHtml(tagHref)}">${escapeHtml(title)}</div>
13737
- <div class="nav-bar-tag-icon" tabindex="0" data-action="expand-collapse-tag"></div>
13836
+ <div class="nav-bar-tag-title">${escapeHtml(title)}</div>
13837
+ <div
13838
+ class="nav-bar-tag-icon"
13839
+ tabindex="0"
13840
+ role="button"
13841
+ aria-label="Expand or collapse ${escapeHtml(title)}"
13842
+ aria-expanded="${isExpanded ? "true" : "false"}"
13843
+ data-action="expand-collapse-tag"
13844
+ ></div>
13738
13845
  </div>
13739
13846
  <div class="nav-bar-paths-under-tag">
13740
13847
  ${pathsHtml}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rapidoc/prerender",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Renders RapiDoc API documentation to HTML at build time: pre-rendered <rapi-doc> (Declarative Shadow DOM or light DOM), sidebar navigation, Arazzo diagrams",
5
5
  "keywords": [
6
6
  "api-documentation",