@emeryld/rrroutes-contract 2.7.10 → 2.7.12

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 CHANGED
@@ -459,7 +459,7 @@ How to use:
459
459
  1. Generate an export JSON with `export:finalized-leaves`.
460
460
  2. Open the HTML file in your browser.
461
461
  3. Load the JSON file using the file picker.
462
- 4. Use the single search textbox + field checkboxes to filter routes.
462
+ 4. Use the search box, quick filter toggles, grouped field chips, and advanced filter panel to filter routes.
463
463
 
464
464
  Each result is rendered as a collapsible block with title `METHOD path`.
465
465
 
@@ -1 +1 @@
1
- export declare const DEFAULT_VIEWER_TEMPLATE = "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Finalized Leaves Viewer</title>\n <style>\n :root {\n --bg: #212121;\n --surface: #2a2a2a;\n --border: #4a4a4a;\n --text: #fffafa;\n --muted: #c8c2c2;\n --accent: #a764d3;\n }\n body {\n margin: 0;\n font-family: 'Iosevka Web', 'SFMono-Regular', Menlo, Consolas, monospace;\n color: var(--text);\n background: var(--bg);\n }\n .wrap { max-width: 1100px; margin: 0 auto; padding: 20px; }\n .card { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 14px; }\n .meta { color: var(--muted); font-size: 12px; }\n #results { margin-top: 12px; display: grid; gap: 8px; }\n details { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 8px 10px; }\n summary { cursor: pointer; font-weight: 700; color: var(--accent); }\n pre { margin: 10px 0 0; overflow: auto; border: 1px solid var(--border); border-radius: 8px; padding: 10px; background: #303030; color: var(--text); }\n </style>\n </head>\n <body>\n <div class=\"wrap\">\n <h1>Finalized Leaves Viewer (Baked)</h1>\n <div class=\"card\">\n <div id=\"status\" class=\"meta\">Waiting for baked payload...</div>\n </div>\n <div id=\"results\"></div>\n </div>\n\n <!--__FINALIZED_LEAVES_BAKED_PAYLOAD__-->\n\n <script>\n const statusEl = document.getElementById('status')\n const resultsEl = document.getElementById('results')\n const payload = window.__FINALIZED_LEAVES_PAYLOAD\n\n if (!payload || !Array.isArray(payload.leaves)) {\n statusEl.textContent = 'No baked payload found in this HTML file.'\n } else {\n statusEl.textContent = 'Loaded baked payload with ' + payload.leaves.length + ' routes.'\n\n const toHref = (source) => {\n if (!source || !source.file) return null\n const normalizedPath = String(source.file).replace(/\\\\/g, '/')\n const prefix = normalizedPath.startsWith('/') ? 'file://' : 'file:///'\n return prefix + encodeURI(normalizedPath)\n }\n\n const sourceDisplay = (source) => {\n return ''\n }\n\n payload.leaves.forEach((leaf) => {\n const details = document.createElement('details')\n const summary = document.createElement('summary')\n summary.textContent = String(leaf.method || '').toUpperCase() + ' ' + (leaf.path || '')\n\n const pre = document.createElement('pre')\n pre.textContent = JSON.stringify(leaf, null, 2)\n\n const source = payload.sourceByLeaf && payload.sourceByLeaf[leaf.key]\n let sourceWrap = null\n if (source) {\n sourceWrap = document.createElement('div')\n sourceWrap.className = 'meta'\n\n const definitionHref = toHref(source.definition)\n if (definitionHref) {\n const label = document.createElement('div')\n const link = document.createElement('a')\n link.href = definitionHref\n link.target = '_blank'\n link.rel = 'noopener noreferrer'\n link.textContent = 'definition'\n label.appendChild(link)\n sourceWrap.appendChild(label)\n }\n\n if (source.schemas && typeof source.schemas === 'object') {\n Object.entries(source.schemas).forEach(([name, schema]) => {\n if (!schema) return\n const href = toHref(schema)\n const row = document.createElement('div')\n if (href) {\n const link = document.createElement('a')\n link.href = href\n link.target = '_blank'\n link.rel = 'noopener noreferrer'\n link.textContent =\n name + ': ' + (schema.sourceName || schema.tag || '<anonymous>')\n row.appendChild(link)\n } else {\n row.textContent = name + ': ' + (schema.sourceName || schema.tag || '<anonymous>')\n }\n sourceWrap.appendChild(row)\n })\n }\n\n }\n\n details.appendChild(summary)\n if (sourceWrap) details.appendChild(sourceWrap)\n details.appendChild(pre)\n resultsEl.appendChild(details)\n })\n }\n </script>\n </body>\n</html>\n";
1
+ export declare const DEFAULT_VIEWER_TEMPLATE = "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Finalized Leaves Viewer</title>\n <style>\n :root {\n --bg: #212121;\n --surface: #2a2a2a;\n --border: #4a4a4a;\n --text: #fffafa;\n --muted: #c8c2c2;\n --accent: #a764d3;\n }\n body {\n margin: 0;\n font-family: 'Iosevka Web', 'SFMono-Regular', Menlo, Consolas, monospace;\n color: var(--text);\n background: var(--bg);\n }\n .wrap { max-width: 1100px; margin: 0 auto; padding: 20px; }\n .card { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 14px; }\n .meta { color: var(--muted); font-size: 12px; }\n #results { margin-top: 12px; display: grid; gap: 8px; }\n details { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 8px 10px; }\n summary { cursor: pointer; font-weight: 700; color: var(--accent); }\n pre { margin: 10px 0 0; overflow: auto; border: 1px solid var(--border); border-radius: 8px; padding: 10px; background: #303030; color: var(--text); }\n </style>\n </head>\n <body>\n <div class=\"wrap\">\n <h1>Finalized Leaves Viewer (Baked)</h1>\n <div class=\"card\">\n <div id=\"status\" class=\"meta\">Waiting for baked payload...</div>\n </div>\n <div id=\"results\"></div>\n </div>\n\n <!--__FINALIZED_LEAVES_BAKED_PAYLOAD__-->\n\n <script>\n const statusEl = document.getElementById('status')\n const resultsEl = document.getElementById('results')\n const payload = window.__FINALIZED_LEAVES_PAYLOAD\n\n if (!payload || !Array.isArray(payload.leaves)) {\n statusEl.textContent = 'No baked payload found in this HTML file.'\n } else {\n statusEl.textContent = 'Loaded baked payload with ' + payload.leaves.length + ' routes.'\n\n const toHref = (source) => {\n if (!source || !source.file) return null\n const normalizedPath = String(source.file).replace(/\\\\/g, '/')\n const platform =\n (navigator.userAgentData && navigator.userAgentData.platform) ||\n navigator.platform ||\n ''\n const isWindows = /win/i.test(platform)\n const vscodePath = isWindows\n ? normalizedPath.replace(/^\\/+/, '')\n : normalizedPath.startsWith('/')\n ? normalizedPath\n : '/' + normalizedPath\n const line = Number.isFinite(source.line) ? source.line : 1\n const column = Number.isFinite(source.column) ? source.column : 1\n return 'vscode://file/' + encodeURI(vscodePath) + ':' + line + ':' + column\n }\n\n const sourceDisplay = (source) => {\n return ''\n }\n\n payload.leaves.forEach((leaf) => {\n const details = document.createElement('details')\n const summary = document.createElement('summary')\n summary.textContent = String(leaf.method || '').toUpperCase() + ' ' + (leaf.path || '')\n\n const pre = document.createElement('pre')\n pre.textContent = JSON.stringify(leaf, null, 2)\n\n const source = payload.sourceByLeaf && payload.sourceByLeaf[leaf.key]\n let sourceWrap = null\n if (source) {\n sourceWrap = document.createElement('div')\n sourceWrap.className = 'meta'\n\n const definitionHref = toHref(source.definition)\n if (definitionHref) {\n const label = document.createElement('div')\n const link = document.createElement('a')\n link.href = definitionHref\n link.target = '_blank'\n link.rel = 'noopener noreferrer'\n link.textContent = 'definition'\n label.appendChild(link)\n sourceWrap.appendChild(label)\n }\n\n if (source.schemas && typeof source.schemas === 'object') {\n Object.entries(source.schemas).forEach(([name, schema]) => {\n if (!schema) return\n const href = toHref(schema)\n const row = document.createElement('div')\n if (href) {\n const link = document.createElement('a')\n link.href = href\n link.target = '_blank'\n link.rel = 'noopener noreferrer'\n link.textContent =\n name + ': ' + (schema.sourceName || schema.tag || '<anonymous>')\n row.appendChild(link)\n } else {\n row.textContent = name + ': ' + (schema.sourceName || schema.tag || '<anonymous>')\n }\n sourceWrap.appendChild(row)\n })\n }\n\n }\n\n details.appendChild(summary)\n if (sourceWrap) details.appendChild(sourceWrap)\n details.appendChild(pre)\n resultsEl.appendChild(details)\n })\n }\n </script>\n </body>\n</html>\n";
@@ -5,6 +5,7 @@ export type FlatSchemaEntry = {
5
5
  type: string;
6
6
  nullable: boolean;
7
7
  optional: boolean;
8
+ literal?: unknown;
8
9
  };
