@sanity/client 6.7.1-canary.3 → 6.7.1-canary.5

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/README.md CHANGED
@@ -656,6 +656,12 @@ function useContentSourceMap(resultSourceMap: ContentSourceMapping): unknown {
656
656
  useContentSourceMap(resultSourceMap)
657
657
  ```
658
658
 
659
+ #### Creating Studio edit intent links
660
+
661
+ In general
662
+
663
+ With arrays, and keyed array items.
664
+
659
665
  ### Listening to queries
660
666
 
661
667
  ```js
package/dist/csm.cjs CHANGED
@@ -68,27 +68,32 @@ function parseJsonPath(path) {
68
68
  }
69
69
  return parsed;
70
70
  }
71
- function createEditIntentLink(studioUrl, _ref, path) {
72
- let {
73
- _id,
74
- _type
75
- } = _ref;
76
- const _studioUrl = studioUrl.replace(/\/$/, "");
77
- const _path = encodeJsonPathToUriComponent(path);
78
- return "".concat(_studioUrl, "/intent/edit/id=").concat(_id, ";type=").concat(_type, ";path=").concat(_path);
71
+ function resolveMapping(resultPath, csm) {
72
+ const resultJsonPath = jsonPath(resultPath);
73
+ if (csm.mappings[resultJsonPath] !== void 0) {
74
+ return [csm.mappings[resultJsonPath], resultJsonPath, ""];
75
+ }
76
+ const mappings = Object.entries(csm.mappings).filter(_ref => {
77
+ let [key] = _ref;
78
+ return resultJsonPath.startsWith(key);
79
+ }).sort((_ref2, _ref3) => {
80
+ let [key1] = _ref2;
81
+ let [key2] = _ref3;
82
+ return key2.length - key1.length;
83
+ });
84
+ if (mappings.length == 0) {
85
+ return void 0;
86
+ }
87
+ const [matchedPath, mapping] = mappings[0];
88
+ const pathSuffix = resultJsonPath.substring(matchedPath.length);
89
+ return [mapping, matchedPath, pathSuffix];
79
90
  }
80
- function encodeJsonPathToUriComponent(path) {
81
- const sourcePath = Array.isArray(path) ? path : parseJsonPath(path);
82
- return encodeURIComponent(sourcePath.map((key, i) =>
83
- // eslint-disable-next-line no-nested-ternary
84
- typeof key === "number" ? "[".concat(key, "]") : i > 0 ? ".".concat(key) : key).join(""));
91
+ function isArray(value) {
92
+ return value !== null && Array.isArray(value);
85
93
  }
86
94
  function isRecord(value) {
87
95
  return typeof value === "object" && value !== null;
88
96
  }
89
- function isArray(value) {
90
- return value !== null && Array.isArray(value);
91
- }
92
97
  function walkMap(value, mappingFn) {
93
98
  let path = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
94
99
  if (isArray(value)) {
@@ -106,36 +111,114 @@ function walkMap(value, mappingFn) {
106
111
  });
107
112
  }
108
113
  if (isRecord(value)) {
109
- return Object.fromEntries(Object.entries(value).map(_ref2 => {
110
- let [k, v] = _ref2;
114
+ return Object.fromEntries(Object.entries(value).map(_ref4 => {
115
+ let [k, v] = _ref4;
111
116
  return [k, walkMap(v, mappingFn, path.concat(k))];
112
117
  }));
113
118
  }
114
119
  return mappingFn(value, path);
115
120
  }
116
- function resolveMapping(resultPath, csm) {
117
- const resultJsonPath = jsonPath(resultPath);
118
- if (csm.mappings[resultJsonPath] !== void 0) {
119
- return [csm.mappings[resultJsonPath], resultJsonPath, ""];
120
- }
121
- const mappings = Object.entries(csm.mappings).filter(_ref3 => {
122
- let [key] = _ref3;
123
- return resultJsonPath.startsWith(key);
124
- }).sort((_ref4, _ref5) => {
125
- let [key1] = _ref4;
126
- let [key2] = _ref5;
127
- return key2.length - key1.length;
121
+ const defaultUpdateFunction = changed => changed;
122
+ function applySourceDocuments(result, resultSourceMap, getCachedDocument) {
123
+ let updateFn = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : defaultUpdateFunction;
124
+ if (!resultSourceMap) return result;
125
+ return walkMap(result, (value, path) => {
126
+ var _a;
127
+ const resolveMappingResult = resolveMapping(path, resultSourceMap);
128
+ if (!resolveMappingResult) {
129
+ return value;
130
+ }
131
+ const [mapping,, pathSuffix] = resolveMappingResult;
132
+ if (mapping.type !== "value") {
133
+ return value;
134
+ }
135
+ if (mapping.source.type !== "documentValue") {
136
+ return value;
137
+ }
138
+ const sourceDocument = resultSourceMap.documents[mapping.source.document];
139
+ const sourcePath = resultSourceMap.paths[mapping.source.path];
140
+ if (sourceDocument) {
141
+ const cachedDocument = getCachedDocument(sourceDocument);
142
+ if (!cachedDocument) {
143
+ return value;
144
+ }
145
+ const parsedPath = parseJsonPath(sourcePath + pathSuffix);
146
+ const changedValue = cachedDocument ? (_a = getField(cachedDocument, parsedPath)) != null ? _a : value : value;
147
+ return value === changedValue ? value : updateFn(changedValue, {
148
+ cachedDocument,
149
+ previousValue: value,
150
+ sourceDocument,
151
+ sourcePath: parsedPath
152
+ });
153
+ }
154
+ return value;
128
155
  });
129
- if (mappings.length == 0) {
130
- return void 0;
156
+ }
157
+ function getField(obj, path) {
158
+ let value = obj;
159
+ for (const segment of path) {
160
+ if (typeof segment === "string") {
161
+ value = value[segment];
162
+ } else {
163
+ const match = typeof segment === "object" ? value.find(item => item._key === segment.key) : value[segment];
164
+ value = match || null;
165
+ }
166
+ if (value === null || value === void 0) {
167
+ break;
168
+ }
131
169
  }
132
- const [matchedPath, mapping] = mappings[0];
133
- const pathSuffix = resultJsonPath.substring(matchedPath.length);
134
- return [mapping, matchedPath, pathSuffix];
170
+ return value;
171
+ }
172
+ function createEditIntentLink(studioUrl, _ref5, path) {
173
+ let {
174
+ _id,
175
+ _type
176
+ } = _ref5;
177
+ const _studioUrl = studioUrl.replace(/\/$/, "");
178
+ const _path = encodeJsonPathToUriComponent(path);
179
+ return "".concat(_studioUrl, "/intent/edit/id=").concat(_id, ";type=").concat(_type, ";path=").concat(_path);
180
+ }
181
+ function encodeJsonPathToUriComponent(path) {
182
+ const sourcePath = Array.isArray(path) ? path : parseJsonPath(path);
183
+ return encodeURIComponent(sourcePath.map((key, i) => typeof key === "number" ? "[".concat(key, "]") : i > 0 ? ".".concat(key) : key).join(""));
184
+ }
185
+ function encodeIntoResult(result, csm, encoder, options) {
186
+ return walkMap(result, (value, path) => {
187
+ if (typeof value !== "string") {
188
+ return value;
189
+ }
190
+ const resolveMappingResult = resolveMapping(path, csm);
191
+ if (!resolveMappingResult) {
192
+ return value;
193
+ }
194
+ const [mapping, matchedPath, pathSuffix] = resolveMappingResult;
195
+ if (mapping.type !== "value") {
196
+ return value;
197
+ }
198
+ if (mapping.source.type !== "documentValue") {
199
+ return value;
200
+ }
201
+ const sourceDocument = csm.documents[mapping.source.document];
202
+ const sourcePath = csm.paths[mapping.source.path];
203
+ if (options == null ? void 0 : options.keyArraySelectors) {
204
+ const matchPathSegments = parseJsonPath(matchedPath);
205
+ const sourcePathSegments = parseJsonPath(sourcePath);
206
+ const fullSourceSegments = sourcePathSegments.concat(path.slice(matchPathSegments.length));
207
+ return encoder(value, sourceDocument, fullSourceSegments);
208
+ }
209
+ return encoder(value, sourceDocument, parseJsonPath(sourcePath + pathSuffix));
210
+ });
211
+ }
212
+ function encode(result, csm, encoder, options) {
213
+ return encodeIntoResult(result, csm, encoder, options);
135
214
  }
215
+ exports.applySourceDocuments = applySourceDocuments;
136
216
  exports.createEditIntentLink = createEditIntentLink;
217
+ exports.encode = encode;
218
+ exports.encodeIntoResult = encodeIntoResult;
137
219
  exports.encodeJsonPathToUriComponent = encodeJsonPathToUriComponent;
138
220
  exports.jsonPath = jsonPath;
221
+ exports.parseJsonPath = parseJsonPath;
139
222
  exports.resolveMapping = resolveMapping;
140
223
  exports.walkMap = walkMap;
141
224
  //# sourceMappingURL=csm.cjs.map
package/dist/csm.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"csm.cjs","sources":["../src/csm/jsonpath.ts","../src/csm/editIntent.ts","../src/csm/sourcemap.ts"],"sourcesContent":["import type { PathSegment } from './types'\n\nconst ESCAPE: Record<string, string> = {\n '\\f': '\\\\f',\n '\\n': '\\\\n',\n '\\r': '\\\\r',\n '\\t': '\\\\t',\n \"'\": \"\\\\'\",\n '\\\\': '\\\\\\\\',\n}\n\nconst UNESCAPE: Record<string, string> = {\n '\\\\f': '\\f',\n '\\\\n': '\\n',\n '\\\\r': '\\r',\n '\\\\t': '\\t',\n \"\\\\'\": \"'\",\n '\\\\\\\\': '\\\\',\n}\n\n/** @internal */\nexport function jsonPath(\n path: PathSegment[],\n opts?: {\n keyArraySelectors: boolean\n },\n): string {\n return `$${path\n .map((segment) => {\n if (typeof segment === 'string') {\n const escapedKey = segment.replace(/[\\f\\n\\r\\t'\\\\]/g, (match) => {\n return ESCAPE[match]\n })\n return `['${escapedKey}']`\n }\n\n if (typeof segment === 'number') {\n return `[${segment}]`\n }\n\n if (opts?.keyArraySelectors && segment.key !== '') {\n const escapedKey = segment.key.replace(/['\\\\]/g, (match) => {\n return ESCAPE[match]\n })\n return `[?(@._key=='${escapedKey}')]`\n }\n\n return `[${segment.index}]`\n })\n .join('')}`\n}\n\n/** @internal */\nexport function parseJsonPath(path: string): PathSegment[] {\n const parsed: PathSegment[] = []\n\n const parseRe = /\\['(.*?)'\\]|\\[(\\d+)\\]|\\[\\?\\(@\\._key=='(.*?)'\\)\\]/g\n let match: RegExpExecArray | null\n\n while ((match = parseRe.exec(path)) !== null) {\n if (match[1] !== undefined) {\n const key = match[1].replace(/\\\\(\\\\|f|n|r|t|')/g, (m) => {\n return UNESCAPE[m]\n })\n\n parsed.push(key)\n continue\n }\n\n if (match[2] !== undefined) {\n parsed.push(parseInt(match[2], 10))\n continue\n }\n\n if (match[3] !== undefined) {\n const key = match[3].replace(/\\\\(\\\\')/g, (m) => {\n return UNESCAPE[m]\n })\n\n parsed.push({\n key,\n index: -1,\n })\n continue\n }\n }\n\n return parsed\n}\n","import type {ContentSourceMapDocuments} from '../types'\nimport {parseJsonPath} from './jsonpath'\nimport type {PathSegment, StudioUrl} from './types'\n\n/** @public */\nexport type EditIntentLink = `/intent/edit/id=${string};type=${string};path=${string}`\n\n/** @public */\nexport function createEditIntentLink(\n studioUrl: StudioUrl,\n {_id, _type}: ContentSourceMapDocuments[number],\n path: string | PathSegment[],\n): `${StudioUrl}${EditIntentLink}` {\n const _studioUrl = studioUrl.replace(/\\/$/, '')\n const _path = encodeJsonPathToUriComponent(path)\n return `${_studioUrl}/intent/edit/id=${_id};type=${_type};path=${_path}`\n}\n\n/** @public */\nexport function encodeJsonPathToUriComponent(path: string | PathSegment[]): string {\n const sourcePath = Array.isArray(path) ? path : parseJsonPath(path)\n return encodeURIComponent(\n sourcePath\n .map((key, i) =>\n // eslint-disable-next-line no-nested-ternary\n typeof key === 'number' ? `[${key}]` : i > 0 ? `.${key}` : key,\n )\n .join(''),\n )\n}\n","import type {ContentSourceMap, ContentSourceMapDocuments, ContentSourceMapMapping} from '../types'\nimport {jsonPath, parseJsonPath} from './jsonpath'\nimport type {PathSegment} from './types'\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null\n}\n\nfunction isArray(value: unknown): value is Array<unknown> {\n return value !== null && Array.isArray(value)\n}\n\n/** @alpha */\nexport type Encoder<E> = (\n value: string,\n sourceDocument: ContentSourceMapDocuments[number],\n path: PathSegment[],\n) => E\n\n/** @alpha */\nexport function encode<R, E>(\n result: R,\n csm: ContentSourceMap,\n encoder: Encoder<E>,\n options?: {keyArraySelectors: boolean},\n): R {\n return encodeIntoResult(result, csm, encoder, options) as R\n}\n\n/** @alpha */\nexport function encodeIntoResult<R>(\n result: R,\n csm: ContentSourceMap,\n encoder: Encoder<unknown>,\n options?: {keyArraySelectors: boolean},\n): ReturnType<Encoder<unknown>> {\n return walkMap(result, (value, path) => {\n // Only map strings, we could extend this in the future to support other types like integers...\n if (typeof value !== 'string') {\n return value\n }\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const resolveMappingResult = resolveMapping(path, csm)\n if (!resolveMappingResult) {\n return value\n }\n\n const [mapping, matchedPath, pathSuffix] = resolveMappingResult\n if (mapping.type !== 'value') {\n return value\n }\n\n if (mapping.source.type !== 'documentValue') {\n return value\n }\n\n const sourceDocument =\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n csm.documents[mapping.source.document!]\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const sourcePath = csm.paths[mapping.source.path]\n\n if (options?.keyArraySelectors) {\n const matchPathSegments = parseJsonPath(matchedPath)\n const sourcePathSegments = parseJsonPath(sourcePath)\n const fullSourceSegments = sourcePathSegments.concat(path.slice(matchPathSegments.length))\n\n return encoder(value, sourceDocument, fullSourceSegments)\n }\n\n return encoder(value, sourceDocument, parseJsonPath(sourcePath + pathSuffix))\n })\n}\n\n/** @alpha */\nexport type WalkMapFn = (value: unknown, path: PathSegment[]) => unknown\n\n/** generic way to walk a nested object or array and apply a mapping function to each value\n * @alpha\n */\nexport function walkMap(value: unknown, mappingFn: WalkMapFn, path: PathSegment[] = []): unknown {\n if (isArray(value)) {\n return value.map((v, idx) => {\n if (isRecord(v)) {\n const key = v['_key']\n if (typeof key === 'string') {\n return walkMap(v, mappingFn, path.concat({key, index: idx}))\n }\n }\n\n return walkMap(v, mappingFn, path.concat(idx))\n })\n }\n\n if (isRecord(value)) {\n return Object.fromEntries(\n Object.entries(value).map(([k, v]) => [k, walkMap(v, mappingFn, path.concat(k))]),\n )\n }\n\n return mappingFn(value, path)\n}\n\n/** @alpha */\nexport function resolveMapping(\n resultPath: PathSegment[],\n csm: ContentSourceMap,\n): [ContentSourceMapMapping, string, string] | undefined {\n const resultJsonPath = jsonPath(resultPath)\n\n if (csm.mappings[resultJsonPath] !== undefined) {\n return [csm.mappings[resultJsonPath], resultJsonPath, '']\n }\n\n const mappings = Object.entries(csm.mappings)\n .filter(([key]) => resultJsonPath.startsWith(key))\n .sort(([key1], [key2]) => key2.length - key1.length)\n\n if (mappings.length == 0) {\n return undefined\n }\n\n const [matchedPath, mapping] = mappings[0]\n const pathSuffix = resultJsonPath.substring(matchedPath.length)\n return [mapping, matchedPath, pathSuffix]\n}\n"],"names":["ESCAPE","UNESCAPE","jsonPath","path","opts","concat","map","segment","escapedKey","replace","match","keyArraySelectors","key","index","join","parseJsonPath","parsed","parseRe","exec","m","push","parseInt","createEditIntentLink","studioUrl","_ref","_id","_type","_studioUrl","_path","encodeJsonPathToUriComponent","sourcePath","Array","isArray","encodeURIComponent","i","isRecord","value","walkMap","mappingFn","arguments","length","undefined","v","idx","Object","fromEntries","entries","_ref2","k","resolveMapping","resultPath","csm","resultJsonPath","mappings","filter","_ref3","startsWith","sort","_ref4","_ref5","key1","key2","matchedPath","mapping","pathSuffix","substring"],"mappings":"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"}
1
+ {"version":3,"file":"csm.cjs","sources":["../src/csm/jsonpath.ts","../src/csm/resolveMapping.ts","../src/csm/isArray.ts","../src/csm/isRecord.ts","../src/csm/walkMap.ts","../src/csm/applySourceDocuments.ts","../src/csm/editIntent.ts","../src/csm/encodeIntoResult.ts","../src/csm/encode.ts"],"sourcesContent":["import type {PathSegment} from './types'\n\nconst ESCAPE: Record<string, string> = {\n '\\f': '\\\\f',\n '\\n': '\\\\n',\n '\\r': '\\\\r',\n '\\t': '\\\\t',\n \"'\": \"\\\\'\",\n '\\\\': '\\\\\\\\',\n}\n\nconst UNESCAPE: Record<string, string> = {\n '\\\\f': '\\f',\n '\\\\n': '\\n',\n '\\\\r': '\\r',\n '\\\\t': '\\t',\n \"\\\\'\": \"'\",\n '\\\\\\\\': '\\\\',\n}\n\n/**\n * @internal\n */\nexport function jsonPath(\n path: PathSegment[],\n opts?: {\n keyArraySelectors: boolean\n },\n): string {\n return `$${path\n .map((segment) => {\n if (typeof segment === 'string') {\n const escapedKey = segment.replace(/[\\f\\n\\r\\t'\\\\]/g, (match) => {\n return ESCAPE[match]\n })\n return `['${escapedKey}']`\n }\n\n if (typeof segment === 'number') {\n return `[${segment}]`\n }\n\n if (opts?.keyArraySelectors && segment.key !== '') {\n const escapedKey = segment.key.replace(/['\\\\]/g, (match) => {\n return ESCAPE[match]\n })\n return `[?(@._key=='${escapedKey}')]`\n }\n\n return `[${segment.index}]`\n })\n .join('')}`\n}\n\n/**\n * @internal\n */\nexport function parseJsonPath(path: string): PathSegment[] {\n const parsed: PathSegment[] = []\n\n const parseRe = /\\['(.*?)'\\]|\\[(\\d+)\\]|\\[\\?\\(@\\._key=='(.*?)'\\)\\]/g\n let match: RegExpExecArray | null\n\n while ((match = parseRe.exec(path)) !== null) {\n if (match[1] !== undefined) {\n const key = match[1].replace(/\\\\(\\\\|f|n|r|t|')/g, (m) => {\n return UNESCAPE[m]\n })\n\n parsed.push(key)\n continue\n }\n\n if (match[2] !== undefined) {\n parsed.push(parseInt(match[2], 10))\n continue\n }\n\n if (match[3] !== undefined) {\n const key = match[3].replace(/\\\\(\\\\')/g, (m) => {\n return UNESCAPE[m]\n })\n\n parsed.push({\n key,\n index: -1,\n })\n continue\n }\n }\n\n return parsed\n}\n","import {jsonPath} from './jsonpath'\nimport type {ContentSourceMap, ContentSourceMapMapping, PathSegment} from './types'\n\n/**\n * @alpha\n */\nexport function resolveMapping(\n resultPath: PathSegment[],\n csm: ContentSourceMap,\n): [ContentSourceMapMapping, string, string] | undefined {\n const resultJsonPath = jsonPath(resultPath)\n\n if (csm.mappings[resultJsonPath] !== undefined) {\n return [csm.mappings[resultJsonPath], resultJsonPath, '']\n }\n\n const mappings = Object.entries(csm.mappings)\n .filter(([key]) => resultJsonPath.startsWith(key))\n .sort(([key1], [key2]) => key2.length - key1.length)\n\n if (mappings.length == 0) {\n return undefined\n }\n\n const [matchedPath, mapping] = mappings[0]\n const pathSuffix = resultJsonPath.substring(matchedPath.length)\n return [mapping, matchedPath, pathSuffix]\n}\n","export function isArray(value: unknown): value is Array<unknown> {\n return value !== null && Array.isArray(value)\n}\n","export function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null\n}\n","import {isArray} from './isArray'\nimport {isRecord} from './isRecord'\nimport type {PathSegment} from './types'\n\n/**\n * @alpha\n */\nexport type WalkMapFn = (value: unknown, path: PathSegment[]) => unknown\n\n/**\n * generic way to walk a nested object or array and apply a mapping function to each value\n * @alpha\n */\nexport function walkMap(value: unknown, mappingFn: WalkMapFn, path: PathSegment[] = []): unknown {\n if (isArray(value)) {\n return value.map((v, idx) => {\n if (isRecord(v)) {\n const key = v['_key']\n if (typeof key === 'string') {\n return walkMap(v, mappingFn, path.concat({key, index: idx}))\n }\n }\n\n return walkMap(v, mappingFn, path.concat(idx))\n })\n }\n\n if (isRecord(value)) {\n return Object.fromEntries(\n Object.entries(value).map(([k, v]) => [k, walkMap(v, mappingFn, path.concat(k))]),\n )\n }\n\n return mappingFn(value, path)\n}\n","import {parseJsonPath} from './jsonpath'\nimport {resolveMapping} from './resolveMapping'\nimport type {\n Any,\n ContentSourceMap,\n ContentSourceMapDocuments,\n PathSegment,\n SanityDocument,\n} from './types'\nimport {walkMap} from './walkMap'\n\n/**\n * @public\n */\nexport type ApplySourceDocumentsUpdateFunction = <T = unknown>(\n changedValue: T,\n context: {\n cachedDocument: SanityDocument\n previousValue: T\n sourceDocument: ContentSourceMapDocuments[number]\n sourcePath: PathSegment[]\n },\n) => T\n\nconst defaultUpdateFunction = <T = unknown>(changed: T): T => changed\n\n/**\n * Optimistically applies source documents to a result, using the content source map to trace fields.\n * Can be used to apply mutations to documents being edited in a Studio, or any mutation on Content Lake, to a result with extremely low latency.\n * @public\n */\nexport function applySourceDocuments<Result = unknown>(\n result: Result,\n resultSourceMap: ContentSourceMap | undefined,\n getCachedDocument: (\n sourceDocument: ContentSourceMapDocuments[number],\n ) => SanityDocument | undefined,\n updateFn: ApplySourceDocumentsUpdateFunction = defaultUpdateFunction,\n): Result {\n if (!resultSourceMap) return result\n\n return walkMap(result, (value, path) => {\n const resolveMappingResult = resolveMapping(path, resultSourceMap)\n if (!resolveMappingResult) {\n return value\n }\n\n const [mapping, , pathSuffix] = resolveMappingResult\n if (mapping.type !== 'value') {\n return value\n }\n\n if (mapping.source.type !== 'documentValue') {\n return value\n }\n\n const sourceDocument = resultSourceMap.documents[mapping.source.document]\n const sourcePath = resultSourceMap.paths[mapping.source.path]\n\n if (sourceDocument) {\n const cachedDocument = getCachedDocument(sourceDocument)\n if (!cachedDocument) {\n return value\n }\n\n const parsedPath = parseJsonPath(sourcePath + pathSuffix)\n const changedValue = cachedDocument ? getField(cachedDocument, parsedPath) ?? value : value\n return value === changedValue\n ? value\n : updateFn<Result[keyof Result]>(changedValue, {\n cachedDocument,\n previousValue: value as Result[keyof Result],\n sourceDocument,\n sourcePath: parsedPath,\n })\n }\n\n return value\n }) as Result\n}\n\nfunction getField(obj: SanityDocument, path: PathSegment[]): Any {\n let value = obj as SanityDocument | SanityDocument[keyof SanityDocument]\n for (const segment of path) {\n if (typeof segment === 'string') {\n value = value[segment]\n } else {\n const match =\n typeof segment === 'object'\n ? value.find((item: SanityDocument[keyof SanityDocument]) => item._key === segment.key)\n : value[segment]\n value = match || null\n }\n if (value === null || value === undefined) {\n break\n }\n }\n return value\n}\n","import type {ContentSourceMapDocuments} from '../types'\nimport {parseJsonPath} from './jsonpath'\nimport type {PathSegment, StudioUrl} from './types'\n\n/** @public */\nexport type EditIntentLink = `/intent/edit/id=${string};type=${string};path=${string}`\n\n/** @public */\nexport function createEditIntentLink(\n studioUrl: StudioUrl,\n {_id, _type}: ContentSourceMapDocuments[number],\n path: string | PathSegment[],\n): `${StudioUrl}${EditIntentLink}` {\n const _studioUrl = studioUrl.replace(/\\/$/, '')\n const _path = encodeJsonPathToUriComponent(path)\n return `${_studioUrl}/intent/edit/id=${_id};type=${_type};path=${_path}`\n}\n\n/** @public */\nexport function encodeJsonPathToUriComponent(path: string | PathSegment[]): string {\n const sourcePath = Array.isArray(path) ? path : parseJsonPath(path)\n return encodeURIComponent(\n sourcePath\n .map((key, i) => (typeof key === 'number' ? `[${key}]` : i > 0 ? `.${key}` : key))\n .join(''),\n )\n}\n","import {Encoder} from './encode'\nimport {parseJsonPath} from './jsonpath'\nimport {resolveMapping} from './resolveMapping'\nimport type {ContentSourceMap} from './types'\nimport {walkMap} from './walkMap'\n\n/**\n * @alpha\n */\nexport function encodeIntoResult<R>(\n result: R,\n csm: ContentSourceMap,\n encoder: Encoder<unknown>,\n options?: {keyArraySelectors: boolean},\n): ReturnType<Encoder<unknown>> {\n return walkMap(result, (value, path) => {\n // Only map strings, we could extend this in the future to support other types like integers...\n if (typeof value !== 'string') {\n return value\n }\n\n const resolveMappingResult = resolveMapping(path, csm)\n if (!resolveMappingResult) {\n return value\n }\n\n const [mapping, matchedPath, pathSuffix] = resolveMappingResult\n if (mapping.type !== 'value') {\n return value\n }\n\n if (mapping.source.type !== 'documentValue') {\n return value\n }\n\n const sourceDocument = csm.documents[mapping.source.document!]\n const sourcePath = csm.paths[mapping.source.path]\n\n if (options?.keyArraySelectors) {\n const matchPathSegments = parseJsonPath(matchedPath)\n const sourcePathSegments = parseJsonPath(sourcePath)\n const fullSourceSegments = sourcePathSegments.concat(path.slice(matchPathSegments.length))\n\n return encoder(value, sourceDocument, fullSourceSegments)\n }\n\n return encoder(value, sourceDocument, parseJsonPath(sourcePath + pathSuffix))\n })\n}\n","import {encodeIntoResult} from './encodeIntoResult'\nimport type {ContentSourceMap, ContentSourceMapDocuments, PathSegment} from './types'\n\n/**\n * @alpha\n */\nexport type Encoder<E> = (\n value: string,\n sourceDocument: ContentSourceMapDocuments[number],\n path: PathSegment[],\n) => E\n\n/**\n * @alpha\n */\nexport function encode<R, E>(\n result: R,\n csm: ContentSourceMap,\n encoder: Encoder<E>,\n options?: {keyArraySelectors: boolean},\n): R {\n return encodeIntoResult(result, csm, encoder, options) as R\n}\n"],"names":["ESCAPE","UNESCAPE","jsonPath","path","opts","concat","map","segment","escapedKey","replace","match","keyArraySelectors","key","index","join","parseJsonPath","parsed","parseRe","exec","m","push","parseInt","resolveMapping","resultPath","csm","resultJsonPath","mappings","Object","entries","filter","_ref","startsWith","sort","_ref2","_ref3","key1","key2","length","matchedPath","mapping","pathSuffix","substring","isArray","value","Array","isRecord","walkMap","mappingFn","arguments","undefined","v","idx","fromEntries","_ref4","k","defaultUpdateFunction","changed","applySourceDocuments","result","resultSourceMap","getCachedDocument","updateFn","_a","resolveMappingResult","type","source","sourceDocument","documents","document","sourcePath","paths","cachedDocument","parsedPath","changedValue","getField","previousValue","obj","find","item","_key","createEditIntentLink","studioUrl","_ref5","_id","_type","_studioUrl","_path","encodeJsonPathToUriComponent","encodeURIComponent","i","encodeIntoResult","encoder","options","matchPathSegments","sourcePathSegments","fullSourceSegments","slice","encode"],"mappings":";;;;;AAEA,MAAMA,MAAiC,GAAA;EACrC,IAAM,EAAA,KAAA;EACN,IAAM,EAAA,KAAA;EACN,IAAM,EAAA,KAAA;EACN,GAAM,EAAA,KAAA;EACN,GAAK,EAAA,KAAA;EACL,IAAM,EAAA;AACR,CAAA;AAEA,MAAMC,QAAmC,GAAA;EACvC,KAAO,EAAA,IAAA;EACP,KAAO,EAAA,IAAA;EACP,KAAO,EAAA,IAAA;EACP,KAAO,EAAA,GAAA;EACP,KAAO,EAAA,GAAA;EACP,MAAQ,EAAA;AACV,CAAA;AAKgB,SAAAC,QAAAA,CACdC,MACAC,IAGQ,EAAA;EACR,OAAO,GAAI,CAAAC,MAAA,CAAAF,IAAA,CACRG,GAAI,CAACC,OAAY,IAAA;IACZ,IAAA,OAAOA,YAAY,QAAU,EAAA;MAC/B,MAAMC,UAAa,GAAAD,OAAA,CAAQE,OAAQ,CAAA,gBAAA,EAAmBC,KAAU,IAAA;QAC9D,OAAOV,OAAOU,KAAK,CAAA;MAAA,CACpB,CAAA;MACD,OAAO,KAAKL,MAAU,CAAAG,UAAA,EAAA,IAAA,CAAA;IACxB;IAEI,IAAA,OAAOD,YAAY,QAAU,EAAA;MAC/B,OAAO,IAAIF,MAAO,CAAAE,OAAA,EAAA,GAAA,CAAA;IACpB;IAEA,IAAA,CAAIH,IAAM,IAAA,IAAA,GAAA,KAAA,CAAA,GAAAA,IAAA,CAAAO,iBAAA,KAAqBJ,OAAQ,CAAAK,GAAA,KAAQ,EAAI,EAAA;MACjD,MAAMJ,aAAaD,OAAQ,CAAAK,GAAA,CAAIH,OAAQ,CAAA,QAAA,EAAWC,KAAU,IAAA;QAC1D,OAAOV,OAAOU,KAAK,CAAA;MAAA,CACpB,CAAA;MACD,OAAO,eAAeL,MAAU,CAAAG,UAAA,EAAA,KAAA,CAAA;IAClC;IAEO,OAAA,GAAA,CAAIH,eAAQQ,KAAK,EAAA,GAAA,CAAA;EAAA,CACzB,CACA,CAAAC,IAAA,CAAK,EAAE,CAAA,CAAA;AACZ;AAKO,SAASC,cAAcZ,IAA6B,EAAA;EACzD,MAAMa,SAAwB,EAAC;EAE/B,MAAMC,OAAU,GAAA,mDAAA;EACZ,IAAAP,KAAA;EAEJ,OAAA,CAAQA,KAAQ,GAAAO,OAAA,CAAQC,IAAK,CAAAf,IAAI,OAAO,IAAM,EAAA;IACxC,IAAAO,KAAA,CAAM,CAAC,CAAA,KAAM,KAAW,CAAA,EAAA;MAC1B,MAAME,MAAMF,KAAM,CAAA,CAAC,EAAED,OAAQ,CAAA,mBAAA,EAAsBU,CAAM,IAAA;QACvD,OAAOlB,SAASkB,CAAC,CAAA;MAAA,CAClB,CAAA;MAEDH,MAAA,CAAOI,KAAKR,GAAG,CAAA;MACf;IACF;IAEI,IAAAF,KAAA,CAAM,CAAC,CAAA,KAAM,KAAW,CAAA,EAAA;MAC1BM,MAAA,CAAOI,KAAKC,QAAS,CAAAX,KAAA,CAAM,CAAC,CAAA,EAAG,EAAE,CAAC,CAAA;MAClC;IACF;IAEI,IAAAA,KAAA,CAAM,CAAC,CAAA,KAAM,KAAW,CAAA,EAAA;MAC1B,MAAME,MAAMF,KAAM,CAAA,CAAC,EAAED,OAAQ,CAAA,UAAA,EAAaU,CAAM,IAAA;QAC9C,OAAOlB,SAASkB,CAAC,CAAA;MAAA,CAClB,CAAA;MAEDH,MAAA,CAAOI,IAAK,CAAA;QACVR,GAAA;QACAC,KAAO,EAAA,CAAA;MAAA,CACR,CAAA;MACD;IACF;EACF;EAEO,OAAAG,MAAA;AACT;ACtFgB,SAAAM,cAAAA,CACdC,YACAC,GACuD,EAAA;EACjD,MAAAC,cAAA,GAAiBvB,SAASqB,UAAU,CAAA;EAE1C,IAAIC,GAAI,CAAAE,QAAA,CAASD,cAAc,CAAA,KAAM,KAAW,CAAA,EAAA;IAC9C,OAAO,CAACD,GAAI,CAAAE,QAAA,CAASD,cAAc,CAAA,EAAGA,gBAAgB,EAAE,CAAA;EAC1D;EAEM,MAAAC,QAAA,GAAWC,MAAO,CAAAC,OAAA,CAAQJ,GAAI,CAAAE,QAAQ,CACzC,CAAAG,MAAA,CAAOC,IAAA;IAAA,IAAC,CAAClB,GAAG,CAAA,GAAAkB,IAAA;IAAA,OAAML,cAAe,CAAAM,UAAA,CAAWnB,GAAG,CAAC;EAAA,EAChD,CAAAoB,IAAA,CAAK,CAAAC,KAAA,EAAAC,KAAA;IAAA,IAAC,CAACC,IAAI,CAAA,GAAAF,KAAA;IAAA,IAAG,CAACG,IAAI,CAAM,GAAAF,KAAA;IAAA,OAAAE,IAAA,CAAKC,MAAS,GAAAF,IAAA,CAAKE,MAAM;EAAA,EAAA;EAEjD,IAAAX,QAAA,CAASW,UAAU,CAAG,EAAA;IACjB,OAAA,KAAA,CAAA;EACT;EAEA,MAAM,CAACC,WAAA,EAAaC,OAAO,CAAA,GAAIb,SAAS,CAAC,CAAA;EACzC,MAAMc,UAAa,GAAAf,cAAA,CAAegB,SAAU,CAAAH,WAAA,CAAYD,MAAM,CAAA;EACvD,OAAA,CAACE,OAAS,EAAAD,WAAA,EAAaE,UAAU,CAAA;AAC1C;AC3BO,SAASE,QAAQC,KAAyC,EAAA;EAC/D,OAAOA,KAAU,KAAA,IAAA,IAAQC,KAAM,CAAAF,OAAA,CAAQC,KAAK,CAAA;AAC9C;ACFO,SAASE,SAASF,KAAkD,EAAA;EAClE,OAAA,OAAOA,KAAU,KAAA,QAAA,IAAYA,KAAU,KAAA,IAAA;AAChD;ACWO,SAASG,OAAQA,CAAAH,KAAA,EAAgBI,SAAsB,EAAmC;EAAA,IAAnC5C,IAAA,GAAA6C,SAAA,CAAAX,MAAA,QAAAW,SAAA,QAAAC,SAAA,GAAAD,SAAA,MAAsB,EAAa;EAC3F,IAAAN,OAAA,CAAQC,KAAK,CAAG,EAAA;IAClB,OAAOA,KAAM,CAAArC,GAAA,CAAI,CAAC4C,CAAA,EAAGC,GAAQ,KAAA;MACvB,IAAAN,QAAA,CAASK,CAAC,CAAG,EAAA;QACT,MAAAtC,GAAA,GAAMsC,EAAE,MAAM,CAAA;QAChB,IAAA,OAAOtC,QAAQ,QAAU,EAAA;UACpB,OAAAkC,OAAA,CAAQI,CAAG,EAAAH,SAAA,EAAW5C,IAAK,CAAAE,MAAA,CAAO;YAACO,GAAK;YAAAC,KAAA,EAAOsC;UAAI,CAAA,CAAC,CAAA;QAC7D;MACF;MAEA,OAAOL,QAAQI,CAAG,EAAAH,SAAA,EAAW5C,IAAK,CAAAE,MAAA,CAAO8C,GAAG,CAAC,CAAA;IAAA,CAC9C,CAAA;EACH;EAEI,IAAAN,QAAA,CAASF,KAAK,CAAG,EAAA;IACnB,OAAOhB,MAAO,CAAAyB,WAAA,CACZzB,MAAA,CAAOC,QAAQe,KAAK,CAAA,CAAErC,IAAI+C,KAAA;MAAA,IAAC,CAACC,GAAGJ,CAAC,CAAA,GAAAG,KAAA;MAAA,OAAM,CAACC,CAAG,EAAAR,OAAA,CAAQI,GAAGH,SAAW,EAAA5C,IAAA,CAAKE,OAAOiD,CAAC,CAAC,CAAC,CAAC;IAAA,EAAA,CAClF;EACF;EAEO,OAAAP,SAAA,CAAUJ,OAAOxC,IAAI,CAAA;AAC9B;ACVA,MAAMoD,qBAAA,GAAsCC,OAAkB,IAAAA,OAAA;AAOvD,SAASC,oBACdA,CAAAC,MAAA,EACAC,eACA,EAAAC,iBAAA,EAIQ;EAAA,IADRC,+EAA+CN,qBACvC;EACR,IAAI,CAACI,eAAA,EAAwB,OAAAD,MAAA;EAE7B,OAAOZ,OAAQ,CAAAY,MAAA,EAAQ,CAACf,KAAA,EAAOxC,IAAS,KAAA;IAzC1C,IAAA2D,EAAA;IA0CU,MAAAC,oBAAA,GAAuBzC,cAAe,CAAAnB,IAAA,EAAMwD,eAAe,CAAA;IACjE,IAAI,CAACI,oBAAsB,EAAA;MAClB,OAAApB,KAAA;IACT;IAEA,MAAM,CAACJ,OAAA,GAAWC,UAAU,CAAI,GAAAuB,oBAAA;IAC5B,IAAAxB,OAAA,CAAQyB,SAAS,OAAS,EAAA;MACrB,OAAArB,KAAA;IACT;IAEI,IAAAJ,OAAA,CAAQ0B,MAAO,CAAAD,IAAA,KAAS,eAAiB,EAAA;MACpC,OAAArB,KAAA;IACT;IAEA,MAAMuB,cAAiB,GAAAP,eAAA,CAAgBQ,SAAU,CAAA5B,OAAA,CAAQ0B,OAAOG,QAAQ,CAAA;IACxE,MAAMC,UAAa,GAAAV,eAAA,CAAgBW,KAAM,CAAA/B,OAAA,CAAQ0B,OAAO9D,IAAI,CAAA;IAE5D,IAAI+D,cAAgB,EAAA;MACZ,MAAAK,cAAA,GAAiBX,kBAAkBM,cAAc,CAAA;MACvD,IAAI,CAACK,cAAgB,EAAA;QACZ,OAAA5B,KAAA;MACT;MAEM,MAAA6B,UAAA,GAAazD,aAAc,CAAAsD,UAAA,GAAa7B,UAAU,CAAA;MACxD,MAAMiC,eAAeF,cAAiB,GAAA,CAAAT,EAAA,GAAAY,QAAA,CAASH,gBAAgBC,UAAU,CAAA,KAAnC,YAAwC7B,KAAQ,GAAAA,KAAA;MACtF,OAAOA,KAAU,KAAA8B,YAAA,GACb9B,KACA,GAAAkB,QAAA,CAA+BY,YAAc,EAAA;QAC3CF,cAAA;QACAI,aAAe,EAAAhC,KAAA;QACfuB,cAAA;QACAG,UAAY,EAAAG;MAAA,CACb,CAAA;IACP;IAEO,OAAA7B,KAAA;EAAA,CACR,CAAA;AACH;AAEA,SAAS+B,QAAAA,CAASE,KAAqBzE,IAA0B,EAAA;EAC/D,IAAIwC,KAAQ,GAAAiC,GAAA;EACZ,KAAA,MAAWrE,WAAWJ,IAAM,EAAA;IACtB,IAAA,OAAOI,YAAY,QAAU,EAAA;MAC/BoC,KAAA,GAAQA,MAAMpC,OAAO,CAAA;IAAA,CAChB,MAAA;MACL,MAAMG,KACJ,GAAA,OAAOH,OAAY,KAAA,QAAA,GACfoC,MAAMkC,IAAK,CAACC,IAA+C,IAAAA,IAAA,CAAKC,IAAS,KAAAxE,OAAA,CAAQK,GAAG,CAAA,GACpF+B,MAAMpC,OAAO,CAAA;MACnBoC,KAAA,GAAQjC,KAAS,IAAA,IAAA;IACnB;IACI,IAAAiC,KAAA,KAAU,IAAQ,IAAAA,KAAA,KAAU,KAAW,CAAA,EAAA;MACzC;IACF;EACF;EACO,OAAAA,KAAA;AACT;AC1FO,SAASqC,qBACdC,SACA,EAAAC,KAAA,EACA/E,IACiC,EAAA;EAAA,IAFjC;IAACgF,GAAK;IAAAC;EAAA;EAGN,MAAMC,UAAa,GAAAJ,SAAA,CAAUxE,OAAQ,CAAA,KAAA,EAAO,EAAE,CAAA;EACxC,MAAA6E,KAAA,GAAQC,6BAA6BpF,IAAI,CAAA;EAC/C,OAAO,GAAGE,MAAU,CAAAgF,UAAA,EAAA,kBAAA,CAAA,CAAmBhF,MAAG,CAAA8E,GAAA,EAAA,QAAA,CAAA,CAAS9E,cAAK,QAAS,CAAA,CAAAA,MAAA,CAAAiF,KAAA,CAAA;AACnE;AAGO,SAASC,6BAA6BpF,IAAsC,EAAA;EACjF,MAAMkE,aAAazB,KAAM,CAAAF,OAAA,CAAQvC,IAAI,CAAI,GAAAA,IAAA,GAAOY,cAAcZ,IAAI,CAAA;EAC3D,OAAAqF,kBAAA,CACLnB,WACG/D,GAAI,CAAA,CAACM,KAAK6E,CAAO,KAAA,OAAO7E,QAAQ,QAAW,GAAA,GAAA,CAAIP,MAAG,CAAAO,GAAA,EAAA,GAAA,CAAA,GAAM6E,IAAI,CAAI,GAAA,GAAA,CAAIpF,cAAQO,GAAI,CAAA,CAChFE,KAAK,EAAE,CAAA,CACZ;AACF;ACjBO,SAAS4E,gBACdA,CAAAhC,MAAA,EACAlC,GACA,EAAAmE,OAAA,EACAC,OAC8B,EAAA;EAC9B,OAAO9C,OAAQ,CAAAY,MAAA,EAAQ,CAACf,KAAA,EAAOxC,IAAS,KAAA;IAElC,IAAA,OAAOwC,UAAU,QAAU,EAAA;MACtB,OAAAA,KAAA;IACT;IAEM,MAAAoB,oBAAA,GAAuBzC,cAAe,CAAAnB,IAAA,EAAMqB,GAAG,CAAA;IACrD,IAAI,CAACuC,oBAAsB,EAAA;MAClB,OAAApB,KAAA;IACT;IAEA,MAAM,CAACJ,OAAA,EAASD,WAAa,EAAAE,UAAU,CAAI,GAAAuB,oBAAA;IACvC,IAAAxB,OAAA,CAAQyB,SAAS,OAAS,EAAA;MACrB,OAAArB,KAAA;IACT;IAEI,IAAAJ,OAAA,CAAQ0B,MAAO,CAAAD,IAAA,KAAS,eAAiB,EAAA;MACpC,OAAArB,KAAA;IACT;IAEA,MAAMuB,cAAiB,GAAA1C,GAAA,CAAI2C,SAAU,CAAA5B,OAAA,CAAQ0B,OAAOG,QAAS,CAAA;IAC7D,MAAMC,UAAa,GAAA7C,GAAA,CAAI8C,KAAM,CAAA/B,OAAA,CAAQ0B,OAAO9D,IAAI,CAAA;IAEhD,IAAIyF,mCAASjF,iBAAmB,EAAA;MACxB,MAAAkF,iBAAA,GAAoB9E,cAAcuB,WAAW,CAAA;MAC7C,MAAAwD,kBAAA,GAAqB/E,cAAcsD,UAAU,CAAA;MACnD,MAAM0B,qBAAqBD,kBAAmB,CAAAzF,MAAA,CAAOF,KAAK6F,KAAM,CAAAH,iBAAA,CAAkBxD,MAAM,CAAC,CAAA;MAElF,OAAAsD,OAAA,CAAQhD,KAAO,EAAAuB,cAAA,EAAgB6B,kBAAkB,CAAA;IAC1D;IAEA,OAAOJ,QAAQhD,KAAO,EAAAuB,cAAA,EAAgBnD,aAAc,CAAAsD,UAAA,GAAa7B,UAAU,CAAC,CAAA;EAAA,CAC7E,CAAA;AACH;ACjCO,SAASyD,MACdA,CAAAvC,MAAA,EACAlC,GACA,EAAAmE,OAAA,EACAC,OACG,EAAA;EACH,OAAOF,gBAAiB,CAAAhC,MAAA,EAAQlC,GAAK,EAAAmE,OAAA,EAASC,OAAO,CAAA;AACvD;;;;;;;;;"}
package/dist/csm.d.ts CHANGED
@@ -1,5 +1,38 @@
1
1
  /// <reference types="node" />
2
2
 
3
+ /**
4
+ * Used to tag types that is set to `any` as a temporary measure, but should be replaced with proper typings in the future
5
+ * @internal
6
+ */
7
+ export declare type Any = any
8
+
9
+ /**
10
+ * Optimistically applies source documents to a result, using the content source map to trace fields.
11
+ * Can be used to apply mutations to documents being edited in a Studio, or any mutation on Content Lake, to a result with extremely low latency.
12
+ * @public
13
+ */
14
+ export declare function applySourceDocuments<Result = unknown>(
15
+ result: Result,
16
+ resultSourceMap: ContentSourceMap | undefined,
17
+ getCachedDocument: (
18
+ sourceDocument: ContentSourceMapDocuments[number],
19
+ ) => SanityDocument | undefined,
20
+ updateFn?: ApplySourceDocumentsUpdateFunction,
21
+ ): Result
22
+
23
+ /**
24
+ * @public
25
+ */
26
+ export declare type ApplySourceDocumentsUpdateFunction = <T = unknown>(
27
+ changedValue: T,
28
+ context: {
29
+ cachedDocument: SanityDocument
30
+ previousValue: T
31
+ sourceDocument: ContentSourceMapDocuments[number]
32
+ sourcePath: PathSegment[]
33
+ },
34
+ ) => T
35
+
3
36
  /** @public */
4
37
  export declare interface ContentSourceMap {
5
38
  mappings: ContentSourceMapMappings
@@ -92,10 +125,45 @@ export declare function createEditIntentLink(
92
125
  /** @public */
93
126
  export declare type EditIntentLink = `/intent/edit/id=${string};type=${string};path=${string}`
94
127
 
128
+ /**
129
+ * @alpha
130
+ */
131
+ export declare function encode<R, E>(
132
+ result: R,
133
+ csm: ContentSourceMap,
134
+ encoder: Encoder<E>,
135
+ options?: {
136
+ keyArraySelectors: boolean
137
+ },
138
+ ): R
139
+
140
+ /**
141
+ * @alpha
142
+ */
143
+ export declare function encodeIntoResult<R>(
144
+ result: R,
145
+ csm: ContentSourceMap,
146
+ encoder: Encoder<unknown>,
147
+ options?: {
148
+ keyArraySelectors: boolean
149
+ },
150
+ ): ReturnType<Encoder<unknown>>
151
+
95
152
  /** @public */
96
153
  export declare function encodeJsonPathToUriComponent(path: string | PathSegment[]): string
97
154
 
98
- /** @internal */
155
+ /**
156
+ * @alpha
157
+ */
158
+ export declare type Encoder<E> = (
159
+ value: string,
160
+ sourceDocument: ContentSourceMapDocuments[number],
161
+ path: PathSegment[],
162
+ ) => E
163
+
164
+ /**
165
+ * @internal
166
+ */
99
167
  export declare function jsonPath(
100
168
  path: PathSegment[],
101
169
  opts?: {
@@ -109,15 +177,37 @@ export declare type KeyedSegment = {
109
177
  index: number
110
178
  }
111
179
 
180
+ /**
181
+ * @internal
182
+ */
183
+ export declare function parseJsonPath(path: string): PathSegment[]
184
+
112
185
  /** @public */
113
186
  export declare type PathSegment = string | number | KeyedSegment
114
187
 
115
- /** @alpha */
188
+ /**
189
+ * @alpha
190
+ */
116
191
  export declare function resolveMapping(
117
192
  resultPath: PathSegment[],
118
193
  csm: ContentSourceMap,
119
194
  ): [ContentSourceMapMapping, string, string] | undefined
120
195
 
196
+ /** @internal */
197
+ export declare type SanityDocument<T extends Record<string, Any> = Record<string, Any>> = {
198
+ [P in keyof T]: T[P]
199
+ } & {
200
+ _id: string
201
+ _rev: string
202
+ _type: string
203
+ _createdAt: string
204
+ _updatedAt: string
205
+ /**
206
+ * Present when `perspective` is set to `previewDrafts`
207
+ */
208
+ _originalId?: string
209
+ }
210
+
121
211
  /** @public */
122
212
  export declare type StudioUrl =
123
213
  | `/${string}`
@@ -125,12 +215,15 @@ export declare type StudioUrl =
125
215
  | `https://${string}`
126
216
  | string
127
217
 
128
- /** generic way to walk a nested object or array and apply a mapping function to each value
218
+ /**
219
+ * generic way to walk a nested object or array and apply a mapping function to each value
129
220
  * @alpha
130
221
  */
131
222
  export declare function walkMap(value: unknown, mappingFn: WalkMapFn, path?: PathSegment[]): unknown
132
223
 
133
- /** @alpha */
224
+ /**
225
+ * @alpha
226
+ */
134
227
  export declare type WalkMapFn = (value: unknown, path: PathSegment[]) => unknown
135
228
 
136
229
  export {}
package/dist/csm.js CHANGED
@@ -63,27 +63,32 @@ function parseJsonPath(path) {
63
63
  }
64
64
  return parsed;
65
65
  }
66
- function createEditIntentLink(studioUrl, _ref, path) {
67
- let {
68
- _id,
69
- _type
70
- } = _ref;
71
- const _studioUrl = studioUrl.replace(/\/$/, "");
72
- const _path = encodeJsonPathToUriComponent(path);
73
- return "".concat(_studioUrl, "/intent/edit/id=").concat(_id, ";type=").concat(_type, ";path=").concat(_path);
66
+ function resolveMapping(resultPath, csm) {
67
+ const resultJsonPath = jsonPath(resultPath);
68
+ if (csm.mappings[resultJsonPath] !== void 0) {
69
+ return [csm.mappings[resultJsonPath], resultJsonPath, ""];
70
+ }
71
+ const mappings = Object.entries(csm.mappings).filter(_ref => {
72
+ let [key] = _ref;
73
+ return resultJsonPath.startsWith(key);
74
+ }).sort((_ref2, _ref3) => {
75
+ let [key1] = _ref2;
76
+ let [key2] = _ref3;
77
+ return key2.length - key1.length;
78
+ });
79
+ if (mappings.length == 0) {
80
+ return void 0;
81
+ }
82
+ const [matchedPath, mapping] = mappings[0];
83
+ const pathSuffix = resultJsonPath.substring(matchedPath.length);
84
+ return [mapping, matchedPath, pathSuffix];
74
85
  }
75
- function encodeJsonPathToUriComponent(path) {
76
- const sourcePath = Array.isArray(path) ? path : parseJsonPath(path);
77
- return encodeURIComponent(sourcePath.map((key, i) =>
78
- // eslint-disable-next-line no-nested-ternary
79
- typeof key === "number" ? "[".concat(key, "]") : i > 0 ? ".".concat(key) : key).join(""));
86
+ function isArray(value) {
87
+ return value !== null && Array.isArray(value);
80
88
  }
81
89
  function isRecord(value) {
82
90
  return typeof value === "object" && value !== null;
83
91
  }
84
- function isArray(value) {
85
- return value !== null && Array.isArray(value);
86
- }
87
92
  function walkMap(value, mappingFn) {
88
93
  let path = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
89
94
  if (isArray(value)) {
@@ -101,32 +106,106 @@ function walkMap(value, mappingFn) {
101
106
  });
102
107
  }
103
108
  if (isRecord(value)) {
104
- return Object.fromEntries(Object.entries(value).map(_ref2 => {
105
- let [k, v] = _ref2;
109
+ return Object.fromEntries(Object.entries(value).map(_ref4 => {
110
+ let [k, v] = _ref4;
106
111
  return [k, walkMap(v, mappingFn, path.concat(k))];
107
112
  }));
108
113
  }
109
114
  return mappingFn(value, path);
110
115
  }
111
- function resolveMapping(resultPath, csm) {
112
- const resultJsonPath = jsonPath(resultPath);
113
- if (csm.mappings[resultJsonPath] !== void 0) {
114
- return [csm.mappings[resultJsonPath], resultJsonPath, ""];
115
- }
116
- const mappings = Object.entries(csm.mappings).filter(_ref3 => {
117
- let [key] = _ref3;
118
- return resultJsonPath.startsWith(key);
119
- }).sort((_ref4, _ref5) => {
120
- let [key1] = _ref4;
121
- let [key2] = _ref5;
122
- return key2.length - key1.length;
116
+ const defaultUpdateFunction = changed => changed;
117
+ function applySourceDocuments(result, resultSourceMap, getCachedDocument) {
118
+ let updateFn = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : defaultUpdateFunction;
119
+ if (!resultSourceMap) return result;
120
+ return walkMap(result, (value, path) => {
121
+ var _a;
122
+ const resolveMappingResult = resolveMapping(path, resultSourceMap);
123
+ if (!resolveMappingResult) {
124
+ return value;
125
+ }
126
+ const [mapping,, pathSuffix] = resolveMappingResult;
127
+ if (mapping.type !== "value") {
128
+ return value;
129
+ }
130
+ if (mapping.source.type !== "documentValue") {
131
+ return value;
132
+ }
133
+ const sourceDocument = resultSourceMap.documents[mapping.source.document];
134
+ const sourcePath = resultSourceMap.paths[mapping.source.path];
135
+ if (sourceDocument) {
136
+ const cachedDocument = getCachedDocument(sourceDocument);
137
+ if (!cachedDocument) {
138
+ return value;
139
+ }
140
+ const parsedPath = parseJsonPath(sourcePath + pathSuffix);
141
+ const changedValue = cachedDocument ? (_a = getField(cachedDocument, parsedPath)) != null ? _a : value : value;
142
+ return value === changedValue ? value : updateFn(changedValue, {
143
+ cachedDocument,
144
+ previousValue: value,
145
+ sourceDocument,
146
+ sourcePath: parsedPath
147
+ });
148
+ }
149
+ return value;
123
150
  });
124
- if (mappings.length == 0) {
125
- return void 0;
151
+ }
152
+ function getField(obj, path) {
153
+ let value = obj;
154
+ for (const segment of path) {
155
+ if (typeof segment === "string") {
156
+ value = value[segment];
157
+ } else {
158
+ const match = typeof segment === "object" ? value.find(item => item._key === segment.key) : value[segment];
159
+ value = match || null;
160
+ }
161
+ if (value === null || value === void 0) {
162
+ break;
163
+ }
126
164
  }
127
- const [matchedPath, mapping] = mappings[0];
128
- const pathSuffix = resultJsonPath.substring(matchedPath.length);
129
- return [mapping, matchedPath, pathSuffix];
165
+ return value;
166
+ }
167
+ function createEditIntentLink(studioUrl, _ref5, path) {
168
+ let {
169
+ _id,
170
+ _type
171
+ } = _ref5;
172
+ const _studioUrl = studioUrl.replace(/\/$/, "");
173
+ const _path = encodeJsonPathToUriComponent(path);
174
+ return "".concat(_studioUrl, "/intent/edit/id=").concat(_id, ";type=").concat(_type, ";path=").concat(_path);
175
+ }
176
+ function encodeJsonPathToUriComponent(path) {
177
+ const sourcePath = Array.isArray(path) ? path : parseJsonPath(path);
178
+ return encodeURIComponent(sourcePath.map((key, i) => typeof key === "number" ? "[".concat(key, "]") : i > 0 ? ".".concat(key) : key).join(""));
179
+ }
180
+ function encodeIntoResult(result, csm, encoder, options) {
181
+ return walkMap(result, (value, path) => {
182
+ if (typeof value !== "string") {
183
+ return value;
184
+ }
185
+ const resolveMappingResult = resolveMapping(path, csm);
186
+ if (!resolveMappingResult) {
187
+ return value;
188
+ }
189
+ const [mapping, matchedPath, pathSuffix] = resolveMappingResult;
190
+ if (mapping.type !== "value") {
191
+ return value;
192
+ }
193
+ if (mapping.source.type !== "documentValue") {
194
+ return value;
195
+ }
196
+ const sourceDocument = csm.documents[mapping.source.document];
197
+ const sourcePath = csm.paths[mapping.source.path];
198
+ if (options == null ? void 0 : options.keyArraySelectors) {
199
+ const matchPathSegments = parseJsonPath(matchedPath);
200
+ const sourcePathSegments = parseJsonPath(sourcePath);
201
+ const fullSourceSegments = sourcePathSegments.concat(path.slice(matchPathSegments.length));
202
+ return encoder(value, sourceDocument, fullSourceSegments);
203
+ }
204
+ return encoder(value, sourceDocument, parseJsonPath(sourcePath + pathSuffix));
205
+ });
206
+ }
207
+ function encode(result, csm, encoder, options) {
208
+ return encodeIntoResult(result, csm, encoder, options);
130
209
  }
131
- export { createEditIntentLink, encodeJsonPathToUriComponent, jsonPath, resolveMapping, walkMap };
210
+ export { applySourceDocuments, createEditIntentLink, encode, encodeIntoResult, encodeJsonPathToUriComponent, jsonPath, parseJsonPath, resolveMapping, walkMap };
132
211
  //# sourceMappingURL=csm.js.map