zudoku 0.0.0-z7b86faab → 0.0.0-z9d382b4a

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 (36) hide show
  1. package/dist/lib/oas/graphql/circular.d.ts +1 -1
  2. package/dist/lib/oas/graphql/circular.js +18 -35
  3. package/dist/lib/oas/graphql/circular.js.map +1 -1
  4. package/dist/lib/oas/graphql/circular.test.js +33 -2
  5. package/dist/lib/oas/graphql/circular.test.js.map +1 -1
  6. package/dist/lib/util/readFrontmatter.js +2 -1
  7. package/dist/lib/util/readFrontmatter.js.map +1 -1
  8. package/dist/vite/build.js +91 -73
  9. package/dist/vite/build.js.map +1 -1
  10. package/dist/vite/mdx/remark-inject-filepath.js +5 -1
  11. package/dist/vite/mdx/remark-inject-filepath.js.map +1 -1
  12. package/dist/vite/mdx/remark-link-rewrite.js +3 -2
  13. package/dist/vite/mdx/remark-link-rewrite.js.map +1 -1
  14. package/dist/vite/plugin-docs.js +9 -7
  15. package/dist/vite/plugin-docs.js.map +1 -1
  16. package/dist/vite/plugin-markdown-export.js +4 -2
  17. package/dist/vite/plugin-markdown-export.js.map +1 -1
  18. package/lib/{OasProvider-CS_ASmBB.js → OasProvider-B2KxIBsI.js} +2 -2
  19. package/lib/{OasProvider-CS_ASmBB.js.map → OasProvider-B2KxIBsI.js.map} +1 -1
  20. package/lib/{OperationList-Dq_AB4W9.js → OperationList-C2tAfThO.js} +3 -3
  21. package/lib/{OperationList-Dq_AB4W9.js.map → OperationList-C2tAfThO.js.map} +1 -1
  22. package/lib/{SchemaList-BJZJv1gD.js → SchemaList-Ep8DleP_.js} +3 -3
  23. package/lib/{SchemaList-BJZJv1gD.js.map → SchemaList-Ep8DleP_.js.map} +1 -1
  24. package/lib/{SchemaView-U4JMYB3N.js → SchemaView-BpaEKRYx.js} +2 -2
  25. package/lib/{SchemaView-U4JMYB3N.js.map → SchemaView-BpaEKRYx.js.map} +1 -1
  26. package/lib/{circular-BmMJjG1v.js → circular-CG3e0_Uz.js} +1327 -1346
  27. package/lib/{circular-BmMJjG1v.js.map → circular-CG3e0_Uz.js.map} +1 -1
  28. package/lib/{createServer-CLSZ7hWJ.js → createServer-CNeRqj98.js} +3 -3
  29. package/lib/{createServer-CLSZ7hWJ.js.map → createServer-CNeRqj98.js.map} +1 -1
  30. package/lib/{index-O9RHI87z.js → index-I3kmZ7tG.js} +6 -6
  31. package/lib/{index-O9RHI87z.js.map → index-I3kmZ7tG.js.map} +1 -1
  32. package/lib/zudoku.plugin-openapi.js +1 -1
  33. package/package.json +2 -2
  34. package/src/lib/oas/graphql/circular.test.ts +37 -2
  35. package/src/lib/oas/graphql/circular.ts +25 -51
  36. package/src/lib/util/readFrontmatter.ts +2 -1
@@ -3,7 +3,7 @@ import "lucide-react";
3
3
  import "./chunk-EPOLDU6W-C6C8jAwd.js";
4
4
  import "./ui/Button.js";
5
5
  import "./ZudokuContext-BZB1TWdT.js";
