@sanity/diff-patch 5.0.0 → 7.0.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.
package/src/index.ts CHANGED
@@ -1,20 +1,8 @@
1
- export {diffPatch, diffItem} from './diffPatch.js'
1
+ export {diffPatch, diffValue} from './diffPatch.js'
2
2
  export {DiffError} from './diffError.js'
3
3
 
4
- export type {
5
- DiffMatchPatch,
6
- InsertAfterPatch,
7
- Patch,
8
- SanityDiffMatchPatch,
9
- SanityInsertPatch,
10
- SanityPatch,
11
- SanityPatchMutation,
12
- SanitySetPatch,
13
- SanityUnsetPatch,
14
- SetPatch,
15
- UnsetPatch,
16
- } from './patches.js'
4
+ export type {SanityPatch, SanityPatchMutation, SanityPatchOperations} from './patches.js'
17
5
 
18
- export type {DiffMatchPatchOptions, DiffOptions, DocumentStub, PatchOptions} from './diffPatch.js'
6
+ export type {DocumentStub, PatchOptions} from './diffPatch.js'
19
7
 
20
8
  export type {Path, PathSegment} from './paths.js'
package/src/patches.ts CHANGED
@@ -1,13 +1,12 @@
1
- import type {Path} from './paths.js'
1
+ import type {KeyedSanityObject, Path} from './paths.js'
2
2
 
3
3
  /**
4
4
  * A `set` operation
5
5
  * Replaces the current path, does not merge
6
- * Note: NOT a serializable mutation, see {@link SanitySetPatch} for that
7
6
  *
8
- * @public
7
+ * @internal
9
8
  */