9
10
  export type FlatSchemaMap = Record<string, FlatSchemaEntry>;
10
11
  export declare function flattenSerializableSchema(schema: SerializableSchema | undefined, path: string): FlatSchemaMap;
package/dist/index.cjs CHANGED
@@ -657,6 +657,24 @@ function serializeLeavesContract(leaves, options = {}) {
657
657
  }
658
658
 
659
659
  // src/export/flattenSchema.ts
660
+ function formatLiteralType(literal) {
661
+ if (typeof literal === "string") return literal;
662
+ if (typeof literal === "number" || typeof literal === "boolean" || typeof literal === "bigint") {
663
+ return String(literal);
664
+ }
665
+ if (literal === null) return "null";
666
+ if (Array.isArray(literal)) {
667
+ return literal.map((item) => formatLiteralType(item)).join("|");
668
+ }
669
+ if (typeof literal === "object") {
670
+ try {
671
+ return JSON.stringify(literal);
672
+ } catch {
673
+ return "object";
674
+ }
675
+ }
676
+ return "unknown";
677
+ }
660
678
  function normalizeType(schema) {
661
679
  switch (schema.kind) {
662
680
  case "string":
@@ -673,11 +691,7 @@ function normalizeType(schema) {
673
691
  return "unknown";
674
692
  }
675
693
  case "literal": {
676
- const lit = schema.literal;
677
- if (typeof lit === "string") return "string";
678
- if (typeof lit === "number") return "number";
679
- if (typeof lit === "boolean") return "boolean";
680
- return "unknown";
694
+ return formatLiteralType(schema.literal);
681
695
  }
682
696
  default:
683
697
  return "unknown";
@@ -691,7 +705,8 @@ function setNode(out, path4, schema, inherited) {
691
705
  out[path4] = {
692
706
  type: normalizeType(schema),
693
707
  nullable: inherited.nullable || Boolean(schema.nullable),
694
- optional: inherited.optional || Boolean(schema.optional)
708
+ optional: inherited.optional || Boolean(schema.optional),
709
+ literal: schema.kind === "literal" ? schema.literal : void 0
695
710
  };
696
711
  }
697
712
  function flattenInto(out, schema, path4, inherited) {
@@ -800,8 +815,19 @@ var DEFAULT_VIEWER_TEMPLATE = `<!doctype html>
800
815
  const toHref = (source) => {
801
816
  if (!source || !source.file) return null
802
817
  const normalizedPath = String(source.file).replace(/\\\\/g, '/')
803
- const prefix = normalizedPath.startsWith('/') ? 'file://' : 'file:///'
804
- return prefix + encodeURI(normalizedPath)
818
+ const platform =
819
+ (navigator.userAgentData && navigator.userAgentData.platform) ||
820
+ navigator.platform ||
821
+ ''
822
+ const isWindows = /win/i.test(platform)
823
+ const vscodePath = isWindows
824
+ ? normalizedPath.replace(/^\\/+/, '')
825
+ : normalizedPath.startsWith('/')
826
+ ? normalizedPath
827
+ : '/' + normalizedPath
828
+ const line = Number.isFinite(source.line) ? source.line : 1
829
+ const column = Number.isFinite(source.column) ? source.column : 1
830
+ return 'vscode://file/' + encodeURI(vscodePath) + ':' + line + ':' + column
805
831
  }
806
832
 
807
833
  const sourceDisplay = (source) => {
@@ -1450,7 +1476,7 @@ function buildMeta(sourceExtraction) {
1450
1476
  "literal?",
1451
1477
  "enumValues?"
1452
1478
  ],
1453
- flatSchemaEntry: ["type", "nullable", "optional"]
1479
+ flatSchemaEntry: ["type", "nullable", "optional", "literal?"]
1454
1480
  },
1455
1481
  flattening: {
1456
1482
  notation: "dot+[]",