6
- import { y as e, U as n, z as s } from "./index-O9RHI87z.js";
6
+ import { y as e, U as n, z as s } from "./index-I3kmZ7tG.js";
7
7
  export {
8
8
  e as GetNavigationOperationsQuery,
9
9
  n as UNTAGGED_PATH,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zudoku",
3
- "version": "0.0.0-z7b86faab",
3
+ "version": "0.0.0-z9d382b4a",
4
4
  "type": "module",
5
5
  "homepage": "https://zudoku.dev",
6
6
  "repository": {
@@ -233,7 +233,7 @@
233
233
  "pagefind": "1.5.0-beta.1",
234
234
  "picocolors": "1.1.1",
235
235
  "piscina": "5.1.4",
236
- "posthog-node": "5.14.1",
236
+ "posthog-node": "5.21.2",
237
237
  "react-error-boundary": "6.0.0",
238
238
  "react-hook-form": "7.66.0",
239
239
  "react-is": "19.2.3",
@@ -156,16 +156,20 @@ describe("handleCircularRefs", () => {
156
156
  });
157
157
  });
158
158
 
159
- it("should deduplicate shared object instances with __$ref", () => {
159
+ it("should handle shared object instances with __$ref without marking circular", () => {
160
160
  const shared = { __$ref: "#/components/schemas/Foo", type: "string" };
161
161
  const obj = { a: shared, b: shared };
162
162
  const result = handleCircularRefs(obj);
163
163
 
164
+ // Both should return the cached result, not mark as circular
164
165
  expect(result.a).toEqual({
165
166
  __$ref: "#/components/schemas/Foo",
166
167
  type: "string",
167
168
  });
168
- expect(result.b).toBe(`${SCHEMA_REF_PREFIX}#/components/schemas/Foo`);
169
+ expect(result.b).toEqual({
170
+ __$ref: "#/components/schemas/Foo",
171
+ type: "string",
172
+ });
169
173
  });
170
174
 
171
175
  it("should mark circular ref with property name from path", () => {
@@ -183,4 +187,35 @@ describe("handleCircularRefs", () => {
183
187
 
184
188
  expect(result.properties.child.properties.back).toContain(CIRCULAR_REF);
185
189
  });
190
+
191
+ // Exact reproduction of #1869 - shared object instances with __$ref
192
+ it("should NOT mark shared object instances with __$ref as circular (issue #1869)", () => {
193
+ // When dereferencing, the SAME object instance is returned for all refs to the same schema
194
+ const timestampSchema = {
195
+ __$ref: "#/components/schemas/timestamp",
196
+ type: "string",
197
+ format: "date-time",
198
+ };
199
+
200
+ // Both created_at and updated_at point to the SAME object instance
201
+ const obj = {
202
+ type: "object",
203
+ properties: {
204
+ created_at: timestampSchema,
205
+ updated_at: timestampSchema,
206
+ },
207
+ };
208
+
209
+ const result = handleCircularRefs(obj);
210
+
211
+ // The first one should be fully expanded
212
+ expect(result.properties.created_at).toEqual({
213
+ __$ref: "#/components/schemas/timestamp",
214
+ type: "string",
215
+ format: "date-time",
216
+ });
217
+ // The second one should ALSO be fully expanded (not marked as circular)
218
+ expect(typeof result.properties.updated_at).toBe("object");
219
+ expect(result.properties.updated_at).not.toContain(CIRCULAR_REF);
220
+ });
186
221
  });
@@ -1,6 +1,5 @@
1
1
  import { GraphQLScalarType } from "graphql/index.js";
2
2
  import { GraphQLJSON } from "graphql-type-json";
3
- import type { RecordAny } from "../../util/traverse.js";
4
3
 
5
4
  export const CIRCULAR_REF = "$[Circular Reference]";
6
5
  export const SCHEMA_REF_PREFIX = "$ref:";
@@ -17,73 +16,48 @@ const OPENAPI_PROPS = new Set([
17
16
  export const handleCircularRefs = (
18
17
  // biome-ignore lint/suspicious/noExplicitAny: Allow any type
19
18
  obj: any,
20
- visited = new WeakSet(),
19
+ currentPath = new WeakSet(),
21
20
  refs = new WeakMap(),
22
21
  path: string[] = [],
23
- seenRefPaths = new Set<string>(),
22
+ currentRefPaths = new Set<string>(),
24
23
  // biome-ignore lint/suspicious/noExplicitAny: Allow any type
25
24
  ): any => {
26
25
  if (obj === null || typeof obj !== "object") return obj;
27
26
 
28
27
  const refPath = obj.__$ref;
28
+ const isCircular =
29
+ currentPath.has(obj) ||
30
+ (typeof refPath === "string" && currentRefPaths.has(refPath));
29
31
 
30
- // Check if this object has a __$ref marker (set during schema code generation)
31
- // If we've already fully processed this ref path, return a reference marker
32
- // instead of the full data to avoid JSON.stringify serializing duplicates
33
- if (typeof refPath === "string" && seenRefPaths.has(refPath)) {
34
- return SCHEMA_REF_PREFIX + refPath;
35
- }
36
-
37
- if (visited.has(obj)) {
38
- const cached = refs.get(obj);
39
- if (cached) {
40
- return typeof refPath === "string"
41
- ? // If already processed, return ref marker to avoid duplicate serialization
42
- SCHEMA_REF_PREFIX + refPath
43
- : cached;
44
- }
32
+ if (isCircular) {
33
+ if (typeof refPath === "string") return SCHEMA_REF_PREFIX + refPath;
45
34
  const circularProp = path.find((p) => !OPENAPI_PROPS.has(p)) || path[0];
46
-
47
35
  return [CIRCULAR_REF, circularProp].filter(Boolean).join(":");
48
36
  }
49
37
 
50
- visited.add(obj);
38
+ if (refs.has(obj)) return refs.get(obj);
51
39
 
52
- // Add refPath BEFORE recursing to detect cycles within this branch
53
- // This will be removed after processing to allow siblings with the same ref
54
- if (typeof refPath === "string") {
55
- seenRefPaths.add(refPath);
56
- }
40
+ currentPath.add(obj);
41
+ if (typeof refPath === "string") currentRefPaths.add(refPath);
57
42
 
58
- let result: RecordAny | RecordAny[];
59
- if (Array.isArray(obj)) {
60
- result = obj.map((item, index) =>
61
- handleCircularRefs(
62
- item,
63
- visited,
64
- refs,
65
- [...path, index.toString()],
66
- seenRefPaths,
67
- ),
43
+ const recurse = (value: unknown, key: string) =>
44
+ handleCircularRefs(
45
+ value,
46
+ currentPath,
47
+ refs,
48
+ [...path, key],
49
+ currentRefPaths,
68
50
  );
69
- } else {
70
- result = {};
71
- for (const [key, value] of Object.entries(obj)) {
72
- result[key] = handleCircularRefs(
73
- value,
74
- visited,
75
- refs,
76
- [...path, key],
77
- seenRefPaths,
51
+
52
+ const result = Array.isArray(obj)
53
+ ? obj.map((item, i) => recurse(item, i.toString()))
54
+ : Object.fromEntries(
55
+ Object.entries(obj).map(([k, v]) => [k, recurse(v, k)]),
78
56
  );
79
- }
80
- }
81
- refs.set(obj, result);
82
57
 
83
- // Remove refPath after processing so sibling refs aren't incorrectly marked
84
- if (typeof refPath === "string") {
85
- seenRefPaths.delete(refPath);
86
- }
58
+ refs.set(obj, result);
59
+ currentPath.delete(obj);
60
+ if (typeof refPath === "string") currentRefPaths.delete(refPath);
87
61
 
88
62
  return result;
89
63
  };
@@ -9,5 +9,6 @@ export const yaml = {
9
9
 
10
10
  export const readFrontmatter = async (filePath: string) => {
11
11
  const content = await readFile(filePath, "utf-8");
12
- return matter(content, { engines: { yaml } });
12
+ const normalizedContent = content.replace(/\r\n/g, "\n");
13
+ return matter(normalizedContent, { engines: { yaml } });
13
14
  };