@scalar/json-magic 0.12.2 → 0.12.4

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 (72) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/bundle/bundle.js +476 -250
  3. package/dist/bundle/index.js +1 -6
  4. package/dist/bundle/plugins/browser.js +4 -9
  5. package/dist/bundle/plugins/fetch-urls/index.js +76 -49
  6. package/dist/bundle/plugins/node.js +5 -11
  7. package/dist/bundle/plugins/parse-json/index.js +30 -23
  8. package/dist/bundle/plugins/parse-yaml/index.js +31 -24
  9. package/dist/bundle/plugins/read-files/index.js +50 -29
  10. package/dist/bundle/value-generator.js +118 -49
  11. package/dist/dereference/dereference.js +66 -36
  12. package/dist/dereference/index.js +1 -5
  13. package/dist/diff/apply.js +69 -36
  14. package/dist/diff/diff.js +68 -32
  15. package/dist/diff/index.js +4 -9
  16. package/dist/diff/merge.js +122 -60
  17. package/dist/diff/trie.js +100 -77
  18. package/dist/diff/utils.js +96 -41
  19. package/dist/helpers/convert-to-local-ref.js +30 -23
  20. package/dist/helpers/escape-json-pointer.js +7 -6
  21. package/dist/helpers/get-schemas.js +59 -32
  22. package/dist/helpers/get-segments-from-path.js +13 -9
  23. package/dist/helpers/get-value-by-path.js +38 -22
  24. package/dist/helpers/is-file-path.js +19 -9
  25. package/dist/helpers/is-http-url.js +20 -11
  26. package/dist/helpers/is-json-object.js +29 -15
  27. package/dist/helpers/is-yaml.js +17 -6
  28. package/dist/helpers/json-path-utils.js +30 -15
  29. package/dist/helpers/normalize.js +27 -26
  30. package/dist/helpers/resolve-reference-path.js +28 -16
  31. package/dist/helpers/set-value-at-path.js +72 -26
  32. package/dist/helpers/to-relative-path.js +40 -28
  33. package/dist/helpers/unescape-json-pointer.js +8 -6
  34. package/dist/magic-proxy/index.js +1 -6
  35. package/dist/magic-proxy/proxy.js +245 -186
  36. package/dist/types.js +1 -1
  37. package/package.json +5 -7
  38. package/dist/bundle/bundle.js.map +0 -7
  39. package/dist/bundle/index.js.map +0 -7
  40. package/dist/bundle/plugins/browser.js.map +0 -7
  41. package/dist/bundle/plugins/fetch-urls/index.js.map +0 -7
  42. package/dist/bundle/plugins/node.js.map +0 -7
  43. package/dist/bundle/plugins/parse-json/index.js.map +0 -7
  44. package/dist/bundle/plugins/parse-yaml/index.js.map +0 -7
  45. package/dist/bundle/plugins/read-files/index.js.map +0 -7
  46. package/dist/bundle/value-generator.js.map +0 -7
  47. package/dist/dereference/dereference.js.map +0 -7
  48. package/dist/dereference/index.js.map +0 -7
  49. package/dist/diff/apply.js.map +0 -7
  50. package/dist/diff/diff.js.map +0 -7
  51. package/dist/diff/index.js.map +0 -7
  52. package/dist/diff/merge.js.map +0 -7
  53. package/dist/diff/trie.js.map +0 -7
  54. package/dist/diff/utils.js.map +0 -7
  55. package/dist/helpers/convert-to-local-ref.js.map +0 -7
  56. package/dist/helpers/escape-json-pointer.js.map +0 -7
  57. package/dist/helpers/get-schemas.js.map +0 -7
  58. package/dist/helpers/get-segments-from-path.js.map +0 -7
  59. package/dist/helpers/get-value-by-path.js.map +0 -7
  60. package/dist/helpers/is-file-path.js.map +0 -7
  61. package/dist/helpers/is-http-url.js.map +0 -7
  62. package/dist/helpers/is-json-object.js.map +0 -7
  63. package/dist/helpers/is-yaml.js.map +0 -7
  64. package/dist/helpers/json-path-utils.js.map +0 -7
  65. package/dist/helpers/normalize.js.map +0 -7
  66. package/dist/helpers/resolve-reference-path.js.map +0 -7
  67. package/dist/helpers/set-value-at-path.js.map +0 -7
  68. package/dist/helpers/to-relative-path.js.map +0 -7
  69. package/dist/helpers/unescape-json-pointer.js.map +0 -7
  70. package/dist/magic-proxy/index.js.map +0 -7
  71. package/dist/magic-proxy/proxy.js.map +0 -7
  72. package/dist/types.js.map +0 -7