10
- export interface SetPatch {
9
+ interface SetPatch {
11
10
  op: 'set'
12
11
  path: Path
13
12
  value: unknown
@@ -16,9 +15,8 @@ export interface SetPatch {
16
15
  /**
17
16
  * A `unset` operation
18
17
  * Unsets the entire value of the given path
19
- * Note: NOT a serializable mutation, see {@link SanityUnsetPatch} for that
20
18
  *
21
- * @public
19
+ * @internal
22
20
  */
23
21
  export interface UnsetPatch {
24
22
  op: 'unset'
@@ -28,22 +26,21 @@ export interface UnsetPatch {
28
26
  /**
29
27
  * A `insert` operation
30
28
  * Inserts the given items _after_ the given path
31
- * Note: NOT a serializable mutation, see {@link SanityInsertPatch} for that
32
29
  *
33
- * @public
30
+ * @internal
34
31
  */
35
- export interface InsertAfterPatch {
32
+ interface InsertPatch {
36
33
  op: 'insert'
37
- after: Path
34
+ position: 'before' | 'after' | 'replace'
35
+ path: Path
38
36
  items: any[]
39
37
  }
40
38
 
41
39
  /**
42
40
  * A `diffMatchPatch` operation
43
41
  * Applies the given `value` (unidiff format) to the given path. Must be a string.
44
- * Note: NOT a serializable mutation, see {@link SanityDiffMatchPatch} for that
45
42
  *
46
- * @public
43
+ * @internal
47
44
  */
48
45
  export interface DiffMatchPatch {
49
46
  op: 'diffMatchPatch'
@@ -52,11 +49,25 @@ export interface DiffMatchPatch {
52
49
  }
53
50
 
54
51
  /**
55
- * A patch containing either a Sanity set, unset, insert or diffMatchPatch operation
52
+ * A `reorder` operation used to ...
53
+ *
54
+ * Note: NOT a serializable mutation.
56
55
  *
57
56
  * @public
58
57
  */
59
- export type Patch = SetPatch | UnsetPatch | InsertAfterPatch | DiffMatchPatch
58
+ export interface ReorderPatch {
59
+ op: 'reorder'
60
+ path: Path
61
+ snapshot: KeyedSanityObject[]
62
+ reorders: {sourceKey: string; targetKey: string}[]
63
+ }
64
+
65
+ /**
66
+ * Internal patch representation used during diff generation
67
+ *
68
+ * @internal
69
+ */
70
+ export type Patch = SetPatch | UnsetPatch | InsertPatch | DiffMatchPatch | ReorderPatch
60
71
 
61
72
  /**
62
73
  * A Sanity `set` patch mutation operation
@@ -64,9 +75,8 @@ export type Patch = SetPatch | UnsetPatch | InsertAfterPatch | DiffMatchPatch
64
75
  *
65
76
  * @public
66
77
  */
67
- export interface SanitySetPatch {
68
- id: string
69
- set: {[key: string]: any}
78
+ export interface SanitySetPatchOperation {
79
+ set: Record<string, unknown>
70
80
  }
71
81
 
72
82
  /**
@@ -75,8 +85,7 @@ export interface SanitySetPatch {
75
85
  *
76
86
  * @public
77
87
  */
78
- export interface SanityUnsetPatch {
79
- id: string
88
+ export interface SanityUnsetPatchOperation {
80
89
  unset: string[]
81
90
  }
82
91
 
@@ -86,12 +95,11 @@ export interface SanityUnsetPatch {
86
95
  *
87
96
  * @public
88
97
  */
89
- export interface SanityInsertPatch {
90
- id: string
98
+ export interface SanityInsertPatchOperation {
91
99
  insert:
92
- | {before: string; items: any[]}
93
- | {after: string; items: any[]}
94
- | {replace: string; items: any[]}
100
+ | {before: string; items: unknown[]}
101
+ | {after: string; items: unknown[]}
102
+ | {replace: string; items: unknown[]}
95
103
  }
96
104
 
97
105
  /**
@@ -100,21 +108,34 @@ export interface SanityInsertPatch {
100
108
  *
101
109
  * @public
102
110
  */
103
- export interface SanityDiffMatchPatch {
104
- id: string
105
- diffMatchPatch: {[key: string]: string}
111
+ export interface SanityDiffMatchPatchOperation {
112
+ diffMatchPatch: Record<string, string>
106
113
  }
107
114
 
108
115
  /**
109
- * A patch containing either a set, unset, insert or diffMatchPatch operation
116
+ * Serializable patch operations that can be applied to a Sanity document.
117
+ *
118
+ * @public
119
+ */
120
+ export type SanityPatchOperations = Partial<
121
+ SanitySetPatchOperation &
122
+ SanityUnsetPatchOperation &
123
+ SanityInsertPatchOperation &
124
+ SanityDiffMatchPatchOperation
125
+ >
126
+
127
+ /**
128
+ * Meant to be used as the body of a {@link SanityPatchMutation}'s `patch` key.
129
+ *
130
+ * Contains additional properties to target a particular ID and optionally add
131
+ * an optimistic lock via [`ifRevisionID`](https://www.sanity.io/docs/content-lake/transactions#k29b2c75639d5).
110
132
  *
111
133
  * @public
112
134
  */
113
- export type SanityPatch =
114
- | SanitySetPatch
115
- | SanityUnsetPatch
116
- | SanityInsertPatch
117
- | SanityDiffMatchPatch
135
+ export interface SanityPatch extends SanityPatchOperations {
136
+ id: string
137
+ ifRevisionID?: string
138
+ }
118
139
 
119
140
  /**
120
141
  * A mutation containing a single patch
package/src/paths.ts CHANGED
@@ -1,5 +1,3 @@
1
- import type {KeyedSanityObject} from './diffPatch.js'
2
-
3
1
  const IS_DOTTABLE_RE = /^[A-Za-z_][A-Za-z0-9_]*$/
4
2
 
5
3
  /**
@@ -54,6 +52,16 @@ export function pathToString(path: Path): string {
54
52
  }, '')
55
53
  }
56
54
 
57
- function isKeyedObject(obj: any): obj is KeyedSanityObject {
58
- return typeof obj === 'object' && typeof obj._key === 'string'
55
+ /**
56
+ * An object (record) that has a `_key` property
57
+ *
58
+ * @internal
59
+ */
60
+ export interface KeyedSanityObject {
61
+ [key: string]: unknown
62
+ _key: string
63
+ }
64
+
65
+ export function isKeyedObject(obj: unknown): obj is KeyedSanityObject {
66
+ return typeof obj === 'object' && !!obj && '_key' in obj && typeof obj._key === 'string'
59
67
  }
@@ -0,0 +1,29 @@
1
+ /// <reference lib="esnext" />
2
+
3
+ export function difference<T>(source: Set<T>, target: Set<T>): Set<T> {
4
+ if ('difference' in Set.prototype) {
5
+ return source.difference(target)
6
+ }
7
+
8
+ const result = new Set<T>()
9
+ for (const item of source) {
10
+ if (!target.has(item)) {
11
+ result.add(item)
12
+ }
13
+ }
14
+ return result
15
+ }
16
+
17
+ export function intersection<T>(source: Set<T>, target: Set<T>): Set<T> {
18
+ if ('intersection' in Set.prototype) {
19
+ return source.intersection(target)
20
+ }
21
+
22
+ const result = new Set<T>()
23
+ for (const item of source) {
24
+ if (target.has(item)) {
25
+ result.add(item)
26
+ }
27
+ }
28
+ return result
29
+ }
package/dist/index.cjs DELETED
@@ -1,251 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: !0 });
3
- var diffMatchPatch = require("@sanity/diff-match-patch");
4
- const IS_DOTTABLE_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
5
- function pathToString(path) {
6
- return path.reduce((target, segment, i) => {
7
- if (Array.isArray(segment))
8
- return `${target}[${segment.join(":")}]`;
9
- if (isKeyedObject(segment))
10
- return `${target}[_key=="${segment._key}"]`;
11
- if (typeof segment == "number")
12
- return `${target}[${segment}]`;
13
- if (typeof segment == "string" && !IS_DOTTABLE_RE.test(segment))
14
- return `${target}['${segment}']`;
15
- if (typeof segment == "string")
16
- return `${target}${i === 0 ? "" : "."}${segment}`;
17
- throw new Error(`Unsupported path segment "${segment}"`);
18
- }, "");
19
- }
20
- function isKeyedObject(obj) {
21
- return typeof obj == "object" && typeof obj._key == "string";
22
- }
23
- class DiffError extends Error {
24
- path;
25
- value;
26
- serializedPath;
27
- constructor(message, path, value) {
28
- const serializedPath = pathToString(path);
29
- super(`${message} (at '${serializedPath}')`), this.path = path, this.serializedPath = serializedPath, this.value = value;
30
- }
31
- }
32
- const idPattern = /^[a-z0-9][a-z0-9_.-]+$/i, propPattern = /^[a-zA-Z_][a-zA-Z0-9_-]*$/, propStartPattern = /^[a-z_]/i;
33
- function validateProperty(property, value, path) {
34
- if (!propStartPattern.test(property))
35
- throw new DiffError("Keys must start with a letter (a-z)", path.concat(property), value);
36
- if (!propPattern.test(property))
37
- throw new DiffError(
38
- "Keys can only contain letters, numbers and underscores",
39
- path.concat(property),
40
- value
41
- );
42
- if (property === "_key" || property === "_ref" || property === "_type") {
43
- if (typeof value != "string")
44
- throw new DiffError("Keys must be strings", path.concat(property), value);
45
- if (!idPattern.test(value))
46
- throw new DiffError("Invalid key - use less exotic characters", path.concat(property), value);
47
- }
48
- return property;
49
- }
50
- const ignoredKeys = ["_id", "_type", "_createdAt", "_updatedAt", "_rev"], defaultOptions = {
51
- hideWarnings: !1,
52
- diffMatchPatch: {
53
- enabled: !0,
54
- // Only use diff-match-patch if target string is longer than this threshold
55
- lengthThresholdAbsolute: 30,
56
- // Only use generated diff-match-patch if the patch length is less than or equal to
57
- // (targetString * relative). Example: A 100 character target with a relative factor
58
- // of 1.2 will allow a 120 character diff-match-patch. If larger than this number,
59
- // it will fall back to a regular `set` patch.
60
- lengthThresholdRelative: 1.2
61
- }
62
- };
63
- function mergeOptions(options) {
64
- return {
65
- ...defaultOptions,
66
- ...options,
67
- diffMatchPatch: { ...defaultOptions.diffMatchPatch, ...options.diffMatchPatch || {} }
68
- };
69
- }
70
- function diffPatch(itemA, itemB, opts) {
71
- const options = mergeOptions(opts || {}), id = options.id || itemA._id === itemB._id && itemA._id, revisionLocked = options.ifRevisionID, ifRevisionID = typeof revisionLocked == "boolean" ? itemA._rev : revisionLocked, basePath = options.basePath || [];
72
- if (!id)
73
- throw new Error(
74
- "_id on itemA and itemB not present or differs, specify document id the mutations should be applied to"
75
- );
76
- if (revisionLocked === !0 && !ifRevisionID)
77
- throw new Error(
78
- "`ifRevisionID` is set to `true`, but no `_rev` was passed in item A. Either explicitly set `ifRevisionID` to a revision, or pass `_rev` as part of item A."
79
- );
80
- if (basePath.length === 0 && itemA._type !== itemB._type)
81
- throw new Error(`_type is immutable and cannot be changed (${itemA._type} => ${itemB._type})`);
82
- const operations = diffItem(itemA, itemB, options, basePath, []);
83
- return serializePatches(operations, { id, ifRevisionID: revisionLocked ? ifRevisionID : void 0 });
84
- }
85
- function diffItem(itemA, itemB, opts = defaultOptions, path = [], patches = []) {
86
- if (itemA === itemB)
87
- return patches;
88
- const aType = Array.isArray(itemA) ? "array" : typeof itemA, bType = Array.isArray(itemB) ? "array" : typeof itemB, aIsUndefined = aType === "undefined", bIsUndefined = bType === "undefined";
89
- if (aIsUndefined && !bIsUndefined)
90
- return patches.push({ op: "set", path, value: itemB }), patches;
91
- if (!aIsUndefined && bIsUndefined)
92
- return patches.push({ op: "unset", path }), patches;
93
- const options = mergeOptions(opts), dataType = aIsUndefined ? bType : aType;
94
- return dataType === "object" || dataType === "array" ? aType !== bType ? (patches.push({ op: "set", path, value: itemB }), patches) : dataType === "array" ? diffArray(itemA, itemB, options, path, patches) : diffObject(itemA, itemB, options, path, patches) : diffPrimitive(itemA, itemB, options, path, patches);
95
- }
96
- function diffObject(itemA, itemB, options, path, patches) {
97
- const atRoot = path.length === 0, aKeys = Object.keys(itemA).filter(atRoot ? isNotIgnoredKey : yes).map((key) => validateProperty(key, itemA[key], path)), aKeysLength = aKeys.length, bKeys = Object.keys(itemB).filter(atRoot ? isNotIgnoredKey : yes).map((key) => validateProperty(key, itemB[key], path)), bKeysLength = bKeys.length;
98
- for (let i = 0; i < aKeysLength; i++) {
99
- const key = aKeys[i];
100
- key in itemB || patches.push({ op: "unset", path: path.concat(key) });
101
- }
102
- for (let i = 0; i < bKeysLength; i++) {
103
- const key = bKeys[i];
104
- diffItem(itemA[key], itemB[key], options, path.concat([key]), patches);
105
- }
106
- return patches;
107
- }
108
- function diffArray(itemA, itemB, options, path, patches) {
109
- if (itemB.length > itemA.length && patches.push({
110
- op: "insert",
111
- after: path.concat([-1]),
112
- items: itemB.slice(itemA.length).map((item, i) => nullifyUndefined(item, path, i, options))
113
- }), itemB.length < itemA.length) {
114
- const isSingle = itemA.length - itemB.length === 1, unsetItems = itemA.slice(itemB.length);
115
- isRevisionLocked(options) || !isUniquelyKeyed(unsetItems) ? patches.push({
116
- op: "unset",
117
- path: path.concat([isSingle ? itemB.length : [itemB.length, ""]])
118
- }) : patches.push(
119
- ...unsetItems.map(
120
- (item) => ({ op: "unset", path: path.concat({ _key: item._key }) })
121
- )
122
- );
123
- }
124
- for (let i = 0; i < itemB.length; i++)
125
- if (Array.isArray(itemB[i]))
126
- throw new DiffError("Multi-dimensional arrays not supported", path.concat(i), itemB[i]);
127
- const overlapping = Math.min(itemA.length, itemB.length), segmentA = itemA.slice(0, overlapping), segmentB = itemB.slice(0, overlapping);
128
- return isUniquelyKeyed(segmentA) && isUniquelyKeyed(segmentB) ? diffArrayByKey(segmentA, segmentB, options, path, patches) : diffArrayByIndex(segmentA, segmentB, options, path, patches);
129
- }
130
- function diffArrayByIndex(itemA, itemB, options, path, patches) {
131
- for (let i = 0; i < itemA.length; i++)
132
- diffItem(
133
- itemA[i],
134
- nullifyUndefined(itemB[i], path, i, options),
135
- options,
136
- path.concat(i),
137
- patches
138
- );
139
- return patches;
140
- }
141
- function diffArrayByKey(itemA, itemB, options, path, patches) {
142
- const keyedA = indexByKey(itemA), keyedB = indexByKey(itemB);
143
- if (!arrayIsEqual(keyedA.keys, keyedB.keys))
144
- return diffArrayByIndex(itemA, itemB, options, path, patches);
145
- for (let i = 0; i < keyedB.keys.length; i++) {
146
- const key = keyedB.keys[i], valueA = keyedA.index[key], valueB = nullifyUndefined(keyedB.index[key], path, i, options);
147
- diffItem(valueA, valueB, options, path.concat({ _key: key }), patches);
148
- }
149
- return patches;
150
- }
151
- function getDiffMatchPatch(itemA, itemB, options, path) {
152
- const { enabled, lengthThresholdRelative, lengthThresholdAbsolute } = options.diffMatchPatch, segment = path[path.length - 1];
153
- if (!enabled || // Don't use for anything but strings
154
- typeof itemA != "string" || typeof itemB != "string" || // Don't use for `_key`, `_ref` etc
155
- typeof segment == "string" && segment[0] === "_" || // Don't use on short strings
156
- itemB.length < lengthThresholdAbsolute)
157
- return;
158
- let strPatch = "";
159
- try {
160
- const patch = diffMatchPatch.makeDiff(itemA, itemB), diff = diffMatchPatch.cleanupEfficiency(patch);
161
- strPatch = diffMatchPatch.stringifyPatches(diffMatchPatch.makePatches(diff));
162
- } catch {
163
- return;
164
- }
165
- return strPatch.length > itemB.length * lengthThresholdRelative ? void 0 : { op: "diffMatchPatch", path, value: strPatch };
166
- }
167
- function diffPrimitive(itemA, itemB, options, path, patches) {
168
- const dmp = getDiffMatchPatch(itemA, itemB, options, path);
169
- return patches.push(
170
- dmp || {
171
- op: "set",
172
- path,
173
- value: itemB
174
- }
175
- ), patches;
176
- }
177
- function isNotIgnoredKey(key) {
178
- return ignoredKeys.indexOf(key) === -1;
179
- }
180
- function serializePatches(patches, options) {
181
- if (patches.length === 0)
182
- return [];
183
- const { id, ifRevisionID } = options, set = patches.filter((patch) => patch.op === "set"), unset = patches.filter((patch) => patch.op === "unset"), insert = patches.filter((patch) => patch.op === "insert"), dmp = patches.filter((patch) => patch.op === "diffMatchPatch"), withSet = set.length > 0 && set.reduce(
184
- (patch, item) => {
185
- const path = pathToString(item.path);
186
- return patch.set[path] = item.value, patch;
187
- },
188
- { id, set: {} }
189
- ), withUnset = unset.length > 0 && unset.reduce(
190
- (patch, item) => {
191
- const path = pathToString(item.path);
192
- return patch.unset.push(path), patch;
193
- },
194
- { id, unset: [] }
195
- ), withInsert = insert.reduce((acc, item) => {
196
- const after = pathToString(item.after);
197
- return acc.concat({ id, insert: { after, items: item.items } });
198
- }, []), withDmp = dmp.length > 0 && dmp.reduce(
199
- (patch, item) => {
200
- const path = pathToString(item.path);
201
- return patch.diffMatchPatch[path] = item.value, patch;
202
- },
203
- { id, diffMatchPatch: {} }
204
- );
205
- return [withUnset, withSet, withDmp, ...withInsert].filter(
206
- (item) => item !== !1
207
- ).map((patch, i) => ({
208
- patch: ifRevisionID && i === 0 ? { ...patch, ifRevisionID } : patch
209
- }));
210
- }
211
- function isUniquelyKeyed(arr) {
212
- const keys = [];
213
- for (let i = 0; i < arr.length; i++) {
214
- const key = getKey(arr[i]);
215
- if (!key || keys.indexOf(key) !== -1)
216
- return !1;
217
- keys.push(key);
218
- }
219
- return !0;
220
- }
221
- function getKey(obj) {
222
- return typeof obj == "object" && obj !== null && obj._key;
223
- }
224
- function indexByKey(arr) {
225
- return arr.reduce(
226
- (acc, item) => (acc.keys.push(item._key), acc.index[item._key] = item, acc),
227
- { keys: [], index: {} }
228
- );
229
- }
230
- function arrayIsEqual(itemA, itemB) {
231
- return itemA.length === itemB.length && itemA.every((item, i) => itemB[i] === item);
232
- }
233
- function nullifyUndefined(item, path, index, options) {
234
- if (typeof item < "u")
235
- return item;
236
- if (!options.hideWarnings) {
237
- const serializedPath = pathToString(path.concat(index));
238
- console.warn(`undefined value in array converted to null (at '${serializedPath}')`);
239
- }
240
- return null;
241
- }
242
- function isRevisionLocked(options) {
243
- return !!options.ifRevisionID;
244
- }
245
- function yes(_) {
246
- return !0;
247
- }
248
- exports.DiffError = DiffError;
249
- exports.diffItem = diffItem;
250
- exports.diffPatch = diffPatch;
251
- //# sourceMappingURL=index.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/paths.ts","../src/diffError.ts","../src/validate.ts","../src/diffPatch.ts"],"sourcesContent":["import type {KeyedSanityObject} from './diffPatch.js'\n\nconst IS_DOTTABLE_RE = /^[A-Za-z_][A-Za-z0-9_]*$/\n\n/**\n * A segment of a path\n *\n * @public\n */\nexport type PathSegment =\n | string // Property\n | number // Array index\n | {_key: string} // Array `_key` lookup\n | [number | '', number | ''] // From/to array index\n\n/**\n * An array of path segments representing a path in a document\n *\n * @public\n */\nexport type Path = PathSegment[]\n\n/**\n * Converts an array path to a string path\n *\n * @param path - The array path to convert\n * @returns A stringified path\n * @internal\n */\nexport function pathToString(path: Path): string {\n return path.reduce((target: string, segment: PathSegment, i: number) => {\n if (Array.isArray(segment)) {\n return `${target}[${segment.join(':')}]`\n }\n\n if (isKeyedObject(segment)) {\n return `${target}[_key==\"${segment._key}\"]`\n }\n\n if (typeof segment === 'number') {\n return `${target}[${segment}]`\n }\n\n if (typeof segment === 'string' && !IS_DOTTABLE_RE.test(segment)) {\n return `${target}['${segment}']`\n }\n\n if (typeof segment === 'string') {\n const separator = i === 0 ? '' : '.'\n return `${target}${separator}${segment}`\n }\n\n throw new Error(`Unsupported path segment \"${segment}\"`)\n }, '')\n}\n\nfunction isKeyedObject(obj: any): obj is KeyedSanityObject {\n return typeof obj === 'object' && typeof obj._key === 'string'\n}\n","import {type Path, pathToString} from './paths.js'\n\n/**\n * Represents an error that occurred during a diff process.\n * Contains `path`, `value` and `serializedPath` properties,\n * which is helpful for debugging and showing friendly messages.\n *\n * @public\n */\nexport class DiffError extends Error {\n public path: Path\n public value: unknown\n public serializedPath: string\n\n constructor(message: string, path: Path, value?: unknown) {\n const serializedPath = pathToString(path)\n super(`${message} (at '${serializedPath}')`)\n\n this.path = path\n this.serializedPath = serializedPath\n this.value = value\n }\n}\n","import {DiffError} from './diffError.js'\nimport type {Path} from './paths.js'\n\nconst idPattern = /^[a-z0-9][a-z0-9_.-]+$/i\nconst propPattern = /^[a-zA-Z_][a-zA-Z0-9_-]*$/\nconst propStartPattern = /^[a-z_]/i\n\n/**\n * Validate the given document/subtree for Sanity compatibility\n *\n * @param item - The document or subtree to validate\n * @param path - The path to the current item, for error reporting\n * @returns True if valid, throws otherwise\n * @internal\n */\nexport function validateDocument(item: unknown, path: Path = []): boolean {\n if (Array.isArray(item)) {\n return item.every((child, i) => {\n if (Array.isArray(child)) {\n throw new DiffError('Multi-dimensional arrays not supported', path.concat(i))\n }\n\n return validateDocument(child, path.concat(i))\n })\n }\n\n if (typeof item === 'object' && item !== null) {\n const obj = item as {[key: string]: any}\n return Object.keys(obj).every(\n (key) =>\n validateProperty(key, obj[key], path) && validateDocument(obj[key], path.concat(key)),\n )\n }\n\n return true\n}\n\n/**\n * Validate a property for Sanity compatibility\n *\n * @param property - The property to valide\n * @param value - The value of the property\n * @param path - The path of the property, for error reporting\n * @returns The property name, if valid\n * @internal\n */\nexport function validateProperty(property: string, value: unknown, path: Path): string {\n if (!propStartPattern.test(property)) {\n throw new DiffError('Keys must start with a letter (a-z)', path.concat(property), value)\n }\n\n if (!propPattern.test(property)) {\n throw new DiffError(\n 'Keys can only contain letters, numbers and underscores',\n path.concat(property),\n value,\n )\n }\n\n if (property === '_key' || property === '_ref' || property === '_type') {\n if (typeof value !== 'string') {\n throw new DiffError('Keys must be strings', path.concat(property), value)\n }\n\n if (!idPattern.test(value)) {\n throw new DiffError('Invalid key - use less exotic characters', path.concat(property), value)\n }\n }\n\n return property\n}\n","import {cleanupEfficiency, makeDiff, makePatches, stringifyPatches} from '@sanity/diff-match-patch'\nimport {DiffError} from './diffError.js'\nimport {type Path, pathToString} from './paths.js'\nimport {validateProperty} from './validate.js'\nimport {\n type Patch,\n type SetPatch,\n type UnsetPatch,\n type InsertAfterPatch,\n type DiffMatchPatch,\n type SanityInsertPatch,\n type SanityPatch,\n type SanitySetPatch,\n type SanityUnsetPatch,\n type SanityDiffMatchPatch,\n type SanityPatchMutation,\n} from './patches.js'\n\nconst ignoredKeys = ['_id', '_type', '_createdAt', '_updatedAt', '_rev']\n\ntype PrimitiveValue = string | number | boolean | null | undefined\n\n/**\n * An object (record) that has a `_key` property\n *\n * @internal\n */\nexport interface KeyedSanityObject {\n [key: string]: unknown\n _key: string\n}\n\n/**\n * An object (record) that _may_ have a `_key` property\n *\n * @internal\n */\nexport type SanityObject = KeyedSanityObject | Partial<KeyedSanityObject>\n\n/**\n * Represents a partial Sanity document (eg a \"stub\").\n *\n * @public\n */\nexport interface DocumentStub {\n _id?: string\n _type?: string\n _rev?: string\n _createdAt?: string\n _updatedAt?: string\n [key: string]: unknown\n}\n\n/**\n * Options for the diff-match-patch algorithm.\n *\n * @public\n */\nexport interface DiffMatchPatchOptions {\n /**\n * Whether or not to use diff-match-patch at all\n *\n * @defaultValue `true`\n */\n enabled: boolean\n\n /**\n * Threshold at which to start using diff-match-patch instead of a regular `set` patch.\n *\n * @defaultValue `30`\n */\n lengthThresholdAbsolute: number\n\n /**\n * Only use generated diff-match-patch if the patch length is less than or equal to\n * (targetString * relative). Example: A 100 character target with a relative factor\n * of 1.2 will allow a 120 character diff-match-patch. If larger than this number,\n * it will fall back to a regular `set` patch.\n *\n * @defaultValue `1.2`\n */\n lengthThresholdRelative: number\n}\n\n/**\n * Options for the patch generator\n *\n * @public\n */\nexport interface PatchOptions {\n /**\n * Document ID to apply the patch to.\n *\n * @defaultValue `undefined` - tries to extract `_id` from passed document\n */\n id?: string\n\n /**\n * Base path to apply the patch to - useful if diffing sub-branches of a document.\n *\n * @defaultValue `[]` - eg root of the document\n */\n basePath?: Path\n\n /**\n * Only apply the patch if the document revision matches this value.\n * If the property is the boolean value `true`, it will attempt to extract\n * the revision from the document `_rev` property.\n *\n * @defaultValue `undefined` (do not apply revision check)\n */\n ifRevisionID?: string | true\n\n /**\n * Whether or not to hide warnings during the diff process.\n *\n * @defaultValue `false`\n */\n hideWarnings?: boolean\n\n /**\n * Options for the diff-match-patch algorithm.\n */\n diffMatchPatch?: Partial<DiffMatchPatchOptions>\n}\n\n/**\n * Options for diff generation, where all DMP properties are required\n *\n * @public\n */\nexport type DiffOptions = PatchOptions & {diffMatchPatch: Required<DiffMatchPatchOptions>}\n\nconst defaultOptions = {\n hideWarnings: false,\n diffMatchPatch: {\n enabled: true,\n\n // Only use diff-match-patch if target string is longer than this threshold\n lengthThresholdAbsolute: 30,\n\n // Only use generated diff-match-patch if the patch length is less than or equal to\n // (targetString * relative). Example: A 100 character target with a relative factor\n // of 1.2 will allow a 120 character diff-match-patch. If larger than this number,\n // it will fall back to a regular `set` patch.\n lengthThresholdRelative: 1.2,\n },\n} satisfies DiffOptions\n\n/**\n * Merges the default options with the passed in options.\n *\n * @param options - Options to merge with the defaults\n * @returns Merged options\n */\nfunction mergeOptions(options: PatchOptions): DiffOptions {\n return {\n ...defaultOptions,\n ...options,\n diffMatchPatch: {...defaultOptions.diffMatchPatch, ...(options.diffMatchPatch || {})},\n }\n}\n\n/**\n * Generates an array of mutations for Sanity, based on the differences between\n * the two passed documents/trees.\n *\n * @param itemA - The first document/tree to compare\n * @param itemB - The second document/tree to compare\n * @param opts - Options for the diff generation\n * @returns Array of mutations\n * @public\n */\nexport function diffPatch(\n itemA: DocumentStub,\n itemB: DocumentStub,\n opts?: PatchOptions,\n): SanityPatchMutation[] {\n const options = mergeOptions(opts || {})\n const id = options.id || (itemA._id === itemB._id && itemA._id)\n const revisionLocked = options.ifRevisionID\n const ifRevisionID = typeof revisionLocked === 'boolean' ? itemA._rev : revisionLocked\n const basePath = options.basePath || []\n if (!id) {\n throw new Error(\n '_id on itemA and itemB not present or differs, specify document id the mutations should be applied to',\n )\n }\n\n if (revisionLocked === true && !ifRevisionID) {\n throw new Error(\n '`ifRevisionID` is set to `true`, but no `_rev` was passed in item A. Either explicitly set `ifRevisionID` to a revision, or pass `_rev` as part of item A.',\n )\n }\n\n if (basePath.length === 0 && itemA._type !== itemB._type) {\n throw new Error(`_type is immutable and cannot be changed (${itemA._type} => ${itemB._type})`)\n }\n\n const operations = diffItem(itemA, itemB, options, basePath, [])\n return serializePatches(operations, {id, ifRevisionID: revisionLocked ? ifRevisionID : undefined})\n}\n\n/**\n * Diffs two items and returns an array of patches.\n * Note that this is different from `diffPatch`, which generates _mutations_.\n *\n * @param itemA - The first item to compare\n * @param itemB - The second item to compare\n * @param opts - Options for the diff generation\n * @param path - Path to the current item\n * @param patches - Array of patches to append the results to. Note that this is MUTATED.\n * @returns Array of patches\n * @public\n */\nexport function diffItem(\n itemA: unknown,\n itemB: unknown,\n opts: DiffOptions = defaultOptions,\n path: Path = [],\n patches: Patch[] = [],\n): Patch[] {\n if (itemA === itemB) {\n return patches\n }\n\n const aType = Array.isArray(itemA) ? 'array' : typeof itemA\n const bType = Array.isArray(itemB) ? 'array' : typeof itemB\n\n const aIsUndefined = aType === 'undefined'\n const bIsUndefined = bType === 'undefined'\n\n if (aIsUndefined && !bIsUndefined) {\n patches.push({op: 'set', path, value: itemB})\n return patches\n }\n\n if (!aIsUndefined && bIsUndefined) {\n patches.push({op: 'unset', path})\n return patches\n }\n\n const options = mergeOptions(opts)\n const dataType = aIsUndefined ? bType : aType\n const isContainer = dataType === 'object' || dataType === 'array'\n if (!isContainer) {\n return diffPrimitive(itemA as PrimitiveValue, itemB as PrimitiveValue, options, path, patches)\n }\n\n if (aType !== bType) {\n // Array => Object / Object => Array\n patches.push({op: 'set', path, value: itemB})\n return patches\n }\n\n return dataType === 'array'\n ? diffArray(itemA as unknown[], itemB as unknown[], options, path, patches)\n : diffObject(itemA as object, itemB as object, options, path, patches)\n}\n\nfunction diffObject(\n itemA: SanityObject,\n itemB: SanityObject,\n options: DiffOptions,\n path: Path,\n patches: Patch[],\n) {\n const atRoot = path.length === 0\n const aKeys = Object.keys(itemA)\n .filter(atRoot ? isNotIgnoredKey : yes)\n .map((key) => validateProperty(key, itemA[key], path))\n\n const aKeysLength = aKeys.length\n const bKeys = Object.keys(itemB)\n .filter(atRoot ? isNotIgnoredKey : yes)\n .map((key) => validateProperty(key, itemB[key], path))\n\n const bKeysLength = bKeys.length\n\n // Check for deleted items\n for (let i = 0; i < aKeysLength; i++) {\n const key = aKeys[i]\n if (!(key in itemB)) {\n patches.push({op: 'unset', path: path.concat(key)})\n }\n }\n\n // Check for changed items\n for (let i = 0; i < bKeysLength; i++) {\n const key = bKeys[i]\n diffItem(itemA[key], itemB[key], options, path.concat([key]), patches)\n }\n\n return patches\n}\n\nfunction diffArray(\n itemA: unknown[],\n itemB: unknown[],\n options: DiffOptions,\n path: Path,\n patches: Patch[],\n) {\n // Check for new items\n if (itemB.length > itemA.length) {\n patches.push({\n op: 'insert',\n after: path.concat([-1]),\n items: itemB.slice(itemA.length).map((item, i) => nullifyUndefined(item, path, i, options)),\n })\n }\n\n // Check for deleted items\n if (itemB.length < itemA.length) {\n const isSingle = itemA.length - itemB.length === 1\n const unsetItems = itemA.slice(itemB.length)\n\n // If we're revision locked, we can safely unset ranges (eg 5:<end-of-array>).\n // Also, if we don't have unique array keys, we can't use any better approach\n // than array indexes. If we _do_ have unique array keys, we'll want to unset\n // by key, as this is safer in a realtime, collaborative setting\n if (isRevisionLocked(options) || !isUniquelyKeyed(unsetItems)) {\n patches.push({\n op: 'unset',\n path: path.concat([isSingle ? itemB.length : [itemB.length, '']]),\n })\n } else {\n patches.push(\n ...unsetItems.map(\n (item): UnsetPatch => ({op: 'unset', path: path.concat({_key: item._key})}),\n ),\n )\n }\n }\n\n // Check for illegal array contents\n for (let i = 0; i < itemB.length; i++) {\n if (Array.isArray(itemB[i])) {\n throw new DiffError('Multi-dimensional arrays not supported', path.concat(i), itemB[i])\n }\n }\n\n const overlapping = Math.min(itemA.length, itemB.length)\n const segmentA = itemA.slice(0, overlapping)\n const segmentB = itemB.slice(0, overlapping)\n\n return isUniquelyKeyed(segmentA) && isUniquelyKeyed(segmentB)\n ? diffArrayByKey(segmentA, segmentB, options, path, patches)\n : diffArrayByIndex(segmentA, segmentB, options, path, patches)\n}\n\nfunction diffArrayByIndex(\n itemA: unknown[],\n itemB: unknown[],\n options: DiffOptions,\n path: Path,\n patches: Patch[],\n) {\n for (let i = 0; i < itemA.length; i++) {\n diffItem(\n itemA[i],\n nullifyUndefined(itemB[i], path, i, options),\n options,\n path.concat(i),\n patches,\n )\n }\n\n return patches\n}\n\nfunction diffArrayByKey(\n itemA: KeyedSanityObject[],\n itemB: KeyedSanityObject[],\n options: DiffOptions,\n path: Path,\n patches: Patch[],\n) {\n const keyedA = indexByKey(itemA)\n const keyedB = indexByKey(itemB)\n\n // There's a bunch of hard/semi-hard problems related to using keys\n // Unless we have the exact same order, just use indexes for now\n if (!arrayIsEqual(keyedA.keys, keyedB.keys)) {\n return diffArrayByIndex(itemA, itemB, options, path, patches)\n }\n\n for (let i = 0; i < keyedB.keys.length; i++) {\n const key = keyedB.keys[i]\n const valueA = keyedA.index[key]\n const valueB = nullifyUndefined(keyedB.index[key], path, i, options)\n diffItem(valueA, valueB, options, path.concat({_key: key}), patches)\n }\n\n return patches\n}\n\nfunction getDiffMatchPatch(\n itemA: PrimitiveValue,\n itemB: PrimitiveValue,\n options: DiffOptions,\n path: Path,\n): DiffMatchPatch | undefined {\n const {enabled, lengthThresholdRelative, lengthThresholdAbsolute} = options.diffMatchPatch\n const segment = path[path.length - 1]\n if (\n !enabled ||\n // Don't use for anything but strings\n typeof itemA !== 'string' ||\n typeof itemB !== 'string' ||\n // Don't use for `_key`, `_ref` etc\n (typeof segment === 'string' && segment[0] === '_') ||\n // Don't use on short strings\n itemB.length < lengthThresholdAbsolute\n ) {\n return undefined\n }\n\n let strPatch = ''\n try {\n const patch = makeDiff(itemA, itemB)\n const diff = cleanupEfficiency(patch)\n strPatch = stringifyPatches(makePatches(diff))\n } catch (err) {\n // Fall back to using regular set patch\n return undefined\n }\n\n // Don't use patch if it's longer than allowed relative threshold.\n // Allow a 120 character patch for a 100 character string,\n // but don't allow a 800 character patch for a 500 character value.\n return strPatch.length > itemB.length * lengthThresholdRelative\n ? undefined\n : {op: 'diffMatchPatch', path, value: strPatch}\n}\n\nfunction diffPrimitive(\n itemA: PrimitiveValue,\n itemB: PrimitiveValue,\n options: DiffOptions,\n path: Path,\n patches: Patch[],\n): Patch[] {\n const dmp = getDiffMatchPatch(itemA, itemB, options, path)\n\n patches.push(\n dmp || {\n op: 'set',\n path,\n value: itemB,\n },\n )\n\n return patches\n}\n\nfunction isNotIgnoredKey(key: string) {\n return ignoredKeys.indexOf(key) === -1\n}\n\nfunction serializePatches(\n patches: Patch[],\n options: {id: string; ifRevisionID?: string},\n): SanityPatchMutation[] {\n if (patches.length === 0) {\n return []\n }\n\n const {id, ifRevisionID} = options\n const set = patches.filter((patch): patch is SetPatch => patch.op === 'set')\n const unset = patches.filter((patch): patch is UnsetPatch => patch.op === 'unset')\n const insert = patches.filter((patch): patch is InsertAfterPatch => patch.op === 'insert')\n const dmp = patches.filter((patch): patch is DiffMatchPatch => patch.op === 'diffMatchPatch')\n\n const withSet =\n set.length > 0 &&\n set.reduce(\n (patch: SanitySetPatch, item: SetPatch) => {\n const path = pathToString(item.path)\n patch.set[path] = item.value\n return patch\n },\n {id, set: {}},\n )\n\n const withUnset =\n unset.length > 0 &&\n unset.reduce(\n (patch: SanityUnsetPatch, item: UnsetPatch) => {\n const path = pathToString(item.path)\n patch.unset.push(path)\n return patch\n },\n {id, unset: []},\n )\n\n const withInsert = insert.reduce((acc: SanityInsertPatch[], item: InsertAfterPatch) => {\n const after = pathToString(item.after)\n return acc.concat({id, insert: {after, items: item.items}})\n }, [])\n\n const withDmp =\n dmp.length > 0 &&\n dmp.reduce(\n (patch: SanityDiffMatchPatch, item: DiffMatchPatch) => {\n const path = pathToString(item.path)\n patch.diffMatchPatch[path] = item.value\n return patch\n },\n {id, diffMatchPatch: {}},\n )\n\n const patchSet: SanityPatch[] = [withUnset, withSet, withDmp, ...withInsert].filter(\n (item): item is SanityPatch => item !== false,\n )\n\n return patchSet.map((patch, i) => ({\n patch: ifRevisionID && i === 0 ? {...patch, ifRevisionID} : patch,\n }))\n}\n\nfunction isUniquelyKeyed(arr: unknown[]): arr is KeyedSanityObject[] {\n const keys = []\n\n for (let i = 0; i < arr.length; i++) {\n const key = getKey(arr[i])\n if (!key || keys.indexOf(key) !== -1) {\n return false\n }\n\n keys.push(key)\n }\n\n return true\n}\n\nfunction getKey(obj: unknown) {\n return typeof obj === 'object' && obj !== null && (obj as KeyedSanityObject)._key\n}\n\nfunction indexByKey(arr: KeyedSanityObject[]) {\n return arr.reduce(\n (acc, item) => {\n acc.keys.push(item._key)\n acc.index[item._key] = item\n return acc\n },\n {keys: [] as string[], index: {} as {[key: string]: KeyedSanityObject}},\n )\n}\n\nfunction arrayIsEqual(itemA: unknown[], itemB: unknown[]) {\n return itemA.length === itemB.length && itemA.every((item, i) => itemB[i] === item)\n}\n\nfunction nullifyUndefined(item: unknown, path: Path, index: number, options: PatchOptions) {\n if (typeof item !== 'undefined') {\n return item\n }\n\n if (!options.hideWarnings) {\n const serializedPath = pathToString(path.concat(index))\n console.warn(`undefined value in array converted to null (at '${serializedPath}')`)\n }\n\n return null\n}\n\nfunction isRevisionLocked(options: PatchOptions): boolean {\n return Boolean(options.ifRevisionID)\n}\n\nfunction yes(_: unknown) {\n return true\n}\n"],"names":["makeDiff","cleanupEfficiency","stringifyPatches","makePatches"],"mappings":"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"}