docusaurus-theme-openapi-docs 5.0.2 → 5.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 (143) hide show
  1. package/lib/markdown/schema.js +38 -15
  2. package/lib/markdown/schema.test.d.ts +1 -0
  3. package/lib/markdown/schema.test.js +86 -0
  4. package/lib/theme/ApiExplorer/ApiCodeBlock/Container/index.js +4 -2
  5. package/lib/theme/ApiExplorer/ApiCodeBlock/Content/String.js +9 -6
  6. package/lib/theme/ApiExplorer/ApiCodeBlock/Line/index.d.ts +1 -1
  7. package/lib/theme/ApiExplorer/ApiCodeBlock/index.d.ts +1 -1
  8. package/lib/theme/ApiExplorer/Authorization/index.js +9 -10
  9. package/lib/theme/ApiExplorer/Body/index.js +4 -5
  10. package/lib/theme/ApiExplorer/CodeSnippets/index.js +96 -61
  11. package/lib/theme/ApiExplorer/CodeSnippets/languages.js +12 -1
  12. package/lib/theme/ApiExplorer/CodeSnippets/languages.test.d.ts +1 -0
  13. package/lib/theme/ApiExplorer/CodeSnippets/languages.test.js +102 -0
  14. package/lib/theme/ApiExplorer/CodeTabs/index.d.ts +1 -1
  15. package/lib/theme/ApiExplorer/CodeTabs/index.js +6 -5
  16. package/lib/theme/ApiExplorer/Export/index.js +9 -2
  17. package/lib/theme/ApiExplorer/FormFileUpload/index.js +1 -2
  18. package/lib/theme/ApiExplorer/FormLabel/index.js +1 -2
  19. package/lib/theme/ApiExplorer/FormTextInput/index.js +1 -2
  20. package/lib/theme/ApiExplorer/LiveEditor/index.js +1 -2
  21. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamArrayFormItem.js +5 -3
  22. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.js +75 -4
  23. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.js +1 -2
  24. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.js +67 -4
  25. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamTextFormItem.js +65 -1
  26. package/lib/theme/ApiExplorer/ParamOptions/index.js +2 -3
  27. package/lib/theme/ApiExplorer/Request/index.js +17 -18
  28. package/lib/theme/ApiExplorer/Response/index.js +54 -12
  29. package/lib/theme/ApiExplorer/SecuritySchemes/index.js +57 -50
  30. package/lib/theme/ApiExplorer/Server/index.js +2 -3
  31. package/lib/theme/ApiItem/index.js +59 -33
  32. package/lib/theme/ApiTabs/index.d.ts +1 -1
  33. package/lib/theme/ApiTabs/index.js +7 -7
  34. package/lib/theme/DiscriminatorTabs/index.d.ts +1 -1
  35. package/lib/theme/DiscriminatorTabs/index.js +6 -5
  36. package/lib/theme/Example/index.js +3 -4
  37. package/lib/theme/MimeTabs/index.d.ts +1 -1
  38. package/lib/theme/MimeTabs/index.js +6 -5
  39. package/lib/theme/OperationTabs/index.d.ts +1 -1
  40. package/lib/theme/OperationTabs/index.js +6 -5
  41. package/lib/theme/ParamsDetails/index.js +1 -2
  42. package/lib/theme/ParamsItem/index.js +7 -8
  43. package/lib/theme/RequestSchema/index.js +57 -57
  44. package/lib/theme/ResponseExamples/index.js +3 -4
  45. package/lib/theme/ResponseSchema/index.js +26 -24
  46. package/lib/theme/Schema/index.js +148 -110
  47. package/lib/theme/Schema/normalize.d.ts +41 -0
  48. package/lib/theme/Schema/normalize.js +210 -0
  49. package/lib/theme/Schema/normalize.test.d.ts +1 -0
  50. package/lib/theme/Schema/normalize.test.js +271 -0
  51. package/lib/theme/SchemaExpansion/_SchemaExpansion.scss +113 -0
  52. package/lib/theme/SchemaExpansion/context.d.ts +24 -0
  53. package/lib/theme/SchemaExpansion/context.js +187 -0
  54. package/lib/theme/SchemaExpansion/index.d.ts +4 -0
  55. package/lib/theme/SchemaExpansion/index.js +314 -0
  56. package/lib/theme/SchemaItem/index.js +9 -10
  57. package/lib/theme/SchemaTabs/index.d.ts +1 -1
  58. package/lib/theme/SchemaTabs/index.js +6 -5
  59. package/lib/theme/StatusCodes/index.js +2 -4
  60. package/lib/theme/TabItem/index.d.ts +5 -0
  61. package/lib/theme/TabItem/index.js +51 -0
  62. package/lib/theme/TabItem/styles.module.css +3 -0
  63. package/lib/theme/Tabs/index.d.ts +5 -0
  64. package/lib/theme/Tabs/index.js +148 -0
  65. package/lib/theme/Tabs/styles.module.css +7 -0
  66. package/lib/theme/styles.scss +1 -0
  67. package/lib/theme/translationIds.d.ts +1 -93
  68. package/lib/theme/translationIds.js +0 -109
  69. package/lib/theme/utils/codeBlockUtils.d.ts +28 -0
  70. package/lib/theme/utils/codeBlockUtils.js +223 -0
  71. package/lib/theme/utils/reactUtils.d.ts +1 -0
  72. package/lib/theme/utils/reactUtils.js +23 -0
  73. package/lib/theme/utils/scrollUtils.d.ts +7 -0
  74. package/lib/theme/utils/scrollUtils.js +175 -0
  75. package/lib/theme/utils/tabsUtils.d.ts +47 -0
  76. package/lib/theme/utils/tabsUtils.js +299 -0
  77. package/lib/theme/utils/useCodeWordWrap.d.ts +8 -0
  78. package/lib/theme/utils/useCodeWordWrap.js +84 -0
  79. package/lib/theme/utils/useMutationObserver.d.ts +3 -0
  80. package/lib/theme/utils/useMutationObserver.js +34 -0
  81. package/package.json +4 -4
  82. package/src/markdown/schema.test.ts +102 -0
  83. package/src/markdown/schema.ts +42 -15
  84. package/src/theme/ApiExplorer/ApiCodeBlock/Container/index.tsx +2 -1
  85. package/src/theme/ApiExplorer/ApiCodeBlock/Content/String.tsx +8 -7
  86. package/src/theme/ApiExplorer/ApiCodeBlock/Line/index.tsx +1 -1
  87. package/src/theme/ApiExplorer/ApiCodeBlock/index.tsx +1 -1
  88. package/src/theme/ApiExplorer/Authorization/index.tsx +9 -10
  89. package/src/theme/ApiExplorer/Body/index.tsx +7 -5
  90. package/src/theme/ApiExplorer/CodeSnippets/index.tsx +103 -59
  91. package/src/theme/ApiExplorer/CodeSnippets/languages.test.ts +109 -0
  92. package/src/theme/ApiExplorer/CodeSnippets/languages.ts +13 -1
  93. package/src/theme/ApiExplorer/CodeTabs/index.tsx +5 -5
  94. package/src/theme/ApiExplorer/Export/index.tsx +6 -2
  95. package/src/theme/ApiExplorer/FormFileUpload/index.tsx +1 -2
  96. package/src/theme/ApiExplorer/FormLabel/index.tsx +1 -2
  97. package/src/theme/ApiExplorer/FormTextInput/index.tsx +1 -2
  98. package/src/theme/ApiExplorer/LiveEditor/index.tsx +1 -2
  99. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamArrayFormItem.tsx +5 -3
  100. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.tsx +20 -4
  101. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.tsx +1 -2
  102. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.tsx +15 -4
  103. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamTextFormItem.tsx +11 -1
  104. package/src/theme/ApiExplorer/ParamOptions/index.tsx +2 -3
  105. package/src/theme/ApiExplorer/Request/index.tsx +23 -18
  106. package/src/theme/ApiExplorer/Response/index.tsx +63 -9
  107. package/src/theme/ApiExplorer/SecuritySchemes/index.tsx +60 -52
  108. package/src/theme/ApiExplorer/Server/index.tsx +8 -3
  109. package/src/theme/ApiItem/index.tsx +43 -21
  110. package/src/theme/ApiTabs/index.tsx +8 -8
  111. package/src/theme/DiscriminatorTabs/index.tsx +6 -5
  112. package/src/theme/Example/index.tsx +3 -4
  113. package/src/theme/MimeTabs/index.tsx +9 -8
  114. package/src/theme/OperationTabs/index.tsx +5 -4
  115. package/src/theme/ParamsDetails/index.tsx +1 -2
  116. package/src/theme/ParamsItem/index.tsx +13 -8
  117. package/src/theme/RequestSchema/index.tsx +38 -40
  118. package/src/theme/ResponseExamples/index.tsx +3 -4
  119. package/src/theme/ResponseSchema/index.tsx +16 -17
  120. package/src/theme/Schema/index.tsx +154 -121
  121. package/src/theme/Schema/normalize.test.ts +288 -0
  122. package/src/theme/Schema/normalize.ts +224 -0
  123. package/src/theme/SchemaExpansion/_SchemaExpansion.scss +113 -0
  124. package/src/theme/SchemaExpansion/context.tsx +154 -0
  125. package/src/theme/SchemaExpansion/index.tsx +236 -0
  126. package/src/theme/SchemaItem/index.tsx +18 -10
  127. package/src/theme/SchemaTabs/index.tsx +6 -5
  128. package/src/theme/StatusCodes/index.tsx +2 -3
  129. package/src/theme/TabItem/index.tsx +61 -0
  130. package/src/theme/TabItem/styles.module.css +3 -0
  131. package/src/theme/Tabs/index.tsx +164 -0
  132. package/src/theme/Tabs/styles.module.css +7 -0
  133. package/src/theme/styles.scss +1 -0
  134. package/src/theme/translationIds.ts +37 -106
  135. package/src/theme/utils/codeBlockUtils.ts +296 -0
  136. package/src/theme/utils/reactUtils.ts +22 -0
  137. package/src/theme/utils/scrollUtils.tsx +153 -0
  138. package/src/theme/utils/tabsUtils.tsx +329 -0
  139. package/src/theme/utils/useCodeWordWrap.ts +110 -0
  140. package/src/theme/utils/useMutationObserver.ts +43 -0
  141. package/src/theme-classic.d.ts +0 -96
  142. package/src/types.d.ts +27 -0
  143. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ /* ============================================================================
3
+ * Copyright (c) Palo Alto Networks
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ * ========================================================================== */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.isCircularMarker = isCircularMarker;
10
+ exports.mergeAllOf = mergeAllOf;
11
+ exports.foldSiblingsIntoBranches = foldSiblingsIntoBranches;
12
+ exports.getDiscriminator = getDiscriminator;
13
+ exports.findPropertyDeep = findPropertyDeep;
14
+ exports.normalizeSchema = normalizeSchema;
15
+ // eslint-disable-next-line import/no-extraneous-dependencies
16
+ const allof_merge_1 = require("allof-merge");
17
+ function isCircularMarker(value) {
18
+ return typeof value === "string" && value.startsWith("circular(");
19
+ }
20
+ /**
21
+ * Strip `additionalProperties: false` from sibling allOf members so
22
+ * allof-merge doesn't collapse to an unsatisfiable empty schema. See #1119.
23
+ *
24
+ * NOT cached: DiscriminatorNode mutates raw subschemas (deletes the
25
+ * discriminator property from each branch to avoid duplicate rendering).
26
+ * A WeakMap cache would return the pre-mutation deep clone on subsequent
27
+ * mergeAllOf calls, causing deleted properties to reappear inside tab
28
+ * content. Matches prod's per-call behavior.
29
+ */
30
+ function stripConflictingAdditionalProps(node) {
31
+ if (Array.isArray(node)) return node.map(stripConflictingAdditionalProps);
32
+ if (!node || typeof node !== "object") return node;
33
+ let working = node;
34
+ if (Array.isArray(node.allOf) && node.allOf.length > 1) {
35
+ const hasStrictMember = node.allOf.some(
36
+ (m) => m && m.additionalProperties === false
37
+ );
38
+ if (hasStrictMember) {
39
+ working = {
40
+ ...node,
41
+ allOf: node.allOf.map((m) => {
42
+ if (m && m.additionalProperties === false) {
43
+ const { additionalProperties: _drop, ...rest } = m;
44
+ return rest;
45
+ }
46
+ return m;
47
+ }),
48
+ };
49
+ }
50
+ }
51
+ const result = {};
52
+ for (const [k, v] of Object.entries(working)) {
53
+ result[k] = stripConflictingAdditionalProps(v);
54
+ }
55
+ return result;
56
+ }
57
+ function mergeAllOf(schema) {
58
+ const onMergeError = (msg) => console.warn(msg);
59
+ const merged = (0, allof_merge_1.merge)(
60
+ stripConflictingAdditionalProps(schema),
61
+ {
62
+ onMergeError,
63
+ }
64
+ );
65
+ return merged ?? {};
66
+ }
67
+ // Keys that are parent-level metadata and should NOT be folded into branches.
68
+ const METADATA_KEYS = new Set([
69
+ "title",
70
+ "description",
71
+ "discriminator",
72
+ "deprecated",
73
+ "externalDocs",
74
+ "example",
75
+ "examples",
76
+ "xml",
77
+ "nullable",
78
+ "readOnly",
79
+ "writeOnly",
80
+ "default",
81
+ ]);
82
+ /**
83
+ * Fold sibling fields into each oneOf/anyOf branch via allOf-merge so each
84
+ * branch is self-contained. See #1218.
85
+ *
86
+ * Skipped when a discriminator is present: DiscriminatorNode already renders
87
+ * sibling properties at the top level, and folding would duplicate the
88
+ * discriminator metadata into each branch (causing nested DiscriminatorNode
89
+ * renders inside tabs — see #1525 follow-up).
90
+ *
91
+ * Called by normalizeSchema after allOf resolution. Uses mergeAllOf internally
92
+ * to compose `{ allOf: [siblings, branch] }` per branch — the WeakMap caches
93
+ * in stripConflictingAdditionalProps prevent redundant work on shared subtrees.
94
+ */
95
+ function foldSiblingsIntoBranches(schema) {
96
+ const branchKey = schema?.oneOf
97
+ ? "oneOf"
98
+ : schema?.anyOf
99
+ ? "anyOf"
100
+ : undefined;
101
+ if (!branchKey) return schema;
102
+ const branches = schema[branchKey];
103
+ if (!Array.isArray(branches) || branches.length === 0) return schema;
104
+ // Discriminator schemas rely on top-level properties being intact so
105
+ // DiscriminatorNode can locate the discriminator property and render
106
+ // shared siblings at the top level. Leave them alone.
107
+ if (schema.discriminator) return schema;
108
+ // Build siblings from non-metadata keys only. Metadata (title, description,
109
+ // examples, etc.) belongs at the top level and must not be folded.
110
+ const siblings = {};
111
+ for (const [key, value] of Object.entries(schema)) {
112
+ if (key !== branchKey && !METADATA_KEYS.has(key) && !key.startsWith("x-")) {
113
+ siblings[key] = value;
114
+ }
115
+ }
116
+ if (Object.keys(siblings).length === 0) return schema;
117
+ const folded = branches.map((branch) =>
118
+ mergeAllOf({ allOf: [siblings, branch] })
119
+ );
120
+ const result = { [branchKey]: folded };
121
+ for (const key of Object.keys(schema)) {
122
+ if (key !== branchKey && (METADATA_KEYS.has(key) || key.startsWith("x-"))) {
123
+ result[key] = schema[key];
124
+ }
125
+ }
126
+ return result;
127
+ }
128
+ // WeakMap caches keyed by object identity — shared-reference subtrees from
129
+ // $RefParser.dereference are looked up once, and cycles short-circuit.
130
+ const discriminatorCache = new WeakMap();
131
+ const findPropertyCache = new WeakMap();
132
+ /**
133
+ * Cached recursive discriminator lookup. Returns O(1) on repeated calls
134
+ * with the same object reference (common after normalizeSchema).
135
+ */
136
+ const BRANCH_KEYS = ["oneOf", "anyOf", "allOf"];
137
+ function getDiscriminator(schema) {
138
+ if (!schema || typeof schema !== "object") return undefined;
139
+ if (discriminatorCache.has(schema)) {
140
+ const cached = discriminatorCache.get(schema);
141
+ return cached === null ? undefined : cached;
142
+ }
143
+ discriminatorCache.set(schema, null);
144
+ let result = schema.discriminator;
145
+ if (!result) {
146
+ for (const key of BRANCH_KEYS) {
147
+ const branches = schema[key];
148
+ if (!Array.isArray(branches)) continue;
149
+ for (const branch of branches) {
150
+ result = getDiscriminator(branch);
151
+ if (result) break;
152
+ }
153
+ if (result) break;
154
+ }
155
+ }
156
+ discriminatorCache.set(schema, result ?? null);
157
+ return result;
158
+ }
159
+ /**
160
+ * Cached recursive property lookup. Searches schema.properties first, then
161
+ * into oneOf/anyOf/allOf branches. Returns O(1) on repeated calls with the
162
+ * same (schema, propertyName) pair — replaces the O(subtree) findProperty
163
+ * walk that caused #1525's O(N^2) render cost.
164
+ */
165
+ function findPropertyDeep(schema, propertyName) {
166
+ if (!schema || typeof schema !== "object") return undefined;
167
+ let cache = findPropertyCache.get(schema);
168
+ if (cache && cache.has(propertyName)) {
169
+ const cached = cache.get(propertyName);
170
+ return cached === null ? undefined : cached;
171
+ }
172
+ if (!cache) {
173
+ cache = new Map();
174
+ findPropertyCache.set(schema, cache);
175
+ }
176
+ cache.set(propertyName, null);
177
+ let result = schema.properties?.[propertyName];
178
+ if (!result) {
179
+ for (const key of BRANCH_KEYS) {
180
+ const branches = schema[key];
181
+ if (!Array.isArray(branches)) continue;
182
+ for (const branch of branches) {
183
+ result = findPropertyDeep(branch, propertyName);
184
+ if (result) break;
185
+ }
186
+ if (result) break;
187
+ }
188
+ }
189
+ cache.set(propertyName, result ?? null);
190
+ return result;
191
+ }
192
+ /**
193
+ * Identity-stable schema pass-through. Returns the input as-is so SchemaNode
194
+ * useMemo dependencies stay stable across renders.
195
+ *
196
+ * Earlier iterations of this function eagerly merged allOf and folded
197
+ * siblings into oneOf/anyOf branches, but those operations need to stay
198
+ * conditional inside SchemaNode and DiscriminatorNode — eager versions
199
+ * caused cartesian product expansion (allOf with multiple oneOfs) and
200
+ * double-folding regressions. The render-time helpers below
201
+ * (mergeAllOf, foldSiblingsIntoBranches) are still cached via the WeakMap
202
+ * inside stripConflictingAdditionalProps, so per-render cost stays bounded.
203
+ *
204
+ * The perf win for #1525 comes from getDiscriminator's WeakMap cache
205
+ * replacing the O(subtree) findDiscriminator walk, not from eager
206
+ * normalization here.
207
+ */
208
+ function normalizeSchema(schema) {
209
+ return schema;
210
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,271 @@
1
+ "use strict";
2
+ /* ============================================================================
3
+ * Copyright (c) Palo Alto Networks
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ * ========================================================================== */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ const normalize_1 = require("./normalize");
10
+ describe("normalizeSchema", () => {
11
+ it("returns the input as-is (identity-stable pass-through)", () => {
12
+ const schema = { type: "object", properties: { a: { type: "string" } } };
13
+ expect((0, normalize_1.normalizeSchema)(schema)).toBe(schema);
14
+ });
15
+ it("handles null, undefined, and primitives", () => {
16
+ expect((0, normalize_1.normalizeSchema)(null)).toBeNull();
17
+ expect((0, normalize_1.normalizeSchema)(undefined)).toBeUndefined();
18
+ expect((0, normalize_1.normalizeSchema)("string")).toBe("string");
19
+ expect((0, normalize_1.normalizeSchema)(42)).toBe(42);
20
+ });
21
+ });
22
+ describe("mergeAllOf", () => {
23
+ it("merges allOf members into a flat schema", () => {
24
+ const schema = {
25
+ allOf: [
26
+ { type: "object", properties: { a: { type: "string" } } },
27
+ { type: "object", properties: { b: { type: "number" } } },
28
+ ],
29
+ };
30
+ const result = (0, normalize_1.mergeAllOf)(schema);
31
+ expect(result.allOf).toBeUndefined();
32
+ expect(result.properties.a).toEqual({ type: "string" });
33
+ expect(result.properties.b).toEqual({ type: "number" });
34
+ });
35
+ it("strips conflicting additionalProperties: false from allOf members", () => {
36
+ const schema = {
37
+ allOf: [
38
+ {
39
+ type: "object",
40
+ properties: { a: { type: "string" } },
41
+ additionalProperties: false,
42
+ },
43
+ {
44
+ type: "object",
45
+ properties: { b: { type: "number" } },
46
+ additionalProperties: false,
47
+ },
48
+ ],
49
+ };
50
+ const result = (0, normalize_1.mergeAllOf)(schema);
51
+ expect(result.properties.a).toBeDefined();
52
+ expect(result.properties.b).toBeDefined();
53
+ });
54
+ it("preserves both properties and oneOf when merging incompatible-shape members", () => {
55
+ const result = (0, normalize_1.mergeAllOf)({
56
+ allOf: [
57
+ { type: "object", properties: { id: { type: "string" } } },
58
+ { oneOf: [{ title: "a" }, { title: "b" }] },
59
+ ],
60
+ });
61
+ expect(result.properties.id).toBeDefined();
62
+ expect(result.oneOf).toHaveLength(2);
63
+ });
64
+ });
65
+ describe("foldSiblingsIntoBranches", () => {
66
+ it("returns schema unchanged when no oneOf/anyOf is present", () => {
67
+ const schema = { type: "object", properties: { a: { type: "string" } } };
68
+ expect((0, normalize_1.foldSiblingsIntoBranches)(schema)).toBe(schema);
69
+ });
70
+ it("returns schema unchanged when branches have no siblings", () => {
71
+ const schema = {
72
+ oneOf: [{ properties: { a: { type: "string" } } }],
73
+ };
74
+ expect((0, normalize_1.foldSiblingsIntoBranches)(schema)).toBe(schema);
75
+ });
76
+ it("returns schema unchanged when a discriminator is present", () => {
77
+ const schema = {
78
+ discriminator: { propertyName: "type" },
79
+ properties: { shared: { type: "string" } },
80
+ oneOf: [{ properties: { a: { type: "number" } } }],
81
+ };
82
+ expect((0, normalize_1.foldSiblingsIntoBranches)(schema)).toBe(schema);
83
+ });
84
+ it("folds sibling properties into oneOf branches", () => {
85
+ const schema = {
86
+ properties: { shared: { type: "string" } },
87
+ oneOf: [
88
+ { properties: { a: { type: "number" } } },
89
+ { properties: { b: { type: "boolean" } } },
90
+ ],
91
+ };
92
+ const result = (0, normalize_1.foldSiblingsIntoBranches)(schema);
93
+ expect(result.properties).toBeUndefined();
94
+ expect(result.oneOf).toHaveLength(2);
95
+ expect(result.oneOf[0].properties.shared).toBeDefined();
96
+ expect(result.oneOf[0].properties.a).toBeDefined();
97
+ });
98
+ it("folds sibling properties into anyOf branches", () => {
99
+ const schema = {
100
+ properties: { shared: { type: "string" } },
101
+ anyOf: [
102
+ { properties: { a: { type: "number" } } },
103
+ { properties: { b: { type: "boolean" } } },
104
+ ],
105
+ };
106
+ const result = (0, normalize_1.foldSiblingsIntoBranches)(schema);
107
+ expect(result.properties).toBeUndefined();
108
+ expect(result.anyOf).toHaveLength(2);
109
+ expect(result.anyOf[1].properties.shared).toBeDefined();
110
+ expect(result.anyOf[1].properties.b).toBeDefined();
111
+ });
112
+ it("preserves metadata and x-extension keys when folding", () => {
113
+ const schema = {
114
+ title: "Test",
115
+ description: "desc",
116
+ deprecated: true,
117
+ "x-vendor": true,
118
+ properties: { shared: { type: "string" } },
119
+ anyOf: [{ properties: { a: { type: "number" } } }],
120
+ };
121
+ const result = (0, normalize_1.foldSiblingsIntoBranches)(schema);
122
+ expect(result.title).toBe("Test");
123
+ expect(result.description).toBe("desc");
124
+ expect(result.deprecated).toBe(true);
125
+ expect(result["x-vendor"]).toBe(true);
126
+ expect(result.properties).toBeUndefined();
127
+ });
128
+ it("strips non-metadata keys from result", () => {
129
+ const schema = {
130
+ type: "object",
131
+ required: ["shared"],
132
+ properties: { shared: { type: "string" } },
133
+ items: { type: "string" },
134
+ oneOf: [{ properties: { a: { type: "number" } } }],
135
+ };
136
+ const result = (0, normalize_1.foldSiblingsIntoBranches)(schema);
137
+ expect(result.type).toBeUndefined();
138
+ expect(result.required).toBeUndefined();
139
+ expect(result.properties).toBeUndefined();
140
+ expect(result.items).toBeUndefined();
141
+ expect(result.oneOf).toHaveLength(1);
142
+ });
143
+ });
144
+ describe("getDiscriminator", () => {
145
+ it("returns direct discriminator", () => {
146
+ const schema = { discriminator: { propertyName: "type" } };
147
+ expect((0, normalize_1.getDiscriminator)(schema)).toEqual({
148
+ propertyName: "type",
149
+ });
150
+ });
151
+ it("finds discriminator in oneOf branches", () => {
152
+ const schema = {
153
+ oneOf: [{ discriminator: { propertyName: "kind" } }, { type: "string" }],
154
+ };
155
+ expect((0, normalize_1.getDiscriminator)(schema)).toEqual({
156
+ propertyName: "kind",
157
+ });
158
+ });
159
+ it("finds discriminator in anyOf branches", () => {
160
+ const schema = {
161
+ anyOf: [
162
+ { type: "string" },
163
+ { discriminator: { propertyName: "variant" } },
164
+ ],
165
+ };
166
+ expect((0, normalize_1.getDiscriminator)(schema)).toEqual({
167
+ propertyName: "variant",
168
+ });
169
+ });
170
+ it("finds discriminator in allOf branches", () => {
171
+ const schema = {
172
+ allOf: [
173
+ { properties: { id: { type: "string" } } },
174
+ { discriminator: { propertyName: "type" } },
175
+ ],
176
+ };
177
+ expect((0, normalize_1.getDiscriminator)(schema)).toEqual({
178
+ propertyName: "type",
179
+ });
180
+ });
181
+ it("returns undefined when no discriminator exists", () => {
182
+ const schema = {
183
+ type: "object",
184
+ properties: { name: { type: "string" } },
185
+ };
186
+ expect((0, normalize_1.getDiscriminator)(schema)).toBeUndefined();
187
+ });
188
+ it("returns undefined for null/primitive input", () => {
189
+ expect((0, normalize_1.getDiscriminator)(null)).toBeUndefined();
190
+ expect((0, normalize_1.getDiscriminator)("string")).toBeUndefined();
191
+ });
192
+ it("caches results for same object reference", () => {
193
+ const inner = { discriminator: { propertyName: "type" } };
194
+ const schema = { oneOf: [inner] };
195
+ const first = (0, normalize_1.getDiscriminator)(schema);
196
+ const second = (0, normalize_1.getDiscriminator)(schema);
197
+ expect(first).toBe(second);
198
+ });
199
+ it("handles cycles without infinite recursion", () => {
200
+ const a = { properties: {} };
201
+ const b = { properties: { a } };
202
+ a.properties.b = b;
203
+ expect(() => (0, normalize_1.getDiscriminator)(a)).not.toThrow();
204
+ expect((0, normalize_1.getDiscriminator)(a)).toBeUndefined();
205
+ });
206
+ });
207
+ describe("findPropertyDeep", () => {
208
+ it("returns property at top level", () => {
209
+ const schema = { properties: { foo: { type: "string" } } };
210
+ expect((0, normalize_1.findPropertyDeep)(schema, "foo")).toEqual({
211
+ type: "string",
212
+ });
213
+ });
214
+ it("finds property in oneOf branches", () => {
215
+ const schema = {
216
+ oneOf: [
217
+ { properties: { a: { type: "string" } } },
218
+ { properties: { b: { type: "number" } } },
219
+ ],
220
+ };
221
+ expect((0, normalize_1.findPropertyDeep)(schema, "a")).toEqual({
222
+ type: "string",
223
+ });
224
+ expect((0, normalize_1.findPropertyDeep)(schema, "b")).toEqual({
225
+ type: "number",
226
+ });
227
+ });
228
+ it("finds property in anyOf branches", () => {
229
+ const schema = {
230
+ anyOf: [{ properties: { x: { type: "integer" } } }],
231
+ };
232
+ expect((0, normalize_1.findPropertyDeep)(schema, "x")).toEqual({
233
+ type: "integer",
234
+ });
235
+ });
236
+ it("finds property in allOf branches", () => {
237
+ const schema = {
238
+ allOf: [{ properties: { y: { type: "boolean" } } }],
239
+ };
240
+ expect((0, normalize_1.findPropertyDeep)(schema, "y")).toEqual({
241
+ type: "boolean",
242
+ });
243
+ });
244
+ it("returns undefined when property not found", () => {
245
+ const schema = { properties: { foo: { type: "string" } } };
246
+ expect((0, normalize_1.findPropertyDeep)(schema, "bar")).toBeUndefined();
247
+ });
248
+ it("returns undefined for null/primitive input", () => {
249
+ expect((0, normalize_1.findPropertyDeep)(null, "foo")).toBeUndefined();
250
+ expect((0, normalize_1.findPropertyDeep)("string", "foo")).toBeUndefined();
251
+ });
252
+ it("handles cycles without infinite recursion", () => {
253
+ const a = { properties: {} };
254
+ a.oneOf = [a];
255
+ expect(() => (0, normalize_1.findPropertyDeep)(a, "foo")).not.toThrow();
256
+ expect((0, normalize_1.findPropertyDeep)(a, "foo")).toBeUndefined();
257
+ });
258
+ });
259
+ describe("isCircularMarker", () => {
260
+ it("returns true for circular marker strings", () => {
261
+ expect((0, normalize_1.isCircularMarker)("circular(Title)")).toBe(true);
262
+ expect((0, normalize_1.isCircularMarker)("circular()")).toBe(true);
263
+ });
264
+ it("returns false for other values", () => {
265
+ expect((0, normalize_1.isCircularMarker)("normal string")).toBe(false);
266
+ expect((0, normalize_1.isCircularMarker)(null)).toBe(false);
267
+ expect((0, normalize_1.isCircularMarker)(undefined)).toBe(false);
268
+ expect((0, normalize_1.isCircularMarker)({})).toBe(false);
269
+ expect((0, normalize_1.isCircularMarker)(42)).toBe(false);
270
+ });
271
+ });
@@ -0,0 +1,113 @@
1
+ /* ============================================================================
2
+ * Copyright (c) Palo Alto Networks
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ * ========================================================================== */
7
+
8
+ .openapi-schema-expansion {
9
+ position: relative;
10
+ display: inline-flex;
11
+ align-items: center;
12
+ margin-left: auto;
13
+ }
14
+
15
+ .openapi-schema-expansion__trigger {
16
+ appearance: none;
17
+ background: transparent;
18
+ border: none;
19
+ border-radius: var(--ifm-global-radius);
20
+ padding: 0;
21
+ width: 22px;
22
+ height: 22px;
23
+ flex: 0 0 22px;
24
+ display: inline-flex;
25
+ align-items: center;
26
+ justify-content: center;
27
+ color: var(--ifm-color-emphasis-600);
28
+ line-height: 0;
29
+ opacity: 0.7;
30
+ transition:
31
+ opacity 0.12s ease,
32
+ background-color 0.12s ease,
33
+ color 0.12s ease;
34
+
35
+ &:hover {
36
+ opacity: 1;
37
+ background-color: var(--ifm-color-emphasis-200);
38
+ color: var(--ifm-color-emphasis-900);
39
+ }
40
+
41
+ &:focus-visible {
42
+ outline: 2px solid var(--ifm-color-primary);
43
+ outline-offset: 2px;
44
+ opacity: 1;
45
+ }
46
+
47
+ &[aria-expanded="true"] {
48
+ opacity: 1;
49
+ background-color: var(--ifm-color-emphasis-200);
50
+ color: var(--ifm-color-emphasis-900);
51
+ }
52
+ }
53
+
54
+ .openapi-schema-expansion__popover {
55
+ position: fixed;
56
+ z-index: 1000;
57
+ display: inline-flex;
58
+ align-items: center;
59
+ gap: 2px;
60
+ padding: 3px;
61
+ background-color: var(--ifm-background-surface-color);
62
+ border: 1px solid var(--ifm-color-emphasis-300);
63
+ border-radius: var(--ifm-global-radius);
64
+ box-shadow: var(--ifm-global-shadow-md);
65
+ white-space: nowrap;
66
+ }
67
+
68
+ .openapi-schema-expansion__option {
69
+ appearance: none;
70
+ background: transparent;
71
+ border: none;
72
+ border-radius: calc(var(--ifm-global-radius) - 2px);
73
+ padding: 2px 8px;
74
+ font-size: 0.8rem;
75
+ line-height: 1.4;
76
+ color: var(--ifm-color-emphasis-800);
77
+ transition:
78
+ background-color 0.12s ease,
79
+ color 0.12s ease;
80
+
81
+ &:hover {
82
+ background-color: var(--ifm-color-emphasis-200);
83
+ }
84
+
85
+ &:focus-visible {
86
+ outline: 2px solid var(--ifm-color-primary);
87
+ outline-offset: 1px;
88
+ }
89
+ }
90
+
91
+ .openapi-schema-expansion__option--active {
92
+ background-color: var(--ifm-color-primary);
93
+ color: var(--ifm-color-white);
94
+
95
+ &:hover {
96
+ background-color: var(--ifm-color-primary-dark);
97
+ }
98
+ }
99
+
100
+ .openapi-markdown__details-summary--with-control {
101
+ display: flex !important;
102
+ align-items: center;
103
+ gap: 0.5rem;
104
+
105
+ > h3,
106
+ > strong {
107
+ margin-bottom: 0;
108
+ display: inline-flex;
109
+ align-items: center;
110
+ flex-wrap: wrap;
111
+ gap: 0.4rem;
112
+ }
113
+ }
@@ -0,0 +1,24 @@
1
+ import React from "react";
2
+ export declare const SCHEMA_EXPANSION_STORAGE_KEY = "docusaurus-openapi-schema-expansion-level";
3
+ export interface SchemaExpansionConfig {
4
+ enabled: boolean;
5
+ defaultLevel: number;
6
+ max: number;
7
+ persist: boolean;
8
+ }
9
+ interface SchemaExpansionContextValue {
10
+ config: SchemaExpansionConfig;
11
+ level: number;
12
+ setLevel: (next: number) => void;
13
+ }
14
+ export declare function normalizeLevel(value: number | "all" | undefined): number;
15
+ export declare const SchemaExpansionProvider: React.FC<{
16
+ children: React.ReactNode;
17
+ }>;
18
+ export declare const SchemaDepthProvider: React.FC<{
19
+ depth: number;
20
+ children: React.ReactNode;
21
+ }>;
22
+ export declare function useSchemaExpansion(): SchemaExpansionContextValue;
23
+ export declare function useSchemaDepth(): number;
24
+ export {};