@furystack/rest 8.0.42 → 8.1.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 (54) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/README.md +37 -1
  3. package/esm/api-endpoint-schema.d.ts +47 -2
  4. package/esm/api-endpoint-schema.d.ts.map +1 -1
  5. package/esm/index.d.ts +4 -1
  6. package/esm/index.d.ts.map +1 -1
  7. package/esm/index.js +4 -1
  8. package/esm/index.js.map +1 -1
  9. package/esm/openapi-document.d.ts +303 -0
  10. package/esm/openapi-document.d.ts.map +1 -0
  11. package/esm/openapi-document.js +2 -0
  12. package/esm/openapi-document.js.map +1 -0
  13. package/esm/openapi-resolve-refs.d.ts +20 -0
  14. package/esm/openapi-resolve-refs.d.ts.map +1 -0
  15. package/esm/openapi-resolve-refs.js +68 -0
  16. package/esm/openapi-resolve-refs.js.map +1 -0
  17. package/esm/openapi-resolve-refs.spec.d.ts +2 -0
  18. package/esm/openapi-resolve-refs.spec.d.ts.map +1 -0
  19. package/esm/openapi-resolve-refs.spec.js +294 -0
  20. package/esm/openapi-resolve-refs.spec.js.map +1 -0
  21. package/esm/openapi-to-rest-api.d.ts +197 -0
  22. package/esm/openapi-to-rest-api.d.ts.map +1 -0
  23. package/esm/openapi-to-rest-api.js +2 -0
  24. package/esm/openapi-to-rest-api.js.map +1 -0
  25. package/esm/openapi-to-rest-api.spec.d.ts +2 -0
  26. package/esm/openapi-to-rest-api.spec.d.ts.map +1 -0
  27. package/esm/openapi-to-rest-api.spec.js +665 -0
  28. package/esm/openapi-to-rest-api.spec.js.map +1 -0
  29. package/esm/openapi-to-schema.d.ts +24 -0
  30. package/esm/openapi-to-schema.d.ts.map +1 -0
  31. package/esm/openapi-to-schema.js +145 -0
  32. package/esm/openapi-to-schema.js.map +1 -0
  33. package/esm/openapi-to-schema.spec.d.ts +2 -0
  34. package/esm/openapi-to-schema.spec.d.ts.map +1 -0
  35. package/esm/openapi-to-schema.spec.js +610 -0
  36. package/esm/openapi-to-schema.spec.js.map +1 -0
  37. package/esm/rest-api.d.ts +21 -4
  38. package/esm/rest-api.d.ts.map +1 -1
  39. package/esm/swagger-document.d.ts +2 -195
  40. package/esm/swagger-document.d.ts.map +1 -1
  41. package/esm/swagger-document.js +2 -1
  42. package/esm/swagger-document.js.map +1 -1
  43. package/package.json +3 -3
  44. package/src/api-endpoint-schema.ts +56 -3
  45. package/src/index.ts +4 -1
  46. package/src/openapi-document.ts +328 -0
  47. package/src/openapi-resolve-refs.spec.ts +324 -0
  48. package/src/openapi-resolve-refs.ts +71 -0
  49. package/src/openapi-to-rest-api.spec.ts +823 -0
  50. package/src/openapi-to-rest-api.ts +263 -0
  51. package/src/openapi-to-schema.spec.ts +707 -0
  52. package/src/openapi-to-schema.ts +163 -0
  53. package/src/rest-api.ts +26 -5
  54. package/src/swagger-document.ts +2 -220
@@ -0,0 +1,71 @@
1
+ import type { OpenApiDocument } from './openapi-document.js'
2
+
3
+ /**
4
+ * Resolves an internal JSON Pointer (e.g. `#/components/schemas/User`) against a document tree.
5
+ */
6
+ const resolvePointer = (root: unknown, pointer: string): unknown => {
7
+ const segments = pointer
8
+ .replace(/^#\//, '')
9
+ .split('/')
10
+ .map((s) => s.replace(/~1/g, '/').replace(/~0/g, '~'))
11
+
12
+ let current: unknown = root
13
+ for (const segment of segments) {
14
+ if (current === null || current === undefined || typeof current !== 'object') return undefined
15
+ current = (current as Record<string, unknown>)[segment]
16
+ }
17
+ return current
18
+ }
19
+
20
+ /**
21
+ * Deep-walks a value and replaces all `{ $ref: "#/..." }` objects with the resolved target.
22
+ * Tracks visited `$ref` strings to prevent infinite loops from circular references.
23
+ */
24
+ const resolveNode = (node: unknown, root: unknown, visited: Set<string>): unknown => {
25
+ if (node === null || node === undefined || typeof node !== 'object') return node
26
+
27
+ if (Array.isArray(node)) {
28
+ return node.map((item) => resolveNode(item, root, visited))
29
+ }
30
+
31
+ const obj = node as Record<string, unknown>
32
+
33
+ if (typeof obj.$ref === 'string') {
34
+ const ref = obj.$ref
35
+ if (!ref.startsWith('#/')) return node
36
+ if (visited.has(ref)) return {}
37
+ visited.add(ref)
38
+ const resolved = resolvePointer(root, ref)
39
+ if (resolved === undefined) return node
40
+ const result = resolveNode(resolved, root, new Set(visited))
41
+ visited.delete(ref)
42
+ return result
43
+ }
44
+
45
+ const result: Record<string, unknown> = {}
46
+ for (const [key, value] of Object.entries(obj)) {
47
+ result[key] = resolveNode(value, root, visited)
48
+ }
49
+ return result
50
+ }
51
+
52
+ /**
53
+ * Resolves all internal `$ref` pointers in an OpenAPI document, inlining the referenced objects.
54
+ *
55
+ * Only internal references (`#/...`) are supported. External file references are left as-is.
56
+ * Circular references are broken by substituting an empty object `{}`.
57
+ *
58
+ * @param doc - The OpenAPI document with `$ref` pointers
59
+ * @returns A new OpenAPI document with all internal `$ref` pointers resolved
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * import { resolveOpenApiRefs } from '@furystack/rest'
64
+ *
65
+ * const resolved = resolveOpenApiRefs(myOpenApiDoc)
66
+ * // All $ref pointers have been replaced with the actual schemas
67
+ * ```
68
+ */
69
+ export const resolveOpenApiRefs = (doc: OpenApiDocument): OpenApiDocument => {
70
+ return resolveNode(structuredClone(doc), doc, new Set()) as OpenApiDocument
71
+ }