@datocms/cma-client 5.1.12 → 5.1.14
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 +362 -167
- package/dist/cjs/generated/Client.js +1 -1
- package/dist/cjs/utilities/buildBlockRecord.js.map +1 -1
- package/dist/cjs/utilities/duplicateBlockRecord.js +2 -1
- package/dist/cjs/utilities/duplicateBlockRecord.js.map +1 -1
- package/dist/cjs/utilities/schemaRepository.js +107 -0
- package/dist/cjs/utilities/schemaRepository.js.map +1 -1
- package/dist/esm/fieldTypes/schema.d.ts +1 -1
- package/dist/esm/fieldTypes/single_block.d.ts +1 -1
- package/dist/esm/generated/ApiTypes.d.ts +4 -0
- package/dist/esm/generated/Client.js +1 -1
- package/dist/esm/generated/RawApiTypes.d.ts +4 -0
- package/dist/esm/generated/resources/Field.d.ts +100 -100
- package/dist/esm/utilities/buildBlockRecord.d.ts +10 -2
- package/dist/esm/utilities/buildBlockRecord.js.map +1 -1
- package/dist/esm/utilities/duplicateBlockRecord.js +2 -1
- package/dist/esm/utilities/duplicateBlockRecord.js.map +1 -1
- package/dist/esm/utilities/schemaRepository.d.ts +40 -0
- package/dist/esm/utilities/schemaRepository.js +107 -0
- package/dist/esm/utilities/schemaRepository.js.map +1 -1
- package/dist/types/fieldTypes/schema.d.ts +1 -1
- package/dist/types/fieldTypes/single_block.d.ts +1 -1
- package/dist/types/generated/ApiTypes.d.ts +4 -0
- package/dist/types/generated/RawApiTypes.d.ts +4 -0
- package/dist/types/generated/resources/Field.d.ts +100 -100
- package/dist/types/utilities/buildBlockRecord.d.ts +10 -2
- package/dist/types/utilities/schemaRepository.d.ts +40 -0
- package/package.json +4 -4
- package/src/fieldTypes/schema.ts +1 -1
- package/src/fieldTypes/single_block.ts +1 -1
- package/src/generated/ApiTypes.ts +4 -0
- package/src/generated/Client.ts +1 -1
- package/src/generated/RawApiTypes.ts +4 -0
- package/src/utilities/buildBlockRecord.ts +18 -2
- package/src/utilities/duplicateBlockRecord.ts +2 -1
- package/src/utilities/schemaRepository.ts +141 -0
package/README.md
CHANGED
|
@@ -1,28 +1,221 @@
|
|
|
1
|
-
|
|
1
|
+
# DatoCMS Content Management API Utilities
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Take a look at the full [API documentation](https://www.datocms.com/docs/content-management-api) for examples!
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Field Types
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
<a href="https://www.datocms.com/">
|
|
9
|
-
<img src="https://www.datocms.com/images/full_logo.svg" height="60">
|
|
10
|
-
</a>
|
|
11
|
-
<br /><br />
|
|
7
|
+
This library provides comprehensive TypeScript type definitions and utilities for all DatoCMS field types. Each field type includes type guards, validation functions, localization support, and editor appearance configurations.
|
|
12
8
|
|
|
13
|
-
|
|
9
|
+
### What's available
|
|
14
10
|
|
|
15
|
-
|
|
11
|
+
Every field type follows a consistent pattern providing:
|
|
16
12
|
|
|
17
|
-
|
|
13
|
+
- **Field value types**: TypeScript definitions for the field's data structure
|
|
14
|
+
- **Type guards**: Functions to validate field values at runtime
|
|
15
|
+
- **Localization support**: Utilities for handling localized field variants
|
|
16
|
+
- **Validation types**: Supported validators for the field type
|
|
17
|
+
- **Appearance configuration**: Editor types and their configuration options
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
**Example: `lat_lon` Field Type**
|
|
20
|
+
|
|
21
|
+
<details>
|
|
22
|
+
<summary>View example</summary>
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { isLatLonFieldValue, isLocalizedLatLonFieldValue } from '@datocms/cma-client';
|
|
26
|
+
import type { LatLonFieldValue, LatLonFieldValidators, LatLonFieldAppearance } from '@datocms/cma-client';
|
|
27
|
+
|
|
28
|
+
// Field value type - object with latitude/longitude or null
|
|
29
|
+
const value: LatLonFieldValue = { latitude: 45.4642, longitude: 9.1900 };
|
|
30
|
+
|
|
31
|
+
// Type guard functions for validation
|
|
32
|
+
if (isLatLonFieldValue(someValue)) {
|
|
33
|
+
// someValue is guaranteed to be { latitude: number; longitude: number } | null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (isLocalizedLatLonFieldValue(localizedValue)) {
|
|
37
|
+
// localizedValue is a localized lat/lon field
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Validator and appearance types available for type-safe configuration
|
|
41
|
+
type Validators = LatLonFieldValidators;
|
|
42
|
+
type Appearance = LatLonFieldAppearance;
|
|
43
|
+
```
|
|
44
|
+
</details>
|
|
45
|
+
|
|
46
|
+
### Context-Dependent field types
|
|
47
|
+
|
|
48
|
+
Some field types have different value formats depending on the API context (request vs response) or query parameters:
|
|
49
|
+
|
|
50
|
+
#### Request vs Response variations
|
|
51
|
+
|
|
52
|
+
**File and Gallery fields** have different type requirements for API requests versus responses:
|
|
53
|
+
|
|
54
|
+
<details>
|
|
55
|
+
<summary>View example</summary>
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import {
|
|
59
|
+
FileFieldValue,
|
|
60
|
+
FileFieldValueInRequest,
|
|
61
|
+
GalleryFieldValue,
|
|
62
|
+
GalleryFieldValueInRequest,
|
|
63
|
+
// Type guards for runtime validation
|
|
64
|
+
isFileFieldValue,
|
|
65
|
+
isFileFieldValueInRequest,
|
|
66
|
+
isGalleryFieldValue,
|
|
67
|
+
isGalleryFieldValueInRequest
|
|
68
|
+
} from '@datocms/cma-client';
|
|
69
|
+
|
|
70
|
+
// API Response format - all metadata fields present with defaults
|
|
71
|
+
const fileResponse: FileFieldValue = {
|
|
72
|
+
upload_id: "12345",
|
|
73
|
+
alt: null, // Always present (default: null)
|
|
74
|
+
title: null, // Always present (default: null)
|
|
75
|
+
custom_data: {}, // Always present (default: {})
|
|
76
|
+
focal_point: null // Always present (default: null)
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// API Request format - metadata fields are optional
|
|
80
|
+
const fileRequest: FileFieldValueInRequest = {
|
|
81
|
+
upload_id: "12345"
|
|
82
|
+
// alt, title, custom_data, focal_point are optional
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// Runtime validation for different contexts
|
|
86
|
+
if (isFileFieldValueInRequest(someFileValue)) {
|
|
87
|
+
// someFileValue has optional metadata fields
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (isGalleryFieldValue(someGalleryValue)) {
|
|
91
|
+
// someGalleryValue is array of files with all metadata present
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
</details>
|
|
95
|
+
|
|
96
|
+
#### "Nested Mode" Response variations
|
|
97
|
+
|
|
98
|
+
**Block-containing fields** (`structured_text`, `single_block`, `rich_text`) support different block representations for regular responses, for ["Nested Mode" responses](https://www.datocms.com/docs/content-management-api/resources/item#api-response-modes-regular-vs-nested), and for requests:
|
|
99
|
+
|
|
100
|
+
<details>
|
|
101
|
+
<summary>View example</summary>
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
import {
|
|
105
|
+
StructuredTextFieldValue,
|
|
106
|
+
StructuredTextFieldValueInRequest,
|
|
107
|
+
StructuredTextFieldValueInNestedResponse,
|
|
108
|
+
// Type guards for all variations (also available for single_block and rich_text)
|
|
109
|
+
isStructuredTextFieldValue,
|
|
110
|
+
isStructuredTextFieldValueInRequest,
|
|
111
|
+
isStructuredTextFieldValueInNestedResponse
|
|
112
|
+
} from '@datocms/cma-client';
|
|
113
|
+
|
|
114
|
+
// Regular response - blocks as string IDs
|
|
115
|
+
const standard: StructuredTextFieldValue = {
|
|
116
|
+
document: {
|
|
117
|
+
type: "root",
|
|
118
|
+
children: [
|
|
119
|
+
{
|
|
120
|
+
type: "block",
|
|
121
|
+
// String ID reference
|
|
122
|
+
item: "IdMLV2GJTXyQ0Bfns7R4IQ"
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// Nested Mode response (?nested=true) - blocks as full objects
|
|
129
|
+
const nested: StructuredTextFieldValueInNestedResponse = {
|
|
130
|
+
document: {
|
|
131
|
+
type: "root",
|
|
132
|
+
children: [
|
|
133
|
+
{
|
|
134
|
+
type: "block",
|
|
135
|
+
// Always full block object
|
|
136
|
+
item: {
|
|
137
|
+
id: "IdMLV2GJTXyQ0Bfns7R4IQ",
|
|
138
|
+
type: "item",
|
|
139
|
+
attributes: { /* ... */ },
|
|
140
|
+
relationships: { /* ... */ }
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// Request format - flexible block representation
|
|
148
|
+
const request: StructuredTextFieldValueInRequest = {
|
|
149
|
+
document: {
|
|
150
|
+
type: "root",
|
|
151
|
+
children: [
|
|
152
|
+
{
|
|
153
|
+
type: "block",
|
|
154
|
+
// Can be string ID, to keep block unchanged...
|
|
155
|
+
item: "FicV5CxCSQ6yOrgfwRoiKA"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
type: "block",
|
|
159
|
+
// ...or full block object (to create new blocks or update existing ones)
|
|
160
|
+
item: {
|
|
161
|
+
type: "item",
|
|
162
|
+
attributes: { /* ... */ },
|
|
163
|
+
relationships: { /* ... */ }
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
]
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// Runtime validation for different contexts
|
|
171
|
+
if (isStructuredTextFieldValueInNestedResponse(someStructuredText)) {
|
|
172
|
+
// someStructuredText has blocks as full objects
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (isStructuredTextFieldValueInRequest(requestData)) {
|
|
176
|
+
// requestData allows flexible block representations
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
</details>
|
|
180
|
+
|
|
181
|
+
These variants ensure type safety across different API contexts while maintaining the same conceptual data structure. All localized variants also have corresponding type guards (e.g., `isLocalizedStructuredTextFieldValueInRequest`, `isLocalizedStructuredTextFieldValueInNestedResponse`, etc.).
|
|
182
|
+
|
|
183
|
+
**TypeScript Generics Support:** For maximum type safety, all field value types and type guards for block-containing fields accept [`ItemTypeDefinition` generics](https://www.datocms.com/docs/content-management-api/resources/item#type-safe-development-with-typescript) to provide precise typing for your specific schema:
|
|
20
184
|
|
|
21
185
|
<details>
|
|
22
|
-
<summary
|
|
186
|
+
<summary>View example</summary>
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
import type { MyArticle, MyArticleSection } from './schema';
|
|
190
|
+
|
|
191
|
+
// Fully typed structured text with specific block types
|
|
192
|
+
const content: StructuredTextFieldValueInRequest<MyArticleSection> = {
|
|
193
|
+
document: {
|
|
194
|
+
type: "root",
|
|
195
|
+
children: [/* ... */]
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// Type guard with generic for precise validation
|
|
200
|
+
if (isStructuredTextFieldValueInNestedResponse<MyArticleSection>(value)) {
|
|
201
|
+
// value is now typed with your specific block schema
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
</details>
|
|
205
|
+
|
|
206
|
+
## Block Processing Utilities
|
|
207
|
+
|
|
208
|
+
### Inspecting Records and Blocks
|
|
209
|
+
|
|
210
|
+
The `inspectItem()` function provides a visual, tree-structured representation of DatoCMS records in the console, making it easier to debug and understand complex content structures.
|
|
211
|
+
|
|
212
|
+
#### inspectItem()
|
|
23
213
|
|
|
24
214
|
Formats a DatoCMS item (record or block) as a visual tree structure, showing all fields with proper formatting for each field type. Particularly useful for debugging nested structures like modular content and structured text.
|
|
25
215
|
|
|
216
|
+
<details>
|
|
217
|
+
<summary>View details</summary>
|
|
218
|
+
|
|
26
219
|
**TypeScript Signature:**
|
|
27
220
|
```typescript
|
|
28
221
|
function inspectItem(
|
|
@@ -59,19 +252,61 @@ console.log(inspectItem(record));
|
|
|
59
252
|
```
|
|
60
253
|
</details>
|
|
61
254
|
|
|
62
|
-
###
|
|
255
|
+
### Creating and Duplicating Blocks
|
|
256
|
+
|
|
257
|
+
#### buildBlockRecord()
|
|
258
|
+
|
|
259
|
+
Converts a block data object into the proper format for API requests.
|
|
260
|
+
|
|
261
|
+
<details>
|
|
262
|
+
<summary>View details</summary>
|
|
263
|
+
|
|
264
|
+
**TypeScript Signature:**
|
|
265
|
+
```typescript
|
|
266
|
+
function buildBlockRecord<D extends ItemTypeDefinition>(
|
|
267
|
+
body: ItemUpdateSchema<ToItemDefinitionInRequest<D>>
|
|
268
|
+
): NewBlockInRequest<ToItemDefinitionInRequest<D>>
|
|
269
|
+
```
|
|
63
270
|
|
|
64
|
-
|
|
271
|
+
**Parameters:**
|
|
272
|
+
- `body`: Block data in update schema format
|
|
65
273
|
|
|
66
|
-
|
|
274
|
+
**Returns:** Formatted block record ready for API requests
|
|
275
|
+
</details>
|
|
67
276
|
|
|
68
|
-
|
|
277
|
+
#### duplicateBlockRecord()
|
|
278
|
+
|
|
279
|
+
Creates a deep copy of a block record, including all nested blocks, removing IDs to create new instances.
|
|
69
280
|
|
|
70
281
|
<details>
|
|
71
|
-
<summary
|
|
282
|
+
<summary>View details</summary>
|
|
283
|
+
|
|
284
|
+
**TypeScript Signature:**
|
|
285
|
+
```typescript
|
|
286
|
+
async function duplicateBlockRecord<D extends ItemTypeDefinition>(
|
|
287
|
+
existingBlock: ItemWithOptionalIdAndMeta<ToItemDefinitionInNestedResponse<D>>,
|
|
288
|
+
schemaRepository: SchemaRepository
|
|
289
|
+
): Promise<NewBlockInRequest<ToItemDefinitionInRequest<D>>>
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
**Parameters:**
|
|
293
|
+
- `existingBlock`: The block to duplicate
|
|
294
|
+
- `schemaRepository`: Repository for schema lookups
|
|
295
|
+
|
|
296
|
+
**Returns:** New block record without IDs, ready to be created
|
|
297
|
+
</details>
|
|
298
|
+
|
|
299
|
+
### Recursive Block Operations
|
|
300
|
+
|
|
301
|
+
DatoCMS supports three field types that can contain blocks: Modular Content (arrays of blocks), Single Block fields, and Structured Text (rich-text with embedded blocks). These functions abstract away the differences between field types and can traverse blocks recursively, processing nested blocks within blocks. They require a `SchemaRepository` instance to look up field definitions for nested blocks.
|
|
302
|
+
|
|
303
|
+
#### visitBlocksInNonLocalizedFieldValue()
|
|
72
304
|
|
|
73
305
|
Visit every block in a non-localized field value recursively, including blocks nested within other blocks.
|
|
74
306
|
|
|
307
|
+
<details>
|
|
308
|
+
<summary>View details</summary>
|
|
309
|
+
|
|
75
310
|
**TypeScript Signature:**
|
|
76
311
|
```typescript
|
|
77
312
|
async function visitBlocksInNonLocalizedFieldValue(
|
|
@@ -79,24 +314,23 @@ async function visitBlocksInNonLocalizedFieldValue(
|
|
|
79
314
|
fieldType: string,
|
|
80
315
|
schemaRepository: SchemaRepository,
|
|
81
316
|
visitor: (item: BlockInRequest, path: TreePath) => void | Promise<void>,
|
|
82
|
-
path?: TreePath
|
|
83
317
|
): Promise<void>
|
|
84
318
|
```
|
|
85
319
|
|
|
86
320
|
**Parameters:**
|
|
87
321
|
- `nonLocalizedFieldValue`: The non-localized field value
|
|
88
|
-
- `fieldType`: The
|
|
322
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
89
323
|
- `schemaRepository`: Repository for caching schema lookups
|
|
90
324
|
- `visitor`: Function called for each block (including nested)
|
|
91
|
-
- `path`: Optional base path for tracking location
|
|
92
|
-
```
|
|
93
325
|
</details>
|
|
94
326
|
|
|
95
|
-
|
|
96
|
-
<summary><strong>mapBlocksInNonLocalizedFieldValue()</strong> - Recursively transform all blocks</summary>
|
|
327
|
+
#### mapBlocksInNonLocalizedFieldValue()
|
|
97
328
|
|
|
98
329
|
Transform all blocks in a non-localized field value recursively, including nested blocks.
|
|
99
330
|
|
|
331
|
+
<details>
|
|
332
|
+
<summary>View details</summary>
|
|
333
|
+
|
|
100
334
|
**TypeScript Signature:**
|
|
101
335
|
```typescript
|
|
102
336
|
async function mapBlocksInNonLocalizedFieldValue(
|
|
@@ -104,24 +338,25 @@ async function mapBlocksInNonLocalizedFieldValue(
|
|
|
104
338
|
fieldType: string,
|
|
105
339
|
schemaRepository: SchemaRepository,
|
|
106
340
|
mapper: (item: BlockInRequest, path: TreePath) => BlockInRequest | Promise<BlockInRequest>,
|
|
107
|
-
path?: TreePath
|
|
108
341
|
): Promise<unknown>
|
|
109
342
|
```
|
|
110
343
|
|
|
111
344
|
**Parameters:**
|
|
112
345
|
- `nonLocalizedFieldValue`: The non-localized field value
|
|
113
|
-
- `fieldType`: The
|
|
346
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
114
347
|
- `schemaRepository`: Repository for caching schema lookups
|
|
115
348
|
- `mapper`: Function that transforms each block
|
|
116
349
|
|
|
117
350
|
**Returns:** New field value
|
|
118
351
|
</details>
|
|
119
352
|
|
|
120
|
-
|
|
121
|
-
<summary><strong>filterBlocksInNonLocalizedFieldValue()</strong> - Recursively filter blocks</summary>
|
|
353
|
+
#### filterBlocksInNonLocalizedFieldValue()
|
|
122
354
|
|
|
123
355
|
Filter blocks recursively, removing blocks at any nesting level that don't match the predicate.
|
|
124
356
|
|
|
357
|
+
<details>
|
|
358
|
+
<summary>View details</summary>
|
|
359
|
+
|
|
125
360
|
**TypeScript Signature:**
|
|
126
361
|
```typescript
|
|
127
362
|
async function filterBlocksInNonLocalizedFieldValue(
|
|
@@ -129,13 +364,12 @@ async function filterBlocksInNonLocalizedFieldValue(
|
|
|
129
364
|
fieldType: string,
|
|
130
365
|
schemaRepository: SchemaRepository,
|
|
131
366
|
predicate: (item: BlockInRequest, path: TreePath) => boolean | Promise<boolean>,
|
|
132
|
-
path?: TreePath
|
|
133
367
|
): Promise<unknown>
|
|
134
368
|
```
|
|
135
369
|
|
|
136
370
|
**Parameters:**
|
|
137
371
|
- `nonLocalizedFieldValue`: The non-localized field value to filter
|
|
138
|
-
- `fieldType`: The
|
|
372
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
139
373
|
- `schemaRepository`: Repository for caching schema lookups
|
|
140
374
|
- `predicate`: Function that tests each block
|
|
141
375
|
|
|
@@ -153,11 +387,13 @@ const noVideos = await filterBlocksInNonLocalizedFieldValue(
|
|
|
153
387
|
```
|
|
154
388
|
</details>
|
|
155
389
|
|
|
156
|
-
|
|
157
|
-
<summary><strong>findAllBlocksInNonLocalizedFieldValue()</strong> - Recursively search for blocks</summary>
|
|
390
|
+
#### findAllBlocksInNonLocalizedFieldValue()
|
|
158
391
|
|
|
159
392
|
Find all blocks that match the predicate, searching recursively through nested blocks.
|
|
160
393
|
|
|
394
|
+
<details>
|
|
395
|
+
<summary>View details</summary>
|
|
396
|
+
|
|
161
397
|
**TypeScript Signature:**
|
|
162
398
|
```typescript
|
|
163
399
|
async function findAllBlocksInNonLocalizedFieldValue(
|
|
@@ -165,24 +401,25 @@ async function findAllBlocksInNonLocalizedFieldValue(
|
|
|
165
401
|
fieldType: string,
|
|
166
402
|
schemaRepository: SchemaRepository,
|
|
167
403
|
predicate: (item: BlockInRequest, path: TreePath) => boolean | Promise<boolean>,
|
|
168
|
-
path?: TreePath
|
|
169
404
|
): Promise<Array<{ item: BlockInRequest; path: TreePath }>>
|
|
170
405
|
```
|
|
171
406
|
|
|
172
407
|
**Parameters:**
|
|
173
408
|
- `nonLocalizedFieldValue`: The non-localized field value to search
|
|
174
|
-
- `fieldType`: The
|
|
409
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
175
410
|
- `schemaRepository`: Repository for caching schema lookups
|
|
176
411
|
- `predicate`: Function that tests each block
|
|
177
412
|
|
|
178
413
|
**Returns:** Array of all matching blocks with their paths
|
|
179
414
|
</details>
|
|
180
415
|
|
|
181
|
-
|
|
182
|
-
<summary><strong>reduceBlocksInNonLocalizedFieldValue()</strong> - Recursively reduce blocks</summary>
|
|
416
|
+
#### reduceBlocksInNonLocalizedFieldValue()
|
|
183
417
|
|
|
184
418
|
Reduce all blocks recursively to a single value.
|
|
185
419
|
|
|
420
|
+
<details>
|
|
421
|
+
<summary>View details</summary>
|
|
422
|
+
|
|
186
423
|
**TypeScript Signature:**
|
|
187
424
|
```typescript
|
|
188
425
|
async function reduceBlocksInNonLocalizedFieldValue<R>(
|
|
@@ -191,26 +428,26 @@ async function reduceBlocksInNonLocalizedFieldValue<R>(
|
|
|
191
428
|
schemaRepository: SchemaRepository,
|
|
192
429
|
reducer: (accumulator: R, item: BlockInRequest, path: TreePath) => R | Promise<R>,
|
|
193
430
|
initialValue: R,
|
|
194
|
-
path?: TreePath
|
|
195
431
|
): Promise<R>
|
|
196
432
|
```
|
|
197
433
|
|
|
198
434
|
**Parameters:**
|
|
199
435
|
- `nonLocalizedFieldValue`: The non-localized field value to reduce
|
|
200
|
-
- `fieldType`: The
|
|
436
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
201
437
|
- `schemaRepository`: Repository for caching schema lookups
|
|
202
438
|
- `reducer`: Function that processes each block
|
|
203
439
|
- `initialValue`: Initial accumulator value
|
|
204
440
|
|
|
205
441
|
**Returns:** The final accumulated value
|
|
206
|
-
```
|
|
207
442
|
</details>
|
|
208
443
|
|
|
209
|
-
|
|
210
|
-
<summary><strong>someBlocksInNonLocalizedFieldValue()</strong> - Recursively test for any match</summary>
|
|
444
|
+
#### someBlocksInNonLocalizedFieldValue()
|
|
211
445
|
|
|
212
446
|
Check if any block (including nested) matches the predicate.
|
|
213
447
|
|
|
448
|
+
<details>
|
|
449
|
+
<summary>View details</summary>
|
|
450
|
+
|
|
214
451
|
**TypeScript Signature:**
|
|
215
452
|
```typescript
|
|
216
453
|
async function someBlocksInNonLocalizedFieldValue(
|
|
@@ -218,25 +455,25 @@ async function someBlocksInNonLocalizedFieldValue(
|
|
|
218
455
|
fieldType: string,
|
|
219
456
|
schemaRepository: SchemaRepository,
|
|
220
457
|
predicate: (item: BlockInRequest, path: TreePath) => boolean | Promise<boolean>,
|
|
221
|
-
path?: TreePath
|
|
222
458
|
): Promise<boolean>
|
|
223
459
|
```
|
|
224
460
|
|
|
225
461
|
**Parameters:**
|
|
226
462
|
- `nonLocalizedFieldValue`: The non-localized field value to test
|
|
227
|
-
- `fieldType`: The
|
|
463
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
228
464
|
- `schemaRepository`: Repository for caching schema lookups
|
|
229
465
|
- `predicate`: Function that tests each block
|
|
230
466
|
|
|
231
467
|
**Returns:** True if any block matches
|
|
232
|
-
```
|
|
233
468
|
</details>
|
|
234
469
|
|
|
235
|
-
|
|
236
|
-
<summary><strong>everyBlockInNonLocalizedFieldValue()</strong> - Recursively test if all match</summary>
|
|
470
|
+
#### everyBlockInNonLocalizedFieldValue()
|
|
237
471
|
|
|
238
472
|
Check if every block (including nested) matches the predicate.
|
|
239
473
|
|
|
474
|
+
<details>
|
|
475
|
+
<summary>View details</summary>
|
|
476
|
+
|
|
240
477
|
**TypeScript Signature:**
|
|
241
478
|
```typescript
|
|
242
479
|
async function everyBlockInNonLocalizedFieldValue(
|
|
@@ -244,83 +481,28 @@ async function everyBlockInNonLocalizedFieldValue(
|
|
|
244
481
|
fieldType: string,
|
|
245
482
|
schemaRepository: SchemaRepository,
|
|
246
483
|
predicate: (item: BlockInRequest, path: TreePath) => boolean | Promise<boolean>,
|
|
247
|
-
path?: TreePath
|
|
248
484
|
): Promise<boolean>
|
|
249
485
|
```
|
|
250
486
|
|
|
251
487
|
**Parameters:**
|
|
252
488
|
- `nonLocalizedFieldValue`: The non-localized field value to test
|
|
253
|
-
- `fieldType`: The
|
|
489
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
254
490
|
- `schemaRepository`: Repository for caching schema lookups
|
|
255
491
|
- `predicate`: Function that tests each block
|
|
256
492
|
|
|
257
493
|
**Returns:** True if all blocks match
|
|
258
494
|
</details>
|
|
259
495
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
<details>
|
|
263
|
-
<summary><strong>buildBlockRecord()</strong> - Create block records from data</summary>
|
|
264
|
-
|
|
265
|
-
Converts a block data object into the proper format for API requests.
|
|
266
|
-
|
|
267
|
-
**TypeScript Signature:**
|
|
268
|
-
```typescript
|
|
269
|
-
function buildBlockRecord<D extends ItemTypeDefinition>(
|
|
270
|
-
body: ItemUpdateSchema<ToItemDefinitionInRequest<D>>
|
|
271
|
-
): NewBlockInRequest<ToItemDefinitionInRequest<D>>
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
**Parameters:**
|
|
275
|
-
- `body`: Block data in update schema format
|
|
276
|
-
|
|
277
|
-
**Returns:** Formatted block record ready for API requests
|
|
278
|
-
</details>
|
|
279
|
-
|
|
280
|
-
<details>
|
|
281
|
-
<summary><strong>duplicateBlockRecord()</strong> - Deep clone blocks with nested content</summary>
|
|
282
|
-
|
|
283
|
-
Creates a deep copy of a block record, including all nested blocks, removing IDs to create new instances.
|
|
284
|
-
|
|
285
|
-
**TypeScript Signature:**
|
|
286
|
-
```typescript
|
|
287
|
-
async function duplicateBlockRecord<D extends ItemTypeDefinition>(
|
|
288
|
-
existingBlock: ItemWithOptionalIdAndMeta<ToItemDefinitionInNestedResponse<D>>,
|
|
289
|
-
schemaRepository: SchemaRepository
|
|
290
|
-
): Promise<NewBlockInRequest<ToItemDefinitionInRequest<D>>>
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
**Parameters:**
|
|
294
|
-
- `existingBlock`: The block to duplicate
|
|
295
|
-
- `schemaRepository`: Repository for schema lookups
|
|
296
|
-
|
|
297
|
-
**Returns:** New block record without IDs, ready to be created
|
|
298
|
-
</details>
|
|
299
|
-
|
|
300
|
-
### 3. Localization-Aware Field Utilities
|
|
496
|
+
## Unified Field Processing (Localized & Non-Localized)
|
|
301
497
|
|
|
302
498
|
These utilities provide a unified interface for working with DatoCMS field values that may or may not be localized. They eliminate the need for conditional logic when processing fields that could be either localized or non-localized.
|
|
303
499
|
|
|
304
|
-
|
|
305
|
-
<summary><strong>isLocalized()</strong> - Check if a field is localized</summary>
|
|
306
|
-
|
|
307
|
-
Determines whether a DatoCMS field is configured for localization.
|
|
500
|
+
#### mapNormalizedFieldValues() / mapNormalizedFieldValuesAsync()
|
|
308
501
|
|
|
309
|
-
|
|
310
|
-
```typescript
|
|
311
|
-
function isLocalized(field: Field): boolean
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
**Parameters:**
|
|
315
|
-
- `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
316
|
-
|
|
317
|
-
**Returns:** True if the field is localized, false otherwise
|
|
318
|
-
</details>
|
|
502
|
+
Apply a transformation function to field values, handling both localized and non-localized fields uniformly.
|
|
319
503
|
|
|
320
504
|
<details>
|
|
321
|
-
<summary
|
|
322
|
-
|
|
323
|
-
Apply a transformation function to field values, handling both localized and non-localized fields uniformly.
|
|
505
|
+
<summary>View details</summary>
|
|
324
506
|
|
|
325
507
|
**TypeScript Signatures:**
|
|
326
508
|
```typescript
|
|
@@ -338,18 +520,20 @@ async function mapNormalizedFieldValuesAsync<TInput, TOutput>(
|
|
|
338
520
|
```
|
|
339
521
|
|
|
340
522
|
**Parameters:**
|
|
341
|
-
- `fieldType`: The
|
|
523
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
342
524
|
- `nonLocalizedFieldValue`: The non-localized field value (localized or non-localized)
|
|
343
525
|
- `mapFn`: Function to transform each value (receives locale for localized fields, undefined for non-localized)
|
|
344
526
|
|
|
345
527
|
**Returns:** Transformed value maintaining the same structure
|
|
346
528
|
</details>
|
|
347
529
|
|
|
348
|
-
|
|
349
|
-
<summary><strong>filterNormalizedFieldValues() / filterNormalizedFieldValuesAsync()</strong> - Filter field values</summary>
|
|
530
|
+
#### filterNormalizedFieldValues() / filterNormalizedFieldValuesAsync()
|
|
350
531
|
|
|
351
532
|
Filter field values based on a predicate, handling both localized and non-localized fields.
|
|
352
533
|
|
|
534
|
+
<details>
|
|
535
|
+
<summary>View details</summary>
|
|
536
|
+
|
|
353
537
|
**TypeScript Signatures:**
|
|
354
538
|
```typescript
|
|
355
539
|
function filterNormalizedFieldValues<T>(
|
|
@@ -366,18 +550,20 @@ async function filterNormalizedFieldValuesAsync<T>(
|
|
|
366
550
|
```
|
|
367
551
|
|
|
368
552
|
**Parameters:**
|
|
369
|
-
- `fieldType`: The
|
|
553
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
370
554
|
- `nonLocalizedFieldValue`: The non-localized field value to filter
|
|
371
555
|
- `filterFn`: Predicate function for filtering
|
|
372
556
|
|
|
373
557
|
**Returns:** Filtered value or undefined if all filtered out
|
|
374
558
|
</details>
|
|
375
559
|
|
|
376
|
-
|
|
377
|
-
<summary><strong>visitNormalizedFieldValues() / visitNormalizedFieldValuesAsync()</strong> - Iterate over field values</summary>
|
|
560
|
+
#### visitNormalizedFieldValues() / visitNormalizedFieldValuesAsync()
|
|
378
561
|
|
|
379
562
|
Visit each value in a field, handling both localized and non-localized fields.
|
|
380
563
|
|
|
564
|
+
<details>
|
|
565
|
+
<summary>View details</summary>
|
|
566
|
+
|
|
381
567
|
**TypeScript Signatures:**
|
|
382
568
|
```typescript
|
|
383
569
|
function visitNormalizedFieldValues<T>(
|
|
@@ -394,16 +580,18 @@ async function visitNormalizedFieldValuesAsync<T>(
|
|
|
394
580
|
```
|
|
395
581
|
|
|
396
582
|
**Parameters:**
|
|
397
|
-
- `fieldType`: The
|
|
583
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
398
584
|
- `nonLocalizedFieldValue`: The non-localized field value to visit
|
|
399
585
|
- `visitFn`: Function called for each value
|
|
400
586
|
</details>
|
|
401
587
|
|
|
402
|
-
|
|
403
|
-
<summary><strong>someNormalizedFieldValues() / someNormalizedFieldValuesAsync()</strong> - Test if any value matches</summary>
|
|
588
|
+
#### someNormalizedFieldValues() / someNormalizedFieldValuesAsync()
|
|
404
589
|
|
|
405
590
|
Check if at least one field value passes the test.
|
|
406
591
|
|
|
592
|
+
<details>
|
|
593
|
+
<summary>View details</summary>
|
|
594
|
+
|
|
407
595
|
**TypeScript Signatures:**
|
|
408
596
|
```typescript
|
|
409
597
|
function someNormalizedFieldValues<T>(
|
|
@@ -420,18 +608,20 @@ async function someNormalizedFieldValuesAsync<T>(
|
|
|
420
608
|
```
|
|
421
609
|
|
|
422
610
|
**Parameters:**
|
|
423
|
-
- `fieldType`: The
|
|
611
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
424
612
|
- `nonLocalizedFieldValue`: The non-localized field value to test
|
|
425
613
|
- `testFn`: Predicate function
|
|
426
614
|
|
|
427
615
|
**Returns:** True if any value passes the test
|
|
428
616
|
</details>
|
|
429
617
|
|
|
430
|
-
|
|
431
|
-
<summary><strong>everyNormalizedFieldValue() / everyNormalizedFieldValueAsync()</strong> - Test if all values match</summary>
|
|
618
|
+
#### everyNormalizedFieldValue() / everyNormalizedFieldValueAsync()
|
|
432
619
|
|
|
433
620
|
Check if all field values pass the test.
|
|
434
621
|
|
|
622
|
+
<details>
|
|
623
|
+
<summary>View details</summary>
|
|
624
|
+
|
|
435
625
|
**TypeScript Signatures:**
|
|
436
626
|
```typescript
|
|
437
627
|
function everyNormalizedFieldValue<T>(
|
|
@@ -448,18 +638,20 @@ async function everyNormalizedFieldValueAsync<T>(
|
|
|
448
638
|
```
|
|
449
639
|
|
|
450
640
|
**Parameters:**
|
|
451
|
-
- `fieldType`: The
|
|
641
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
452
642
|
- `nonLocalizedFieldValue`: The non-localized field value to test
|
|
453
643
|
- `testFn`: Predicate function
|
|
454
644
|
|
|
455
645
|
**Returns:** True if all values pass the test
|
|
456
646
|
</details>
|
|
457
647
|
|
|
458
|
-
|
|
459
|
-
<summary><strong>toNormalizedFieldValueEntries() / fromNormalizedFieldValueEntries()</strong> - Convert between formats</summary>
|
|
648
|
+
#### toNormalizedFieldValueEntries() / fromNormalizedFieldValueEntries()
|
|
460
649
|
|
|
461
650
|
Convert field values to/from a normalized entry format for uniform processing.
|
|
462
651
|
|
|
652
|
+
<details>
|
|
653
|
+
<summary>View details</summary>
|
|
654
|
+
|
|
463
655
|
**TypeScript Signatures:**
|
|
464
656
|
```typescript
|
|
465
657
|
function toNormalizedFieldValueEntries<T>(
|
|
@@ -479,7 +671,7 @@ type NormalizedFieldValueEntry<T> = {
|
|
|
479
671
|
```
|
|
480
672
|
|
|
481
673
|
**Parameters:**
|
|
482
|
-
- `fieldType`: The
|
|
674
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
483
675
|
- `nonLocalizedFieldValue`/`entries non-localized`: Value to convert from/to
|
|
484
676
|
|
|
485
677
|
**Returns:** Normalized entries array or reconstructed field value
|
|
@@ -500,22 +692,60 @@ const result = fromNormalizedFieldValueEntries(field, processed);
|
|
|
500
692
|
```
|
|
501
693
|
</details>
|
|
502
694
|
|
|
503
|
-
|
|
695
|
+
## SchemaRepository
|
|
696
|
+
|
|
697
|
+
The `SchemaRepository` class provides a lightweight, in-memory cache for DatoCMS schema entities (item types, fields, fieldsets, and plugins). It helps avoid redundant API calls when working across multiple functions or utilities that require schema lookups.
|
|
698
|
+
|
|
699
|
+
**Why use it?**
|
|
504
700
|
|
|
505
|
-
|
|
701
|
+
- **Cache once, reuse everywhere**: The first API call stores results in memory; all subsequent lookups are instant.
|
|
702
|
+
- **Efficient schema access**: Retrieve entities by ID, API key, or package name without re-fetching.
|
|
703
|
+
- **Optimized for block processing**: Essential for utilities like `mapBlocksInNonLocalizedFieldValue`.
|
|
704
|
+
- **Fewer API calls**: Dramatically speeds up bulk operations and complex traversals.
|
|
705
|
+
|
|
706
|
+
**Usage Example:**
|
|
506
707
|
|
|
507
708
|
<details>
|
|
508
|
-
<summary
|
|
709
|
+
<summary>View example</summary>
|
|
509
710
|
|
|
510
|
-
|
|
711
|
+
```typescript
|
|
712
|
+
const schemaRepository = new SchemaRepository(client);
|
|
511
713
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
714
|
+
// First call: fetches from API and caches result
|
|
715
|
+
const blogPost = await schemaRepository.getItemTypeByApiKey('blog_post');
|
|
716
|
+
const fields = await schemaRepository.getItemTypeFields(blogPost);
|
|
717
|
+
|
|
718
|
+
// Next calls: resolved instantly from cache (no API calls)
|
|
719
|
+
const sameBlogPost = await schemaRepository.getItemTypeByApiKey('blog_post');
|
|
720
|
+
const sameFields = await schemaRepository.getItemTypeFields(blogPost);
|
|
721
|
+
|
|
722
|
+
// Works seamlessly with block-processing utilities
|
|
723
|
+
await mapBlocksInNonLocalizedFieldValue(
|
|
724
|
+
fieldValue,
|
|
725
|
+
fieldType,
|
|
726
|
+
schemaRepository, // share cached lookups
|
|
727
|
+
async (block) => {
|
|
728
|
+
// transform block here
|
|
729
|
+
}
|
|
730
|
+
);
|
|
731
|
+
```
|
|
732
|
+
</details>
|
|
733
|
+
|
|
734
|
+
**When to Use**
|
|
735
|
+
|
|
736
|
+
* Traversing relationships that repeatedly query schema
|
|
737
|
+
* Bulk record processing scripts
|
|
738
|
+
* Block-processing utilities that need frequent lookups
|
|
739
|
+
* Any script where reducing API calls matters
|
|
740
|
+
|
|
741
|
+
**When Not to Use**
|
|
742
|
+
|
|
743
|
+
* Scripts that modify schema (models, fields, etc.)
|
|
744
|
+
* Long-running applications (cache never expires)
|
|
745
|
+
* Situations where the schema might change during execution
|
|
746
|
+
|
|
747
|
+
<details><summary><strong>Class signature</strong></summary>
|
|
517
748
|
|
|
518
|
-
**TypeScript Class:**
|
|
519
749
|
```typescript
|
|
520
750
|
class SchemaRepository {
|
|
521
751
|
constructor(client: GenericClient)
|
|
@@ -542,41 +772,6 @@ class SchemaRepository {
|
|
|
542
772
|
// ... and more raw variants
|
|
543
773
|
}
|
|
544
774
|
```
|
|
545
|
-
|
|
546
|
-
**When to Use:**
|
|
547
|
-
- Complex traversal operations that repeatedly lookup schema
|
|
548
|
-
- Bulk operations processing multiple records
|
|
549
|
-
- Scripts that need efficient access to schema information
|
|
550
|
-
- Working with recursive block utilities
|
|
551
|
-
|
|
552
|
-
**When NOT to Use:**
|
|
553
|
-
- Scripts that modify schema (models, fields, etc.)
|
|
554
|
-
- Long-running applications (no cache expiration)
|
|
555
|
-
- When schema might change during execution
|
|
556
|
-
|
|
557
|
-
**Usage Example:**
|
|
558
|
-
```typescript
|
|
559
|
-
const schemaRepository = new SchemaRepository(client);
|
|
560
|
-
|
|
561
|
-
// First call fetches from API and caches
|
|
562
|
-
const blogPost = await schemaRepository.getItemTypeByApiKey('blog_post');
|
|
563
|
-
const fields = await schemaRepository.getItemTypeFields(blogPost);
|
|
564
|
-
|
|
565
|
-
// Subsequent calls use cached data (no API calls)
|
|
566
|
-
const sameBlogPost = await schemaRepository.getItemTypeByApiKey('blog_post');
|
|
567
|
-
const sameFields = await schemaRepository.getItemTypeFields(blogPost);
|
|
568
|
-
|
|
569
|
-
// Use with recursive utilities for optimal performance
|
|
570
|
-
await mapBlocksInNonLocalizedFieldValue(
|
|
571
|
-
schemaRepository, // Pass repository for efficient lookups
|
|
572
|
-
field,
|
|
573
|
-
fieldValue,
|
|
574
|
-
async (block) => { /* transform */ }
|
|
575
|
-
);
|
|
576
|
-
```
|
|
577
|
-
|
|
578
|
-
**Performance Impact:**
|
|
579
|
-
Without SchemaRepository, a script processing structured text with nested blocks might make the same API calls dozens of times. SchemaRepository ensures each unique schema request is made only once, dramatically improving performance for complex operations.
|
|
580
775
|
</details>
|
|
581
776
|
|
|
582
777
|
## Contributing
|