@scalar/json-magic 0.1.0

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 (185) hide show
  1. package/.turbo/turbo-build.log +9 -0
  2. package/CHANGELOG.md +7 -0
  3. package/LICENSE +21 -0
  4. package/README.md +356 -0
  5. package/dist/bundle/bundle.d.ts +292 -0
  6. package/dist/bundle/bundle.d.ts.map +1 -0
  7. package/dist/bundle/bundle.js +259 -0
  8. package/dist/bundle/bundle.js.map +7 -0
  9. package/dist/bundle/create-limiter.d.ts +21 -0
  10. package/dist/bundle/create-limiter.d.ts.map +1 -0
  11. package/dist/bundle/create-limiter.js +31 -0
  12. package/dist/bundle/create-limiter.js.map +7 -0
  13. package/dist/bundle/index.d.ts +2 -0
  14. package/dist/bundle/index.d.ts.map +1 -0
  15. package/dist/bundle/index.js +5 -0
  16. package/dist/bundle/index.js.map +7 -0
  17. package/dist/bundle/plugins/browser.d.ts +4 -0
  18. package/dist/bundle/plugins/browser.d.ts.map +1 -0
  19. package/dist/bundle/plugins/browser.js +9 -0
  20. package/dist/bundle/plugins/browser.js.map +7 -0
  21. package/dist/bundle/plugins/fetch-urls/index.d.ts +39 -0
  22. package/dist/bundle/plugins/fetch-urls/index.d.ts.map +1 -0
  23. package/dist/bundle/plugins/fetch-urls/index.js +48 -0
  24. package/dist/bundle/plugins/fetch-urls/index.js.map +7 -0
  25. package/dist/bundle/plugins/node.d.ts +5 -0
  26. package/dist/bundle/plugins/node.d.ts.map +1 -0
  27. package/dist/bundle/plugins/node.js +11 -0
  28. package/dist/bundle/plugins/node.js.map +7 -0
  29. package/dist/bundle/plugins/parse-json/index.d.ts +13 -0
  30. package/dist/bundle/plugins/parse-json/index.d.ts.map +1 -0
  31. package/dist/bundle/plugins/parse-json/index.js +22 -0
  32. package/dist/bundle/plugins/parse-json/index.js.map +7 -0
  33. package/dist/bundle/plugins/parse-yaml/index.d.ts +13 -0
  34. package/dist/bundle/plugins/parse-yaml/index.d.ts.map +1 -0
  35. package/dist/bundle/plugins/parse-yaml/index.js +23 -0
  36. package/dist/bundle/plugins/parse-yaml/index.js.map +7 -0
  37. package/dist/bundle/plugins/read-files/index.d.ts +29 -0
  38. package/dist/bundle/plugins/read-files/index.d.ts.map +1 -0
  39. package/dist/bundle/plugins/read-files/index.js +30 -0
  40. package/dist/bundle/plugins/read-files/index.js.map +7 -0
  41. package/dist/bundle/value-generator.d.ts +79 -0
  42. package/dist/bundle/value-generator.d.ts.map +1 -0
  43. package/dist/bundle/value-generator.js +55 -0
  44. package/dist/bundle/value-generator.js.map +7 -0
  45. package/dist/dereference/dereference.d.ts +45 -0
  46. package/dist/dereference/dereference.d.ts.map +1 -0
  47. package/dist/dereference/dereference.js +37 -0
  48. package/dist/dereference/dereference.js.map +7 -0
  49. package/dist/dereference/index.d.ts +2 -0
  50. package/dist/dereference/index.d.ts.map +1 -0
  51. package/dist/dereference/index.js +5 -0
  52. package/dist/dereference/index.js.map +7 -0
  53. package/dist/diff/apply.d.ts +35 -0
  54. package/dist/diff/apply.d.ts.map +1 -0
  55. package/dist/diff/apply.js +40 -0
  56. package/dist/diff/apply.js.map +7 -0
  57. package/dist/diff/diff.d.ts +56 -0
  58. package/dist/diff/diff.d.ts.map +1 -0
  59. package/dist/diff/diff.js +33 -0
  60. package/dist/diff/diff.js.map +7 -0
  61. package/dist/diff/index.d.ts +5 -0
  62. package/dist/diff/index.d.ts.map +1 -0
  63. package/dist/diff/index.js +9 -0
  64. package/dist/diff/index.js.map +7 -0
  65. package/dist/diff/merge.d.ts +43 -0
  66. package/dist/diff/merge.d.ts.map +1 -0
  67. package/dist/diff/merge.js +61 -0
  68. package/dist/diff/merge.js.map +7 -0
  69. package/dist/diff/trie.d.ts +64 -0
  70. package/dist/diff/trie.d.ts.map +1 -0
  71. package/dist/diff/trie.js +82 -0
  72. package/dist/diff/trie.js.map +7 -0
  73. package/dist/diff/utils.d.ts +63 -0
  74. package/dist/diff/utils.d.ts.map +1 -0
  75. package/dist/diff/utils.js +48 -0
  76. package/dist/diff/utils.js.map +7 -0
  77. package/dist/magic-proxy/index.d.ts +2 -0
  78. package/dist/magic-proxy/index.d.ts.map +1 -0
  79. package/dist/magic-proxy/index.js +6 -0
  80. package/dist/magic-proxy/index.js.map +7 -0
  81. package/dist/magic-proxy/proxy.d.ts +63 -0
  82. package/dist/magic-proxy/proxy.d.ts.map +1 -0
  83. package/dist/magic-proxy/proxy.js +108 -0
  84. package/dist/magic-proxy/proxy.js.map +7 -0
  85. package/dist/polyfills/index.d.ts +2 -0
  86. package/dist/polyfills/index.d.ts.map +1 -0
  87. package/dist/polyfills/index.js +25 -0
  88. package/dist/polyfills/index.js.map +7 -0
  89. package/dist/polyfills/path.d.ts +24 -0
  90. package/dist/polyfills/path.d.ts.map +1 -0
  91. package/dist/polyfills/path.js +174 -0
  92. package/dist/polyfills/path.js.map +7 -0
  93. package/dist/types.d.ts +2 -0
  94. package/dist/types.d.ts.map +1 -0
  95. package/dist/types.js +1 -0
  96. package/dist/types.js.map +7 -0
  97. package/dist/utils/escape-json-pointer.d.ts +7 -0
  98. package/dist/utils/escape-json-pointer.d.ts.map +1 -0
  99. package/dist/utils/escape-json-pointer.js +7 -0
  100. package/dist/utils/escape-json-pointer.js.map +7 -0
  101. package/dist/utils/get-segments-from-path.d.ts +5 -0
  102. package/dist/utils/get-segments-from-path.d.ts.map +1 -0
  103. package/dist/utils/get-segments-from-path.js +11 -0
  104. package/dist/utils/get-segments-from-path.js.map +7 -0
  105. package/dist/utils/is-json-object.d.ts +18 -0
  106. package/dist/utils/is-json-object.d.ts.map +1 -0
  107. package/dist/utils/is-json-object.js +16 -0
  108. package/dist/utils/is-json-object.js.map +7 -0
  109. package/dist/utils/is-object.d.ts +5 -0
  110. package/dist/utils/is-object.d.ts.map +1 -0
  111. package/dist/utils/is-object.js +5 -0
  112. package/dist/utils/is-object.js.map +7 -0
  113. package/dist/utils/is-yaml.d.ts +17 -0
  114. package/dist/utils/is-yaml.d.ts.map +1 -0
  115. package/dist/utils/is-yaml.js +7 -0
  116. package/dist/utils/is-yaml.js.map +7 -0
  117. package/dist/utils/json-path-utils.d.ts +23 -0
  118. package/dist/utils/json-path-utils.d.ts.map +1 -0
  119. package/dist/utils/json-path-utils.js +16 -0
  120. package/dist/utils/json-path-utils.js.map +7 -0
  121. package/dist/utils/normalize.d.ts +5 -0
  122. package/dist/utils/normalize.d.ts.map +1 -0
  123. package/dist/utils/normalize.js +28 -0
  124. package/dist/utils/normalize.js.map +7 -0
  125. package/dist/utils/unescape-json-pointer.d.ts +8 -0
  126. package/dist/utils/unescape-json-pointer.d.ts.map +1 -0
  127. package/dist/utils/unescape-json-pointer.js +7 -0
  128. package/dist/utils/unescape-json-pointer.js.map +7 -0
  129. package/esbuild.ts +13 -0
  130. package/package.json +65 -0
  131. package/src/bundle/bundle.test.ts +1843 -0
  132. package/src/bundle/bundle.ts +758 -0
  133. package/src/bundle/create-limiter.test.ts +28 -0
  134. package/src/bundle/create-limiter.ts +52 -0
  135. package/src/bundle/index.ts +2 -0
  136. package/src/bundle/plugins/browser.ts +4 -0
  137. package/src/bundle/plugins/fetch-urls/index.test.ts +147 -0
  138. package/src/bundle/plugins/fetch-urls/index.ts +94 -0
  139. package/src/bundle/plugins/node.ts +5 -0
  140. package/src/bundle/plugins/parse-json/index.test.ts +22 -0
  141. package/src/bundle/plugins/parse-json/index.ts +30 -0
  142. package/src/bundle/plugins/parse-yaml/index.test.ts +24 -0
  143. package/src/bundle/plugins/parse-yaml/index.ts +31 -0
  144. package/src/bundle/plugins/read-files/index.test.ts +35 -0
  145. package/src/bundle/plugins/read-files/index.ts +55 -0
  146. package/src/bundle/value-generator.test.ts +166 -0
  147. package/src/bundle/value-generator.ts +147 -0
  148. package/src/dereference/dereference.test.ts +137 -0
  149. package/src/dereference/dereference.ts +84 -0
  150. package/src/dereference/index.ts +2 -0
  151. package/src/diff/apply.test.ts +262 -0
  152. package/src/diff/apply.ts +78 -0
  153. package/src/diff/diff.test.ts +328 -0
  154. package/src/diff/diff.ts +94 -0
  155. package/src/diff/index.test.ts +150 -0
  156. package/src/diff/index.ts +5 -0
  157. package/src/diff/merge.test.ts +1109 -0
  158. package/src/diff/merge.ts +136 -0
  159. package/src/diff/trie.test.ts +30 -0
  160. package/src/diff/trie.ts +113 -0
  161. package/src/diff/utils.test.ts +169 -0
  162. package/src/diff/utils.ts +113 -0
  163. package/src/magic-proxy/index.ts +2 -0
  164. package/src/magic-proxy/proxy.test.ts +145 -0
  165. package/src/magic-proxy/proxy.ts +225 -0
  166. package/src/polyfills/index.ts +12 -0
  167. package/src/polyfills/path.ts +248 -0
  168. package/src/types.ts +1 -0
  169. package/src/utils/escape-json-pointer.test.ts +13 -0
  170. package/src/utils/escape-json-pointer.ts +8 -0
  171. package/src/utils/get-segments-from-path.test.ts +17 -0
  172. package/src/utils/get-segments-from-path.ts +17 -0
  173. package/src/utils/is-json-object.ts +31 -0
  174. package/src/utils/is-object.test.ts +27 -0
  175. package/src/utils/is-object.ts +4 -0
  176. package/src/utils/is-yaml.ts +18 -0
  177. package/src/utils/json-path-utils.test.ts +13 -0
  178. package/src/utils/json-path-utils.ts +38 -0
  179. package/src/utils/normalize.test.ts +91 -0
  180. package/src/utils/normalize.ts +34 -0
  181. package/src/utils/unescape-json-pointer.test.ts +23 -0
  182. package/src/utils/unescape-json-pointer.ts +9 -0
  183. package/tsconfig.build.json +12 -0
  184. package/tsconfig.json +16 -0
  185. package/vite.config.ts +8 -0
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Represents the possible types of changes that can be made to a document.
3
+ * - 'add': A new property is added
4
+ * - 'update': An existing property's value is changed
5
+ * - 'delete': A property is removed
6
+ */
7
+ type ChangeType = 'add' | 'update' | 'delete'
8
+
9
+ /**
10
+ * Represents a single difference between two documents.
11
+ * @property path - Array of strings representing the path to the changed property
12
+ * @property changes - The new value for the property (for add/update) or the old value (for delete)
13
+ * @property type - The type of change that occurred
14
+ */
15
+ export type Difference = { path: string[]; changes: any; type: ChangeType }
16
+
17
+ /**
18
+ * Get the difference between two objects.
19
+ *
20
+ * This function performs a breadth-first comparison between two objects and returns
21
+ * a list of operations needed to transform the first object into the second.
22
+ *
23
+ * @param doc1 - The source object to compare from
24
+ * @param doc2 - The target object to compare to
25
+ * @returns A list of operations (add/update/delete) with their paths and changes
26
+ *
27
+ * @example
28
+ * // Compare two simple objects
29
+ * const original = { name: 'John', age: 30 }
30
+ * const updated = { name: 'John', age: 31, city: 'New York' }
31
+ * const differences = diff(original, updated)
32
+ * // Returns:
33
+ * // [
34
+ * // { path: ['age'], changes: 31, type: 'update' },
35
+ * // { path: ['city'], changes: 'New York', type: 'add' }
36
+ * // ]
37
+ *
38
+ * @example
39
+ * // Compare nested objects
40
+ * const original = {
41
+ * user: { name: 'John', settings: { theme: 'light' } }
42
+ * }
43
+ * const updated = {
44
+ * user: { name: 'John', settings: { theme: 'dark' } }
45
+ * }
46
+ * const differences = diff(original, updated)
47
+ * // Returns:
48
+ * // [
49
+ * // { path: ['user', 'settings', 'theme'], changes: 'dark', type: 'update' }
50
+ * // ]
51
+ */
52
+ export const diff = (doc1: Record<string, unknown>, doc2: Record<string, unknown>): Difference[] => {
53
+ const diff: Difference[] = []
54
+
55
+ const bfs = (el1: unknown, el2: unknown, prefix = []) => {
56
+ // If the types are different, we know that the property has been added, deleted or updated
57
+ if (typeof el1 !== typeof el2) {
58
+ if (typeof el1 === 'undefined') {
59
+ diff.push({ path: prefix, changes: el2, type: 'add' })
60
+ return
61
+ }
62
+
63
+ if (typeof el2 === 'undefined') {
64
+ diff.push({ path: prefix, changes: el1, type: 'delete' })
65
+ return
66
+ }
67
+
68
+ diff.push({ path: prefix, changes: el2, type: 'update' })
69
+ return
70
+ }
71
+
72
+ // We now can assume that el1 and el2 are of the same type
73
+
74
+ // For nested objects, we need to recursively check the properties
75
+ if (typeof el1 === 'object' && typeof el2 === 'object' && el1 !== null && el2 !== null) {
76
+ const keys = new Set([...Object.keys(el1), ...Object.keys(el2)])
77
+
78
+ for (const key of keys) {
79
+ // @ts-ignore
80
+ bfs(el1[key], el2[key], [...prefix, key])
81
+ }
82
+ return
83
+ }
84
+
85
+ // For primitives, we can just compare the values
86
+ if (el1 !== el2) {
87
+ diff.push({ path: prefix, changes: el2, type: 'update' })
88
+ }
89
+ }
90
+
91
+ // Run breadth-first search
92
+ bfs(doc1, doc2)
93
+ return diff
94
+ }
@@ -0,0 +1,150 @@
1
+ import { apply } from '@/diff/apply'
2
+ import { diff } from '@/diff/diff'
3
+ import { describe, expect, test } from 'vitest'
4
+
5
+ describe('if we get list of operations we need to perform A -> B, when we apply them on A it should give us B', () => {
6
+ test.each([
7
+ [
8
+ { name: 'John', age: 25 },
9
+ { name: 'Jeremy', age: 25 },
10
+ ],
11
+ [
12
+ {
13
+ name: 'John',
14
+ age: 25,
15
+ interest: {
16
+ cars: { classics: ['Ferrari 250 GTO', 'Chevrolet Camaro'] },
17
+ music: { pop: ['Bruno Mars', 'Justin Bieber'] },
18
+ },
19
+ },
20
+ {
21
+ name: 'John',
22
+ age: 25,
23
+ interest: {
24
+ cars: { classics: ['Ferrari 250 GTO'] },
25
+ music: { rock: ['Eagles', 'AC/DC'] },
26
+ },
27
+ },
28
+ ],
29
+ [{ version: '1.1.0', name: '@scalar/json-diff' }, {}],
30
+ [
31
+ {
32
+ openapi: '3.0.0',
33
+ info: {
34
+ title: 'Simple API',
35
+ description: 'A small OpenAPI specification example',
36
+ version: '1.0.0',
37
+ },
38
+ paths: {
39
+ '/users': {
40
+ get: {
41
+ summary: 'Get a list of users',
42
+ operationId: 'getUsers',
43
+ responses: {
44
+ '200': {
45
+ description: 'A list of users',
46
+ content: {
47
+ 'application/json': {
48
+ schema: {
49
+ type: 'array',
50
+ items: {
51
+ type: 'object',
52
+ properties: {
53
+ id: { type: 'integer' },
54
+ name: { type: 'string' },
55
+ },
56
+ },
57
+ },
58
+ },
59
+ },
60
+ },
61
+ },
62
+ },
63
+ },
64
+ '/users/{id}': {
65
+ get: {
66
+ summary: 'Get a user by ID',
67
+ operationId: 'getUserById',
68
+ parameters: [
69
+ {
70
+ name: 'id',
71
+ in: 'path',
72
+ required: true,
73
+ schema: { type: 'integer' },
74
+ },
75
+ ],
76
+ responses: {
77
+ '200': {
78
+ description: 'User details',
79
+ content: {
80
+ 'application/json': {
81
+ schema: {
82
+ type: 'object',
83
+ properties: {
84
+ id: { type: 'integer' },
85
+ name: { type: 'string' },
86
+ },
87
+ },
88
+ },
89
+ },
90
+ },
91
+ '404': {
92
+ description: 'User not found',
93
+ },
94
+ },
95
+ },
96
+ },
97
+ },
98
+ },
99
+ {
100
+ openapi: '3.0.0',
101
+ info: {
102
+ title: 'Simple API',
103
+ description: 'A big OpenAPI specification example',
104
+ version: '1.0.0',
105
+ },
106
+ paths: {
107
+ '/users': {
108
+ get: {
109
+ summary: 'Get a list of users',
110
+ operationId: 'getUsers',
111
+ responses: {
112
+ '200': {
113
+ description: 'A list of users',
114
+ content: {
115
+ 'application/json': {
116
+ schema: {
117
+ type: 'array',
118
+ items: {
119
+ type: 'object',
120
+ properties: {
121
+ id: { type: 'integer' },
122
+ name: { type: 'string' },
123
+ },
124
+ },
125
+ },
126
+ },
127
+ },
128
+ },
129
+ },
130
+ },
131
+ },
132
+ },
133
+ },
134
+ ],
135
+ [{}, {}],
136
+ [
137
+ {},
138
+ {
139
+ openapi: '3.0.0',
140
+ info: {
141
+ title: 'Simple API',
142
+ description: 'A big OpenAPI specification example',
143
+ version: '1.0.0',
144
+ },
145
+ },
146
+ ],
147
+ ])('apply(a, diff(a, b)) === b', (a, b) => {
148
+ expect(apply(a, diff(a, b))).toEqual(b)
149
+ })
150
+ })
@@ -0,0 +1,5 @@
1
+ import { diff, type Difference } from '@/diff/diff'
2
+ import { apply } from '@/diff/apply'
3
+ import { merge } from '@/diff/merge'
4
+
5
+ export { diff, apply, merge, type Difference }