@datocms/cma-client 5.1.11 → 5.1.13
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 +313 -178
- package/dist/cjs/fieldTypes/file.js +6 -6
- package/dist/cjs/fieldTypes/gallery.js +7 -7
- package/dist/cjs/fieldTypes/rich_text.js +14 -12
- package/dist/cjs/fieldTypes/rich_text.js.map +1 -1
- package/dist/cjs/fieldTypes/schema.js +3 -0
- package/dist/cjs/fieldTypes/schema.js.map +1 -0
- package/dist/cjs/fieldTypes/single_block.js +13 -12
- package/dist/cjs/fieldTypes/single_block.js.map +1 -1
- package/dist/cjs/fieldTypes/structured_text.js +13 -12
- package/dist/cjs/fieldTypes/structured_text.js.map +1 -1
- package/dist/cjs/generated/Client.js +1 -1
- package/dist/cjs/generated/resources/Item.js.map +1 -1
- package/dist/cjs/generated/resources/ScheduledPublication.js.map +1 -1
- package/dist/cjs/generated/resources/ScheduledUnpublishing.js.map +1 -1
- package/dist/cjs/generated/resources/Upload.js.map +1 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/utilities/buildBlockRecord.js +1 -46
- package/dist/cjs/utilities/buildBlockRecord.js.map +1 -1
- package/dist/cjs/utilities/duplicateBlockRecord.js +50 -0
- package/dist/cjs/utilities/duplicateBlockRecord.js.map +1 -0
- package/dist/cjs/utilities/inspectItem.js +50 -20
- package/dist/cjs/utilities/inspectItem.js.map +1 -1
- package/dist/cjs/utilities/nonRecursiveBlocks.js +1 -170
- package/dist/cjs/utilities/nonRecursiveBlocks.js.map +1 -1
- package/dist/cjs/utilities/recursiveBlocks.js +52 -112
- package/dist/cjs/utilities/recursiveBlocks.js.map +1 -1
- package/dist/esm/fieldTypes/file.d.ts +3 -3
- package/dist/esm/fieldTypes/file.js +3 -3
- package/dist/esm/fieldTypes/gallery.d.ts +5 -5
- package/dist/esm/fieldTypes/gallery.js +5 -5
- package/dist/esm/fieldTypes/rich_text.d.ts +8 -9
- package/dist/esm/fieldTypes/rich_text.js +9 -7
- package/dist/esm/fieldTypes/rich_text.js.map +1 -1
- package/dist/esm/fieldTypes/schema.d.ts +59 -0
- package/dist/esm/fieldTypes/schema.js +2 -0
- package/dist/esm/fieldTypes/schema.js.map +1 -0
- package/dist/esm/fieldTypes/single_block.d.ts +30 -15
- package/dist/esm/fieldTypes/single_block.js +8 -7
- package/dist/esm/fieldTypes/single_block.js.map +1 -1
- package/dist/esm/fieldTypes/structured_text.d.ts +14 -15
- package/dist/esm/fieldTypes/structured_text.js +8 -7
- package/dist/esm/fieldTypes/structured_text.js.map +1 -1
- package/dist/esm/generated/ApiTypes.d.ts +94 -980
- package/dist/esm/generated/Client.js +1 -1
- package/dist/esm/generated/RawApiTypes.d.ts +160 -999
- package/dist/esm/generated/resources/Field.d.ts +300 -300
- package/dist/esm/generated/resources/Item.d.ts +34 -34
- package/dist/esm/generated/resources/Item.js.map +1 -1
- package/dist/esm/generated/resources/ItemVersion.d.ts +3 -1
- package/dist/esm/generated/resources/ScheduledPublication.d.ts +3 -3
- package/dist/esm/generated/resources/ScheduledPublication.js.map +1 -1
- package/dist/esm/generated/resources/ScheduledUnpublishing.d.ts +3 -3
- package/dist/esm/generated/resources/ScheduledUnpublishing.js.map +1 -1
- package/dist/esm/generated/resources/Upload.d.ts +6 -6
- package/dist/esm/generated/resources/Upload.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/utilities/buildBlockRecord.d.ts +11 -5
- package/dist/esm/utilities/buildBlockRecord.js +0 -44
- package/dist/esm/utilities/buildBlockRecord.js.map +1 -1
- package/dist/esm/utilities/duplicateBlockRecord.d.ts +6 -0
- package/dist/esm/utilities/duplicateBlockRecord.js +46 -0
- package/dist/esm/utilities/duplicateBlockRecord.js.map +1 -0
- package/dist/esm/utilities/inspectItem.d.ts +3 -3
- package/dist/esm/utilities/inspectItem.js +28 -21
- package/dist/esm/utilities/inspectItem.js.map +1 -1
- package/dist/esm/utilities/itemDefinition.d.ts +25 -27
- package/dist/esm/utilities/nonRecursiveBlocks.d.ts +10 -75
- package/dist/esm/utilities/nonRecursiveBlocks.js +1 -164
- package/dist/esm/utilities/nonRecursiveBlocks.js.map +1 -1
- package/dist/esm/utilities/recursiveBlocks.d.ts +53 -23
- package/dist/esm/utilities/recursiveBlocks.js +52 -112
- package/dist/esm/utilities/recursiveBlocks.js.map +1 -1
- package/dist/types/fieldTypes/file.d.ts +3 -3
- package/dist/types/fieldTypes/gallery.d.ts +5 -5
- package/dist/types/fieldTypes/rich_text.d.ts +8 -9
- package/dist/types/fieldTypes/schema.d.ts +59 -0
- package/dist/types/fieldTypes/single_block.d.ts +30 -15
- package/dist/types/fieldTypes/structured_text.d.ts +14 -15
- package/dist/types/generated/ApiTypes.d.ts +94 -980
- package/dist/types/generated/RawApiTypes.d.ts +160 -999
- package/dist/types/generated/resources/Field.d.ts +300 -300
- package/dist/types/generated/resources/Item.d.ts +34 -34
- package/dist/types/generated/resources/ItemVersion.d.ts +3 -1
- package/dist/types/generated/resources/ScheduledPublication.d.ts +3 -3
- package/dist/types/generated/resources/ScheduledUnpublishing.d.ts +3 -3
- package/dist/types/generated/resources/Upload.d.ts +6 -6
- package/dist/types/index.d.ts +1 -0
- package/dist/types/utilities/buildBlockRecord.d.ts +11 -5
- package/dist/types/utilities/duplicateBlockRecord.d.ts +6 -0
- package/dist/types/utilities/inspectItem.d.ts +3 -3
- package/dist/types/utilities/itemDefinition.d.ts +25 -27
- package/dist/types/utilities/nonRecursiveBlocks.d.ts +10 -75
- package/dist/types/utilities/recursiveBlocks.d.ts +53 -23
- package/package.json +4 -4
- package/src/fieldTypes/file.ts +6 -6
- package/src/fieldTypes/gallery.ts +10 -10
- package/src/fieldTypes/rich_text.ts +26 -24
- package/src/fieldTypes/schema.ts +657 -0
- package/src/fieldTypes/single_block.ts +61 -38
- package/src/fieldTypes/structured_text.ts +57 -51
- package/src/generated/ApiTypes.ts +221 -1880
- package/src/generated/Client.ts +1 -1
- package/src/generated/RawApiTypes.ts +276 -2113
- package/src/generated/resources/Item.ts +93 -187
- package/src/generated/resources/ScheduledPublication.ts +4 -15
- package/src/generated/resources/ScheduledUnpublishing.ts +4 -15
- package/src/generated/resources/Upload.ts +9 -32
- package/src/index.ts +1 -0
- package/src/utilities/buildBlockRecord.ts +16 -56
- package/src/utilities/duplicateBlockRecord.ts +53 -0
- package/src/utilities/inspectItem.ts +64 -52
- package/src/utilities/itemDefinition.ts +109 -98
- package/src/utilities/nonRecursiveBlocks.ts +25 -279
- package/src/utilities/recursiveBlocks.ts +337 -72
package/README.md
CHANGED
|
@@ -1,20 +1,195 @@
|
|
|
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
|
+
|
|
19
|
+
**Example: `lat_lon` Field Type**
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { LatLonFieldValue, isLatLonFieldValue, isLocalizedLatLonFieldValue } from '@datocms/cma-client';
|
|
23
|
+
import type { LatLonFieldValidators, LatLonFieldAppearance } from '@datocms/cma-client';
|
|
24
|
+
|
|
25
|
+
// Field value type - can be boolean or null
|
|
26
|
+
const value: LatLonFieldValue = true;
|
|
27
|
+
|
|
28
|
+
// Type guard functions for validation
|
|
29
|
+
if (isLatLonFieldValue(someValue)) {
|
|
30
|
+
// someValue is guaranteed to be boolean | null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (isLocalizedLatLonFieldValue(localizedValue)) {
|
|
34
|
+
// localizedValue is a localized boolean field
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Validator and appearance types available for type-safe configuration
|
|
38
|
+
type Validators = LatLonFieldValidators;
|
|
39
|
+
type Appearance = LatLonFieldAppearance;
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Context-Dependent field types
|
|
43
|
+
|
|
44
|
+
Some field types have different value formats depending on the API context (request vs response) or query parameters:
|
|
45
|
+
|
|
46
|
+
#### Request vs Response variations
|
|
47
|
+
|
|
48
|
+
**File and Gallery fields** have different type requirements for API requests versus responses:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import {
|
|
52
|
+
FileFieldValue,
|
|
53
|
+
FileFieldValueInRequest,
|
|
54
|
+
GalleryFieldValue,
|
|
55
|
+
GalleryFieldValueInRequest,
|
|
56
|
+
// Type guards for runtime validation
|
|
57
|
+
isFileFieldValue,
|
|
58
|
+
isFileFieldValueInRequest,
|
|
59
|
+
isGalleryFieldValue,
|
|
60
|
+
isGalleryFieldValueInRequest
|
|
61
|
+
} from '@datocms/cma-client';
|
|
62
|
+
|
|
63
|
+
// API Response format - all metadata fields present with defaults
|
|
64
|
+
const fileResponse: FileFieldValue = {
|
|
65
|
+
upload_id: "12345",
|
|
66
|
+
alt: null, // Always present (default: null)
|
|
67
|
+
title: null, // Always present (default: null)
|
|
68
|
+
custom_data: {}, // Always present (default: {})
|
|
69
|
+
focal_point: null // Always present (default: null)
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// API Request format - metadata fields are optional
|
|
73
|
+
const fileRequest: FileFieldValueInRequest = {
|
|
74
|
+
upload_id: "12345"
|
|
75
|
+
// alt, title, custom_data, focal_point are optional
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Runtime validation for different contexts
|
|
79
|
+
if (isFileFieldValueInRequest(someFileValue)) {
|
|
80
|
+
// someFileValue has optional metadata fields
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (isGalleryFieldValue(someGalleryValue)) {
|
|
84
|
+
// someGalleryValue is array of files with all metadata present
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### "Nested Mode" Response variations
|
|
89
|
+
|
|
90
|
+
**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:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import {
|
|
94
|
+
StructuredTextFieldValue,
|
|
95
|
+
StructuredTextFieldValueInRequest,
|
|
96
|
+
StructuredTextFieldValueInNestedResponse,
|
|
97
|
+
// Type guards for all variations (also available for single_block and rich_text)
|
|
98
|
+
isStructuredTextFieldValue,
|
|
99
|
+
isStructuredTextFieldValueInRequest,
|
|
100
|
+
isStructuredTextFieldValueInNestedResponse
|
|
101
|
+
} from '@datocms/cma-client';
|
|
102
|
+
|
|
103
|
+
// Regular response - blocks as string IDs
|
|
104
|
+
const standard: StructuredTextFieldValue = {
|
|
105
|
+
document: {
|
|
106
|
+
type: "root",
|
|
107
|
+
children: [
|
|
108
|
+
{
|
|
109
|
+
type: "block",
|
|
110
|
+
// String ID reference
|
|
111
|
+
item: "IdMLV2GJTXyQ0Bfns7R4IQ"
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// Nested Mode response (?nested=true) - blocks as full objects
|
|
118
|
+
const nested: StructuredTextFieldValueInNestedResponse = {
|
|
119
|
+
document: {
|
|
120
|
+
type: "root",
|
|
121
|
+
children: [
|
|
122
|
+
{
|
|
123
|
+
type: "block",
|
|
124
|
+
// Always full block object
|
|
125
|
+
item: {
|
|
126
|
+
id: "IdMLV2GJTXyQ0Bfns7R4IQ",
|
|
127
|
+
type: "item",
|
|
128
|
+
attributes: { /* ... */ },
|
|
129
|
+
relationships: { /* ... */ }
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// Request format - flexible block representation
|
|
137
|
+
const request: StructuredTextFieldValueInRequest = {
|
|
138
|
+
document: {
|
|
139
|
+
type: "root",
|
|
140
|
+
children: [
|
|
141
|
+
{
|
|
142
|
+
type: "block",
|
|
143
|
+
// Can be string ID, to keep block unchanged...
|
|
144
|
+
item: "FicV5CxCSQ6yOrgfwRoiKA"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
type: "block",
|
|
148
|
+
// ...or full block object (to create new blocks or update existing ones)
|
|
149
|
+
item: {
|
|
150
|
+
type: "item",
|
|
151
|
+
attributes: { /* ... */ },
|
|
152
|
+
relationships: { /* ... */ }
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Runtime validation for different contexts
|
|
160
|
+
if (isStructuredTextFieldValueInNestedResponse(someStructuredText)) {
|
|
161
|
+
// someStructuredText has blocks as full objects
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (isStructuredTextFieldValueInRequest(requestData)) {
|
|
165
|
+
// requestData allows flexible block representations
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
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.).
|
|
170
|
+
|
|
171
|
+
**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:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import type { MyArticle, MyArticleSection } from './schema';
|
|
175
|
+
|
|
176
|
+
// Fully typed structured text with specific block types
|
|
177
|
+
const content: StructuredTextFieldValueInRequest<MyArticleSection> = {
|
|
178
|
+
document: {
|
|
179
|
+
type: "root",
|
|
180
|
+
children: [/* ... */]
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// Type guard with generic for precise validation
|
|
185
|
+
if (isStructuredTextFieldValueInNestedResponse<MyArticleSection>(value)) {
|
|
186
|
+
// value is now typed with your specific block schema
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Block Processing Utilities
|
|
191
|
+
|
|
192
|
+
### Inspecting Records and Blocks
|
|
18
193
|
|
|
19
194
|
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.
|
|
20
195
|
|
|
@@ -59,13 +234,49 @@ console.log(inspectItem(record));
|
|
|
59
234
|
```
|
|
60
235
|
</details>
|
|
61
236
|
|
|
62
|
-
###
|
|
237
|
+
### Creating and Duplicating Blocks
|
|
63
238
|
|
|
64
|
-
|
|
239
|
+
<details>
|
|
240
|
+
<summary><strong>buildBlockRecord()</strong> - Create block records from data</summary>
|
|
65
241
|
|
|
66
|
-
|
|
242
|
+
Converts a block data object into the proper format for API requests.
|
|
67
243
|
|
|
68
|
-
|
|
244
|
+
**TypeScript Signature:**
|
|
245
|
+
```typescript
|
|
246
|
+
function buildBlockRecord<D extends ItemTypeDefinition>(
|
|
247
|
+
body: ItemUpdateSchema<ToItemDefinitionInRequest<D>>
|
|
248
|
+
): NewBlockInRequest<ToItemDefinitionInRequest<D>>
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**Parameters:**
|
|
252
|
+
- `body`: Block data in update schema format
|
|
253
|
+
|
|
254
|
+
**Returns:** Formatted block record ready for API requests
|
|
255
|
+
</details>
|
|
256
|
+
|
|
257
|
+
<details>
|
|
258
|
+
<summary><strong>duplicateBlockRecord()</strong> - Deep clone blocks with nested content</summary>
|
|
259
|
+
|
|
260
|
+
Creates a deep copy of a block record, including all nested blocks, removing IDs to create new instances.
|
|
261
|
+
|
|
262
|
+
**TypeScript Signature:**
|
|
263
|
+
```typescript
|
|
264
|
+
async function duplicateBlockRecord<D extends ItemTypeDefinition>(
|
|
265
|
+
existingBlock: ItemWithOptionalIdAndMeta<ToItemDefinitionInNestedResponse<D>>,
|
|
266
|
+
schemaRepository: SchemaRepository
|
|
267
|
+
): Promise<NewBlockInRequest<ToItemDefinitionInRequest<D>>>
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
**Parameters:**
|
|
271
|
+
- `existingBlock`: The block to duplicate
|
|
272
|
+
- `schemaRepository`: Repository for schema lookups
|
|
273
|
+
|
|
274
|
+
**Returns:** New block record without IDs, ready to be created
|
|
275
|
+
</details>
|
|
276
|
+
|
|
277
|
+
### Recursive Block Operations
|
|
278
|
+
|
|
279
|
+
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.
|
|
69
280
|
|
|
70
281
|
<details>
|
|
71
282
|
<summary><strong>visitBlocksInNonLocalizedFieldValue()</strong> - Recursively visit all blocks</summary>
|
|
@@ -75,21 +286,18 @@ Visit every block in a non-localized field value recursively, including blocks n
|
|
|
75
286
|
**TypeScript Signature:**
|
|
76
287
|
```typescript
|
|
77
288
|
async function visitBlocksInNonLocalizedFieldValue(
|
|
78
|
-
schemaRepository: SchemaRepository,
|
|
79
|
-
fieldType: string,
|
|
80
289
|
nonLocalizedFieldValue: unknown,
|
|
81
|
-
|
|
82
|
-
|
|
290
|
+
fieldType: string,
|
|
291
|
+
schemaRepository: SchemaRepository,
|
|
292
|
+
visitor: (item: BlockInRequest, path: TreePath) => void | Promise<void>,
|
|
83
293
|
): Promise<void>
|
|
84
294
|
```
|
|
85
295
|
|
|
86
296
|
**Parameters:**
|
|
87
|
-
- `schemaRepository`: Repository for caching schema lookups
|
|
88
|
-
- `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
89
297
|
- `nonLocalizedFieldValue`: The non-localized field value
|
|
298
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
299
|
+
- `schemaRepository`: Repository for caching schema lookups
|
|
90
300
|
- `visitor`: Function called for each block (including nested)
|
|
91
|
-
- `path`: Optional base path for tracking location
|
|
92
|
-
```
|
|
93
301
|
</details>
|
|
94
302
|
|
|
95
303
|
<details>
|
|
@@ -100,20 +308,18 @@ Transform all blocks in a non-localized field value recursively, including neste
|
|
|
100
308
|
**TypeScript Signature:**
|
|
101
309
|
```typescript
|
|
102
310
|
async function mapBlocksInNonLocalizedFieldValue(
|
|
103
|
-
schemaRepository: SchemaRepository,
|
|
104
|
-
fieldType: string,
|
|
105
311
|
nonLocalizedFieldValue: unknown,
|
|
106
|
-
|
|
107
|
-
|
|
312
|
+
fieldType: string,
|
|
313
|
+
schemaRepository: SchemaRepository,
|
|
314
|
+
mapper: (item: BlockInRequest, path: TreePath) => BlockInRequest | Promise<BlockInRequest>,
|
|
108
315
|
): Promise<unknown>
|
|
109
316
|
```
|
|
110
317
|
|
|
111
318
|
**Parameters:**
|
|
112
|
-
- `schemaRepository`: Repository for caching schema lookups
|
|
113
|
-
- `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
114
319
|
- `nonLocalizedFieldValue`: The non-localized field value
|
|
320
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
321
|
+
- `schemaRepository`: Repository for caching schema lookups
|
|
115
322
|
- `mapper`: Function that transforms each block
|
|
116
|
-
- `path`: Optional base path
|
|
117
323
|
|
|
118
324
|
**Returns:** New field value
|
|
119
325
|
</details>
|
|
@@ -126,20 +332,18 @@ Filter blocks recursively, removing blocks at any nesting level that don't match
|
|
|
126
332
|
**TypeScript Signature:**
|
|
127
333
|
```typescript
|
|
128
334
|
async function filterBlocksInNonLocalizedFieldValue(
|
|
129
|
-
schemaRepository: SchemaRepository,
|
|
130
|
-
fieldType: string,
|
|
131
335
|
nonLocalizedFieldValue: unknown,
|
|
132
|
-
|
|
133
|
-
|
|
336
|
+
fieldType: string,
|
|
337
|
+
schemaRepository: SchemaRepository,
|
|
338
|
+
predicate: (item: BlockInRequest, path: TreePath) => boolean | Promise<boolean>,
|
|
134
339
|
): Promise<unknown>
|
|
135
340
|
```
|
|
136
341
|
|
|
137
342
|
**Parameters:**
|
|
138
|
-
- `schemaRepository`: Repository for caching schema lookups
|
|
139
|
-
- `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
140
343
|
- `nonLocalizedFieldValue`: The non-localized field value to filter
|
|
344
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
345
|
+
- `schemaRepository`: Repository for caching schema lookups
|
|
141
346
|
- `predicate`: Function that tests each block
|
|
142
|
-
- `path`: Optional base path
|
|
143
347
|
|
|
144
348
|
**Returns:** New field value with filtered blocks
|
|
145
349
|
|
|
@@ -163,20 +367,18 @@ Find all blocks that match the predicate, searching recursively through nested b
|
|
|
163
367
|
**TypeScript Signature:**
|
|
164
368
|
```typescript
|
|
165
369
|
async function findAllBlocksInNonLocalizedFieldValue(
|
|
166
|
-
schemaRepository: SchemaRepository,
|
|
167
|
-
fieldType: string,
|
|
168
370
|
nonLocalizedFieldValue: unknown,
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
371
|
+
fieldType: string,
|
|
372
|
+
schemaRepository: SchemaRepository,
|
|
373
|
+
predicate: (item: BlockInRequest, path: TreePath) => boolean | Promise<boolean>,
|
|
374
|
+
): Promise<Array<{ item: BlockInRequest; path: TreePath }>>
|
|
172
375
|
```
|
|
173
376
|
|
|
174
377
|
**Parameters:**
|
|
175
|
-
- `schemaRepository`: Repository for caching schema lookups
|
|
176
|
-
- `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
177
378
|
- `nonLocalizedFieldValue`: The non-localized field value to search
|
|
379
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
380
|
+
- `schemaRepository`: Repository for caching schema lookups
|
|
178
381
|
- `predicate`: Function that tests each block
|
|
179
|
-
- `path`: Optional base path
|
|
180
382
|
|
|
181
383
|
**Returns:** Array of all matching blocks with their paths
|
|
182
384
|
</details>
|
|
@@ -189,25 +391,22 @@ Reduce all blocks recursively to a single value.
|
|
|
189
391
|
**TypeScript Signature:**
|
|
190
392
|
```typescript
|
|
191
393
|
async function reduceBlocksInNonLocalizedFieldValue<R>(
|
|
192
|
-
schemaRepository: SchemaRepository,
|
|
193
|
-
fieldType: string,
|
|
194
394
|
nonLocalizedFieldValue: unknown,
|
|
195
|
-
|
|
395
|
+
fieldType: string,
|
|
396
|
+
schemaRepository: SchemaRepository,
|
|
397
|
+
reducer: (accumulator: R, item: BlockInRequest, path: TreePath) => R | Promise<R>,
|
|
196
398
|
initialValue: R,
|
|
197
|
-
path?: TreePath
|
|
198
399
|
): Promise<R>
|
|
199
400
|
```
|
|
200
401
|
|
|
201
402
|
**Parameters:**
|
|
202
|
-
- `schemaRepository`: Repository for caching schema lookups
|
|
203
|
-
- `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
204
403
|
- `nonLocalizedFieldValue`: The non-localized field value to reduce
|
|
404
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
405
|
+
- `schemaRepository`: Repository for caching schema lookups
|
|
205
406
|
- `reducer`: Function that processes each block
|
|
206
407
|
- `initialValue`: Initial accumulator value
|
|
207
|
-
- `path`: Optional base path
|
|
208
408
|
|
|
209
409
|
**Returns:** The final accumulated value
|
|
210
|
-
```
|
|
211
410
|
</details>
|
|
212
411
|
|
|
213
412
|
<details>
|
|
@@ -218,23 +417,20 @@ Check if any block (including nested) matches the predicate.
|
|
|
218
417
|
**TypeScript Signature:**
|
|
219
418
|
```typescript
|
|
220
419
|
async function someBlocksInNonLocalizedFieldValue(
|
|
221
|
-
schemaRepository: SchemaRepository,
|
|
222
|
-
fieldType: string,
|
|
223
420
|
nonLocalizedFieldValue: unknown,
|
|
224
|
-
|
|
225
|
-
|
|
421
|
+
fieldType: string,
|
|
422
|
+
schemaRepository: SchemaRepository,
|
|
423
|
+
predicate: (item: BlockInRequest, path: TreePath) => boolean | Promise<boolean>,
|
|
226
424
|
): Promise<boolean>
|
|
227
425
|
```
|
|
228
426
|
|
|
229
427
|
**Parameters:**
|
|
230
|
-
- `schemaRepository`: Repository for caching schema lookups
|
|
231
|
-
- `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
232
428
|
- `nonLocalizedFieldValue`: The non-localized field value to test
|
|
429
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
430
|
+
- `schemaRepository`: Repository for caching schema lookups
|
|
233
431
|
- `predicate`: Function that tests each block
|
|
234
|
-
- `path`: Optional base path
|
|
235
432
|
|
|
236
433
|
**Returns:** True if any block matches
|
|
237
|
-
```
|
|
238
434
|
</details>
|
|
239
435
|
|
|
240
436
|
<details>
|
|
@@ -245,84 +441,26 @@ Check if every block (including nested) matches the predicate.
|
|
|
245
441
|
**TypeScript Signature:**
|
|
246
442
|
```typescript
|
|
247
443
|
async function everyBlockInNonLocalizedFieldValue(
|
|
248
|
-
schemaRepository: SchemaRepository,
|
|
249
|
-
fieldType: string,
|
|
250
444
|
nonLocalizedFieldValue: unknown,
|
|
251
|
-
|
|
252
|
-
|
|
445
|
+
fieldType: string,
|
|
446
|
+
schemaRepository: SchemaRepository,
|
|
447
|
+
predicate: (item: BlockInRequest, path: TreePath) => boolean | Promise<boolean>,
|
|
253
448
|
): Promise<boolean>
|
|
254
449
|
```
|
|
255
450
|
|
|
256
451
|
**Parameters:**
|
|
257
|
-
- `schemaRepository`: Repository for caching schema lookups
|
|
258
|
-
- `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
259
452
|
- `nonLocalizedFieldValue`: The non-localized field value to test
|
|
453
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
454
|
+
- `schemaRepository`: Repository for caching schema lookups
|
|
260
455
|
- `predicate`: Function that tests each block
|
|
261
|
-
- `path`: Optional base path
|
|
262
456
|
|
|
263
457
|
**Returns:** True if all blocks match
|
|
264
458
|
</details>
|
|
265
459
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
<details>
|
|
269
|
-
<summary><strong>buildBlockRecord()</strong> - Create block records from data</summary>
|
|
270
|
-
|
|
271
|
-
Converts a block data object into the proper format for API requests.
|
|
272
|
-
|
|
273
|
-
**TypeScript Signature:**
|
|
274
|
-
```typescript
|
|
275
|
-
function buildBlockRecord<D extends ItemTypeDefinition>(
|
|
276
|
-
body: ItemUpdateSchema<ToItemDefinitionAsRequest<D>>
|
|
277
|
-
): NewBlockInARequest<ToItemDefinitionAsRequest<D>>
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
**Parameters:**
|
|
281
|
-
- `body`: Block data in update schema format
|
|
282
|
-
|
|
283
|
-
**Returns:** Formatted block record ready for API requests
|
|
284
|
-
</details>
|
|
285
|
-
|
|
286
|
-
<details>
|
|
287
|
-
<summary><strong>duplicateBlockRecord()</strong> - Deep clone blocks with nested content</summary>
|
|
288
|
-
|
|
289
|
-
Creates a deep copy of a block record, including all nested blocks, removing IDs to create new instances.
|
|
290
|
-
|
|
291
|
-
**TypeScript Signature:**
|
|
292
|
-
```typescript
|
|
293
|
-
async function duplicateBlockRecord<D extends ItemTypeDefinition>(
|
|
294
|
-
existingBlock: ItemWithOptionalIdAndMeta<ToItemDefinitionWithNestedBlocks<D>>,
|
|
295
|
-
schemaRepository: SchemaRepository
|
|
296
|
-
): Promise<NewBlockInARequest<ToItemDefinitionAsRequest<D>>>
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
**Parameters:**
|
|
300
|
-
- `existingBlock`: The block to duplicate
|
|
301
|
-
- `schemaRepository`: Repository for schema lookups
|
|
302
|
-
|
|
303
|
-
**Returns:** New block record without IDs, ready to be created
|
|
304
|
-
</details>
|
|
305
|
-
|
|
306
|
-
### 3. Localization-Aware Field Utilities
|
|
460
|
+
## Unified Field Processing (Localized & Non-Localized)
|
|
307
461
|
|
|
308
462
|
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.
|
|
309
463
|
|
|
310
|
-
<details>
|
|
311
|
-
<summary><strong>isLocalized()</strong> - Check if a field is localized</summary>
|
|
312
|
-
|
|
313
|
-
Determines whether a DatoCMS field is configured for localization.
|
|
314
|
-
|
|
315
|
-
**TypeScript Signature:**
|
|
316
|
-
```typescript
|
|
317
|
-
function isLocalized(field: Field): boolean
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
**Parameters:**
|
|
321
|
-
- `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
322
|
-
|
|
323
|
-
**Returns:** True if the field is localized, false otherwise
|
|
324
|
-
</details>
|
|
325
|
-
|
|
326
464
|
<details>
|
|
327
465
|
<summary><strong>mapNormalizedFieldValues() / mapNormalizedFieldValuesAsync()</strong> - Transform field values</summary>
|
|
328
466
|
|
|
@@ -344,7 +482,7 @@ async function mapNormalizedFieldValuesAsync<TInput, TOutput>(
|
|
|
344
482
|
```
|
|
345
483
|
|
|
346
484
|
**Parameters:**
|
|
347
|
-
- `fieldType`: The
|
|
485
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
348
486
|
- `nonLocalizedFieldValue`: The non-localized field value (localized or non-localized)
|
|
349
487
|
- `mapFn`: Function to transform each value (receives locale for localized fields, undefined for non-localized)
|
|
350
488
|
|
|
@@ -372,7 +510,7 @@ async function filterNormalizedFieldValuesAsync<T>(
|
|
|
372
510
|
```
|
|
373
511
|
|
|
374
512
|
**Parameters:**
|
|
375
|
-
- `fieldType`: The
|
|
513
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
376
514
|
- `nonLocalizedFieldValue`: The non-localized field value to filter
|
|
377
515
|
- `filterFn`: Predicate function for filtering
|
|
378
516
|
|
|
@@ -400,7 +538,7 @@ async function visitNormalizedFieldValuesAsync<T>(
|
|
|
400
538
|
```
|
|
401
539
|
|
|
402
540
|
**Parameters:**
|
|
403
|
-
- `fieldType`: The
|
|
541
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
404
542
|
- `nonLocalizedFieldValue`: The non-localized field value to visit
|
|
405
543
|
- `visitFn`: Function called for each value
|
|
406
544
|
</details>
|
|
@@ -426,7 +564,7 @@ async function someNormalizedFieldValuesAsync<T>(
|
|
|
426
564
|
```
|
|
427
565
|
|
|
428
566
|
**Parameters:**
|
|
429
|
-
- `fieldType`: The
|
|
567
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
430
568
|
- `nonLocalizedFieldValue`: The non-localized field value to test
|
|
431
569
|
- `testFn`: Predicate function
|
|
432
570
|
|
|
@@ -454,7 +592,7 @@ async function everyNormalizedFieldValueAsync<T>(
|
|
|
454
592
|
```
|
|
455
593
|
|
|
456
594
|
**Parameters:**
|
|
457
|
-
- `fieldType`: The
|
|
595
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
458
596
|
- `nonLocalizedFieldValue`: The non-localized field value to test
|
|
459
597
|
- `testFn`: Predicate function
|
|
460
598
|
|
|
@@ -485,7 +623,7 @@ type NormalizedFieldValueEntry<T> = {
|
|
|
485
623
|
```
|
|
486
624
|
|
|
487
625
|
**Parameters:**
|
|
488
|
-
- `fieldType`: The
|
|
626
|
+
- `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
|
|
489
627
|
- `nonLocalizedFieldValue`/`entries non-localized`: Value to convert from/to
|
|
490
628
|
|
|
491
629
|
**Returns:** Normalized entries array or reconstructed field value
|
|
@@ -503,25 +641,57 @@ const processed = entries.map(({ locale, value }) => ({
|
|
|
503
641
|
|
|
504
642
|
// Convert back to field value format
|
|
505
643
|
const result = fromNormalizedFieldValueEntries(field, processed);
|
|
506
|
-
```
|
|
507
644
|
</details>
|
|
508
645
|
|
|
509
|
-
### 4.
|
|
646
|
+
### 4. SchemaRepository
|
|
510
647
|
|
|
511
|
-
The `SchemaRepository` class provides
|
|
648
|
+
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.
|
|
512
649
|
|
|
513
|
-
|
|
514
|
-
|
|
650
|
+
**Why use it?**
|
|
651
|
+
|
|
652
|
+
- **Cache once, reuse everywhere**: The first API call stores results in memory; all subsequent lookups are instant.
|
|
653
|
+
- **Efficient schema access**: Retrieve entities by ID, API key, or package name without re-fetching.
|
|
654
|
+
- **Optimized for block processing**: Essential for utilities like `mapBlocksInNonLocalizedFieldValue`.
|
|
655
|
+
- **Fewer API calls**: Dramatically speeds up bulk operations and complex traversals.
|
|
656
|
+
|
|
657
|
+
**Usage Example:**
|
|
658
|
+
```typescript
|
|
659
|
+
const schemaRepository = new SchemaRepository(client);
|
|
660
|
+
|
|
661
|
+
// First call: fetches from API and caches result
|
|
662
|
+
const blogPost = await schemaRepository.getItemTypeByApiKey('blog_post');
|
|
663
|
+
const fields = await schemaRepository.getItemTypeFields(blogPost);
|
|
664
|
+
|
|
665
|
+
// Next calls: resolved instantly from cache (no API calls)
|
|
666
|
+
const sameBlogPost = await schemaRepository.getItemTypeByApiKey('blog_post');
|
|
667
|
+
const sameFields = await schemaRepository.getItemTypeFields(blogPost);
|
|
668
|
+
|
|
669
|
+
// Works seamlessly with block-processing utilities
|
|
670
|
+
await mapBlocksInNonLocalizedFieldValue(
|
|
671
|
+
fieldValue,
|
|
672
|
+
field,
|
|
673
|
+
schemaRepository, // share cached lookups
|
|
674
|
+
async (block) => {
|
|
675
|
+
// transform block here
|
|
676
|
+
}
|
|
677
|
+
);
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
**When to Use**
|
|
515
681
|
|
|
516
|
-
|
|
682
|
+
* Traversing relationships that repeatedly query schema
|
|
683
|
+
* Bulk record processing scripts
|
|
684
|
+
* Block-processing utilities that need frequent lookups
|
|
685
|
+
* Any script where reducing API calls matters
|
|
517
686
|
|
|
518
|
-
**
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
-
|
|
522
|
-
|
|
687
|
+
**When Not to Use**
|
|
688
|
+
|
|
689
|
+
* Scripts that modify schema (models, fields, etc.)
|
|
690
|
+
* Long-running applications (cache never expires)
|
|
691
|
+
* Situations where the schema might change during execution
|
|
692
|
+
|
|
693
|
+
<details><summary><strong>Class signature</strong></summary>
|
|
523
694
|
|
|
524
|
-
**TypeScript Class:**
|
|
525
695
|
```typescript
|
|
526
696
|
class SchemaRepository {
|
|
527
697
|
constructor(client: GenericClient)
|
|
@@ -548,41 +718,6 @@ class SchemaRepository {
|
|
|
548
718
|
// ... and more raw variants
|
|
549
719
|
}
|
|
550
720
|
```
|
|
551
|
-
|
|
552
|
-
**When to Use:**
|
|
553
|
-
- Complex traversal operations that repeatedly lookup schema
|
|
554
|
-
- Bulk operations processing multiple records
|
|
555
|
-
- Scripts that need efficient access to schema information
|
|
556
|
-
- Working with recursive block utilities
|
|
557
|
-
|
|
558
|
-
**When NOT to Use:**
|
|
559
|
-
- Scripts that modify schema (models, fields, etc.)
|
|
560
|
-
- Long-running applications (no cache expiration)
|
|
561
|
-
- When schema might change during execution
|
|
562
|
-
|
|
563
|
-
**Usage Example:**
|
|
564
|
-
```typescript
|
|
565
|
-
const schemaRepository = new SchemaRepository(client);
|
|
566
|
-
|
|
567
|
-
// First call fetches from API and caches
|
|
568
|
-
const blogPost = await schemaRepository.getItemTypeByApiKey('blog_post');
|
|
569
|
-
const fields = await schemaRepository.getItemTypeFields(blogPost);
|
|
570
|
-
|
|
571
|
-
// Subsequent calls use cached data (no API calls)
|
|
572
|
-
const sameBlogPost = await schemaRepository.getItemTypeByApiKey('blog_post');
|
|
573
|
-
const sameFields = await schemaRepository.getItemTypeFields(blogPost);
|
|
574
|
-
|
|
575
|
-
// Use with recursive utilities for optimal performance
|
|
576
|
-
await mapBlocksInNonLocalizedFieldValue(
|
|
577
|
-
schemaRepository, // Pass repository for efficient lookups
|
|
578
|
-
field,
|
|
579
|
-
fieldValue,
|
|
580
|
-
async (block) => { /* transform */ }
|
|
581
|
-
);
|
|
582
|
-
```
|
|
583
|
-
|
|
584
|
-
**Performance Impact:**
|
|
585
|
-
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.
|
|
586
721
|
</details>
|
|
587
722
|
|
|
588
723
|
## Contributing
|