@@ -1,48 +1,103 @@
1
- const isKeyCollisions = (a, b) => {
2
- if (typeof a !== typeof b) {
3
- return true;
4
- }
5
- if (typeof a === "object" && typeof b === "object" && a !== null && b !== null) {
6
- const keys = /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]);
7
- for (const key of keys) {
8
- if (a[key] !== void 0 && b[key] !== void 0) {
9
- if (isKeyCollisions(a[key], b[key])) {
10
- return true;
1
+ /**
2
+ * Deep check for objects for collisions
3
+ * Check primitives if their values are different
4
+ *
5
+ * @param a - First value to compare
6
+ * @param b - Second value to compare
7
+ * @returns true if there is a collision, false otherwise
8
+ *
9
+ * @example
10
+ * // Objects with different values for same key
11
+ * isKeyCollisions({ a: 1 }, { a: 2 }) // true
12
+ *
13
+ * // Objects with different types
14
+ * isKeyCollisions({ a: 1 }, { a: '1' }) // true
15
+ *
16
+ * // Objects with no collisions
17
+ * isKeyCollisions({ a: 1 }, { b: 2 }) // false
18
+ *
19
+ * // Nested objects with collision
20
+ * isKeyCollisions({ a: { b: 1 } }, { a: { b: 2 } }) // true
21
+ */
22
+ export const isKeyCollisions = (a, b) => {
23
+ if (typeof a !== typeof b) {
24
+ return true;
25
+ }
26
+ if (typeof a === 'object' && typeof b === 'object' && a !== null && b !== null) {
27
+ const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
28
+ for (const key of keys) {
29
+ if (a[key] !== undefined && b[key] !== undefined) {
30
+ if (isKeyCollisions(a[key], b[key])) {
31
+ return true;
32
+ }
33
+ }
11
34
  }
12
- }
35
+ return false;
13
36
  }
14
- return false;
15
- }
16
- return a !== b;
37
+ // We handle all primitives here
38
+ return a !== b;
17
39
  };
18
- const mergeObjects = (a, b) => {
19
- for (const key in b) {
20
- if (!(key in a)) {
21
- a[key] = b[key];
22
- } else {
23
- const aValue = a[key];
24
- const bValue = b[key];
25
- if (typeof aValue === "object" && aValue !== null && typeof bValue === "object" && bValue !== null) {
26
- a[key] = mergeObjects(aValue, bValue);
27
- }
40
+ /**
41
+ * Deep merges two objects, combining their properties recursively.
42
+ *
43
+ * ⚠️ Note: This operation assumes there are no key collisions between the objects.
44
+ * Use isKeyCollisions() to check for collisions before merging.
45
+ *
46
+ * @param a - Target object to merge into
47
+ * @param b - Source object to merge from
48
+ * @returns The merged object (mutates and returns a)
49
+ *
50
+ * @example
51
+ * // Simple merge
52
+ * const a = { name: 'John' }
53
+ * const b = { age: 30 }
54
+ * mergeObjects(a, b) // { name: 'John', age: 30 }
55
+ *
56
+ * // Nested merge
57
+ * const a = { user: { name: 'John' } }
58
+ * const b = { user: { age: 30 } }
59
+ * mergeObjects(a, b) // { user: { name: 'John', age: 30 } }
60
+ */
61
+ export const mergeObjects = (a, b) => {
62
+ for (const key in b) {
63
+ if (!(key in a)) {
64
+ a[key] = b[key];
65
+ }
66
+ else {
67
+ const aValue = a[key];
68
+ const bValue = b[key];
69
+ if (typeof aValue === 'object' && aValue !== null && typeof bValue === 'object' && bValue !== null) {
70
+ a[key] = mergeObjects(aValue, bValue);
71
+ }
72
+ }
28
73
  }
29
- }
30
- return a;
74
+ return a;
31
75
  };
32
- const isArrayEqual = (a, b) => {
33
- if (a.length !== b.length) {
34
- return false;
35
- }
36
- for (let i = 0; i <= a.length; ++i) {
37
- if (a[i] !== b[i]) {
38
- return false;
76
+ /**
77
+ * Checks if two arrays have the same elements in the same order.
78
+ *
79
+ * @param a - First array to compare
80
+ * @param b - Second array to compare
81
+ * @returns True if arrays have same length and elements, false otherwise
82
+ *
83
+ * @example
84
+ * // Arrays with same elements
85
+ * isArrayEqual([1, 2, 3], [1, 2, 3]) // true
86
+ *
87
+ * // Arrays with different elements
88
+ * isArrayEqual([1, 2, 3], [1, 2, 4]) // false
89
+ *
90
+ * // Arrays with different lengths
91
+ * isArrayEqual([1, 2], [1, 2, 3]) // false
92
+ */
93
+ export const isArrayEqual = (a, b) => {
94
+ if (a.length !== b.length) {
95
+ return false;
39
96
  }
40
- }
41
- return true;
42
- };
43
- export {
44
- isArrayEqual,
45
- isKeyCollisions,
46
- mergeObjects
97
+ for (let i = 0; i <= a.length; ++i) {
98
+ if (a[i] !== b[i]) {
99
+ return false;
100
+ }
101
+ }
102
+ return true;
47
103
  };
48
- //# sourceMappingURL=utils.js.map
@@ -1,26 +1,33 @@
1
- const convertToLocalRef = (ref, currentContext, schemas) => {
2
- const [baseUrl, pathOrAnchor] = ref.split("#", 2);
3
- if (baseUrl) {
4
- if (!schemas.has(baseUrl)) {
5
- return void 0;
1
+ /**
2
+ * Translates a JSON Reference ($ref) to a local object path within the root schema.
3
+ *
4
+ * @param ref - The JSON Reference string (e.g., "#/foo/bar", "other.json#/baz", "other.json#anchor")
5
+ * @param currentContext - The current base context (usually the $id of the current schema or parent)
6
+ * @param schemas - A map of schema identifiers ($id, $anchor) to their local object paths
7
+ * @returns The local object path as a string, or undefined if the reference cannot be resolved
8
+ */
9
+ export const convertToLocalRef = (ref, currentContext, schemas) => {
10
+ // Split the reference into base URL and path/anchor (e.g., "foo.json#/bar" => ["foo.json", "/bar"])
11
+ const [baseUrl, pathOrAnchor] = ref.split('#', 2);
12
+ if (baseUrl) {
13
+ if (!schemas.has(baseUrl)) {
14
+ return undefined;
15
+ }
16
+ if (!pathOrAnchor) {
17
+ return schemas.get(baseUrl);
18
+ }
19
+ // If the pathOrAnchor is a JSON pointer, we need to append it to the baseUrl
20
+ if (pathOrAnchor.startsWith('/')) {
21
+ return `${schemas.get(baseUrl)}${pathOrAnchor}`;
22
+ }
23
+ // If the pathOrAnchor is an anchor, we need to return the anchor
24
+ return schemas.get(`${baseUrl}#${pathOrAnchor}`);
6
25
  }
7
- if (!pathOrAnchor) {
8
- return schemas.get(baseUrl);
26
+ if (pathOrAnchor) {
27
+ if (pathOrAnchor.startsWith('/')) {
28
+ return pathOrAnchor.slice(1);
29
+ }
30
+ return schemas.get(`${currentContext}#${pathOrAnchor}`);
9
31
  }
10
- if (pathOrAnchor.startsWith("/")) {
11
- return `${schemas.get(baseUrl)}${pathOrAnchor}`;
12
- }
13
- return schemas.get(`${baseUrl}#${pathOrAnchor}`);
14
- }
15
- if (pathOrAnchor) {
16
- if (pathOrAnchor.startsWith("/")) {
17
- return pathOrAnchor.slice(1);
18
- }
19
- return schemas.get(`${currentContext}#${pathOrAnchor}`);
20
- }
21
- return void 0;
22
- };
23
- export {
24
- convertToLocalRef
32
+ return undefined;
25
33
  };
26
- //# sourceMappingURL=convert-to-local-ref.js.map
@@ -1,7 +1,8 @@
1
- function escapeJsonPointer(str) {
2
- return str.replace(/~/g, "~0").replace(/\//g, "~1");
1
+ /**
2
+ * Escapes a JSON pointer string.
3
+ *
4
+ * Example: `/foo/bar~baz` -> `'~1foo~1bar~0baz'`
5
+ */
6
+ export function escapeJsonPointer(str) {
7
+ return str.replace(/~/g, '~0').replace(/\//g, '~1');
3
8
  }
4
- export {
5
- escapeJsonPointer
6
- };
7
- //# sourceMappingURL=escape-json-pointer.js.map
@@ -1,37 +1,64 @@
1
- const getId = (input) => {
2
- if (input && typeof input === "object" && input["$id"] && typeof input["$id"] === "string") {
3
- return input["$id"];
4
- }
5
- return void 0;
1
+ /**
2
+ * Retrieves the $id property from the input object if it exists and is a string.
3
+ *
4
+ * @param input - The object to extract the $id from.
5
+ * @returns The $id string if present, otherwise undefined.
6
+ */
7
+ export const getId = (input) => {
8
+ if (input && typeof input === 'object' && input['$id'] && typeof input['$id'] === 'string') {
9
+ return input['$id'];
10
+ }
11
+ return undefined;
6
12
  };
13
+ /**
14
+ * Joins an array of path segments into a single string separated by '/'.
15
+ *
16
+ * @param segments - The array of path segments.
17
+ * @returns The joined path string.
18
+ */
7
19
  const getPath = (segments) => {
8
- return segments.join("/");
20
+ return segments.join('/');
9
21
  };
10
- const getSchemas = (input, base = "", segments = [], map = /* @__PURE__ */ new Map(), visited = /* @__PURE__ */ new WeakSet()) => {
11
- if (typeof input !== "object" || input === null) {
12
- return map;
13
- }
14
- if (visited.has(input)) {
15
- return map;
16
- }
17
- visited.add(input);
18
- const id = getId(input);
19
- if (id) {
20
- map.set(id, getPath(segments));
21
- }
22
- const newBase = id ?? base;
23
- if (input["$anchor"] && typeof input["$anchor"] === "string") {
24
- map.set(`${newBase}#${input["$anchor"]}`, getPath(segments));
25
- }
26
- for (const key in input) {
27
- if (typeof input[key] === "object" && input[key] !== null) {
28
- getSchemas(input[key], newBase, [...segments, key], map, visited);
22
+ /**
23
+ * Recursively traverses the input object to collect all schemas identified by $id and $anchor properties.
24
+ *
25
+ * - If an object has a $id property, it is added to the map with its $id as the key.
26
+ * - If an object has a $anchor property, it is added to the map with a key composed of the current base and the anchor.
27
+ * - The function performs a depth-first search (DFS) through all nested objects.
28
+ *
29
+ * @param input - The input object to traverse.
30
+ * @param base - The current base URI, used for resolving anchors.
31
+ * @param map - The map collecting found schemas.
32
+ * @returns A map of schema identifiers to their corresponding objects.
33
+ */
34
+ export const getSchemas = (input, base = '', segments = [], map = new Map(), visited = new WeakSet()) => {
35
+ // Only process non-null objects
36
+ if (typeof input !== 'object' || input === null) {
37
+ return map;
29
38
  }
30
- }
31
- return map;
32
- };
33
- export {
34
- getId,
35
- getSchemas
39
+ // If the object has already been visited, return the map
40
+ if (visited.has(input)) {
41
+ return map;
42
+ }
43
+ // Add the object to the visited set
44
+ visited.add(input);
45
+ // Attempt to get $id from the current object
46
+ const id = getId(input);
47
+ // If $id exists, add the object to the map with $id as the key
48
+ if (id) {
49
+ map.set(id, getPath(segments));
50
+ }
51
+ // Update the base for nested anchors
52
+ const newBase = id ?? base;
53
+ // If $anchor exists, add the object to the map with base#anchor as the key
54
+ if (input['$anchor'] && typeof input['$anchor'] === 'string') {
55
+ map.set(`${newBase}#${input['$anchor']}`, getPath(segments));
56
+ }
57
+ // Recursively traverse all properties (DFS)
58
+ for (const key in input) {
59
+ if (typeof input[key] === 'object' && input[key] !== null) {
60
+ getSchemas(input[key], newBase, [...segments, key], map, visited);
61
+ }
62
+ }
63
+ return map;
36
64
  };
37
- //# sourceMappingURL=get-schemas.js.map
@@ -1,11 +1,15 @@
1
- import { unescapeJsonPointer } from "./unescape-json-pointer.js";
2
- function getSegmentsFromPath(path) {
3
- return (
1
+ import { unescapeJsonPointer } from './unescape-json-pointer.js';
2
+ /**
3
+ * Translate `/paths/~1test` to `['paths', '/test']`
4
+ */
5
+ export function getSegmentsFromPath(path) {
6
+ return (
4
7
  // /paths/~1test
5
- path.split("/").slice(1).map(unescapeJsonPointer)
6
- );
8
+ path
9
+ // ['', 'paths', '~1test']
10
+ .split('/')
11
+ // ['paths', '~test']
12
+ .slice(1)
13
+ // ['paths', '/test']
14
+ .map(unescapeJsonPointer));
7
15
  }
8
- export {
9
- getSegmentsFromPath
10
- };
11
- //# sourceMappingURL=get-segments-from-path.js.map
@@ -1,23 +1,39 @@
1
- import { getId } from "../helpers/get-schemas.js";
2
- function getValueByPath(target, segments) {
3
- return segments.reduce(
4
- (acc, key) => {
5
- if (acc.value === void 0) {
6
- return { context: "", value: void 0 };
7
- }
8
- if (typeof acc.value !== "object" || acc.value === null) {
9
- return { context: "", value: void 0 };
10
- }
11
- const id = getId(acc.value);
12
- return { context: id ?? acc.context, value: acc.value?.[key] };
13
- },
14
- {
15
- context: "",
16
- value: target
17
- }
18
- );
1
+ import { getId } from '../helpers/get-schemas.js';
2
+ /**
3
+ * Traverses an object using an array of string segments (path keys) and returns
4
+ * the value at the specified path along with its context (id if available).
5
+ *
6
+ * @param target - The root object to traverse.
7
+ * @param segments - An array of string keys representing the path to traverse.
8
+ * @returns An object containing the final context (id or previous context) and the value at the path.
9
+ *
10
+ * @example
11
+ * const obj = {
12
+ * foo: {
13
+ * bar: {
14
+ * baz: 42
15
+ * }
16
+ * }
17
+ * };
18
+ * // Returns: { context: '', value: 42 }
19
+ * getValueByPath(obj, ['foo', 'bar', 'baz']);
20
+ */
21
+ export function getValueByPath(target, segments) {
22
+ return segments.reduce((acc, key) => {
23
+ // If the accumulator is undefined, the path does not exist
24
+ if (acc.value === undefined) {
25
+ return { context: '', value: undefined };
26
+ }
27
+ // If the accumulator is not an object or is null, stop traversal
28
+ if (typeof acc.value !== 'object' || acc.value === null) {
29
+ return { context: '', value: undefined };
30
+ }
31
+ // Attempt to get the id from the current value for context tracking
32
+ const id = getId(acc.value);
33
+ // Return the next context and value for the next iteration
34
+ return { context: id ?? acc.context, value: acc.value?.[key] };
35
+ }, {
36
+ context: '',
37
+ value: target,
38
+ });
19
39
  }
20
- export {
21
- getValueByPath
22
- };
23
- //# sourceMappingURL=get-value-by-path.js.map
@@ -1,10 +1,20 @@
1
- import { isHttpUrl } from "../helpers/is-http-url.js";
2
- import { isJsonObject } from "../helpers/is-json-object.js";
3
- import { isYaml } from "../helpers/is-yaml.js";
4
- function isFilePath(value) {
5
- return !isHttpUrl(value) && !isYaml(value) && !isJsonObject(value);
1
+ import { isHttpUrl } from '../helpers/is-http-url.js';
2
+ import { isJsonObject } from '../helpers/is-json-object.js';
3
+ import { isYaml } from '../helpers/is-yaml.js';
4
+ /**
5
+ * Checks if a string represents a file path by ensuring it's not a remote URL,
6
+ * YAML content, or JSON content.
7
+ *
8
+ * @param value - The string to check
9
+ * @returns true if the string appears to be a file path, false otherwise
10
+ * @example
11
+ * ```ts
12
+ * isFilePath('./schemas/user.json') // true
13
+ * isFilePath('https://example.com/schema.json') // false
14
+ * isFilePath('{"type": "object"}') // false
15
+ * isFilePath('type: object') // false
16
+ * ```
17
+ */
18
+ export function isFilePath(value) {
19
+ return !isHttpUrl(value) && !isYaml(value) && !isJsonObject(value);
6
20
  }
7
- export {
8
- isFilePath
9
- };
10
- //# sourceMappingURL=is-file-path.js.map
@@ -1,12 +1,21 @@
1
- function isHttpUrl(value) {
2
- try {
3
- const url = new URL(value);
4
- return url.protocol === "http:" || url.protocol === "https:";
5
- } catch {
6
- return false;
7
- }
1
+ /**
2
+ * Checks if a string is a remote URL (starts with http:// or https://)
3
+ * @param value - The URL string to check
4
+ * @returns true if the string is a remote URL, false otherwise
5
+ * @example
6
+ * ```ts
7
+ * isHttpUrl('https://example.com/schema.json') // true
8
+ * isHttpUrl('http://api.example.com/schemas/user.json') // true
9
+ * isHttpUrl('#/components/schemas/User') // false
10
+ * isHttpUrl('./local-schema.json') // false
11
+ * ```
12
+ */
13
+ export function isHttpUrl(value) {
14
+ try {
15
+ const url = new URL(value);
16
+ return url.protocol === 'http:' || url.protocol === 'https:';
17
+ }
18
+ catch {
19
+ return false;
20
+ }
8
21
  }
9
- export {
10
- isHttpUrl
11
- };
12
- //# sourceMappingURL=is-http-url.js.map
@@ -1,16 +1,30 @@
1
- import { isObject } from "@scalar/helpers/object/is-object";
2
- function isJsonObject(value) {
3
- if (!/^\s*(\{)/.test(value.slice(0, 500))) {
4
- return false;
5
- }
6
- try {
7
- const val = JSON.parse(value);
8
- return isObject(val);
9
- } catch {
10
- return false;
11
- }
1
+ import { isObject } from '@scalar/helpers/object/is-object';
2
+ /**
3
+ * Determines if a string represents a valid JSON object (i.e., a plain object, not an array, primitive, or null).
4
+ * The function first checks if the string appears to start with an opening curly brace (ignoring leading whitespace),
5
+ * which is a quick heuristic to rule out arrays, primitives, and most invalid JSON. If this check passes,
6
+ * it attempts to parse the string with JSON.parse. The result is then checked to ensure it is a plain object
7
+ * (not an array, null, or primitive) using the isObject utility.
8
+ *
9
+ * @param value - The string to evaluate
10
+ * @returns true if the string is valid JSON and parses to a plain object, false otherwise
11
+ *
12
+ * @example
13
+ * isJsonObject('{"foo": "bar"}') // true
14
+ * isJsonObject('[1,2,3]') // false
15
+ * isJsonObject('not json') // false
16
+ * isJsonObject('42') // false
17
+ */
18
+ export function isJsonObject(value) {
19
+ // Quickly rule out anything that doesn't start with an object brace
20
+ if (!/^\s*(\{)/.test(value.slice(0, 500))) {
21
+ return false;
22
+ }
23
+ try {
24
+ const val = JSON.parse(value);
25
+ return isObject(val);
26
+ }
27
+ catch {
28
+ return false;
29
+ }
12
30
  }
13
- export {
14
- isJsonObject
15
- };
16
- //# sourceMappingURL=is-json-object.js.map
@@ -1,7 +1,18 @@
1
- function isYaml(value) {
2
- return /^\s*(?:-\s*)?[\w\-]+\s*:\s*.+\n.*/.test(value);
1
+ /**
2
+ * Checks if a string appears to be YAML content.
3
+ * This function uses a simple heuristic: it looks for a line that starts with an optional dash,
4
+ * followed by a key (alphanumeric or dash), a colon, and a value, and then at least one more line.
5
+ * This is not a full YAML parser, but works for basic detection.
6
+ *
7
+ * @param value - The string to check
8
+ * @returns true if the string looks like YAML, false otherwise
9
+ *
10
+ * @example
11
+ * isYaml('openapi: 3.0.0\ninfo:\n title: Example') // true
12
+ * isYaml('{"openapi": "3.0.0", "info": {"title": "Example"}}') // false
13
+ * isYaml('- name: value\n- name: value2') // true
14
+ * isYaml('type: object') // false (only one line)
15
+ */
16
+ export function isYaml(value) {
17
+ return /^\s*(?:-\s*)?[\w\-]+\s*:\s*.+\n.*/.test(value);
3
18
  }
4
- export {
5
- isYaml
6
- };
7
- //# sourceMappingURL=is-yaml.js.map
@@ -1,16 +1,31 @@
1
- function createPathFromSegments(obj, segments) {
2
- return segments.reduce((acc, part) => {
3
- if (acc[part] === void 0) {
4
- if (isNaN(Number(part))) {
5
- acc[part] = {};
6
- } else {
7
- acc[part] = [];
8
- }
9
- }
10
- return acc[part];
11
- }, obj);
1
+ /**
2
+ * Creates a nested path in an object from an array of path segments.
3
+ * Only creates intermediate objects/arrays if they don't already exist.
4
+ *
5
+ * @param obj - The target object to create the path in
6
+ * @param segments - Array of path segments to create
7
+ * @returns The final nested object/array at the end of the path
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const obj = {}
12
+ * createPathFromSegments(obj, ['components', 'schemas', 'User'])
13
+ * // Creates: { components: { schemas: { User: {} } } }
14
+ *
15
+ * createPathFromSegments(obj, ['items', '0', 'name'])
16
+ * // Creates: { items: [{ name: {} }] }
17
+ * ```
18
+ */
19
+ export function createPathFromSegments(obj, segments) {
20
+ return segments.reduce((acc, part) => {
21
+ if (acc[part] === undefined) {
22
+ if (isNaN(Number(part))) {
23
+ acc[part] = {};
24
+ }
25
+ else {
26
+ acc[part] = [];
27
+ }
28
+ }
29
+ return acc[part];
30
+ }, obj);
12
31
  }
13
- export {
14
- createPathFromSegments
15
- };
16
- //# sourceMappingURL=json-path-utils.js.map
@@ -1,29 +1,30 @@
1
- import { parse } from "yaml";
2
- function normalize(content) {
3
- if (content === null) {
4
- return void 0;
5
- }
6
- if (typeof content === "string") {
7
- if (content.trim() === "") {
8
- return void 0;
1
+ import { parse } from 'yaml';
2
+ /**
3
+ * Normalize a string (YAML, JSON, object) to a JavaScript datatype.
4
+ */
5
+ export function normalize(content) {
6
+ if (content === null) {
7
+ return undefined;
9
8
  }
10
- try {
11
- return JSON.parse(content);
12
- } catch (_error) {
13
- const hasColon = /^[^:]+:/.test(content);
14
- const isJson = content.slice(0, 50).trimStart().startsWith("{");
15
- if (!hasColon || isJson) {
16
- return void 0;
17
- }
18
- return parse(content, {
19
- maxAliasCount: 1e4,
20
- merge: true
21
- });
9
+ if (typeof content === 'string') {
10
+ if (content.trim() === '') {
11
+ return undefined;
12
+ }
13
+ try {
14
+ return JSON.parse(content);
15
+ }
16
+ catch (_error) {
17
+ // Does it look like YAML?
18
+ const hasColon = /^[^:]+:/.test(content);
19
+ const isJson = content.slice(0, 50).trimStart().startsWith('{');
20
+ if (!hasColon || isJson) {
21
+ return undefined;
22
+ }
23
+ return parse(content, {
24
+ maxAliasCount: 10000,
25
+ merge: true,
26
+ });
27
+ }
22
28
  }
23
- }
24
- return content;
29
+ return content;
25
30
  }
26
- export {
27
- normalize
28
- };
29
- //# sourceMappingURL=normalize.js.map