@storyblok/migrations 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +8 -0
- package/README.md +73 -0
- package/dist/index.cjs +445 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +203 -0
- package/dist/index.d.mts +203 -0
- package/dist/index.mjs +420 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +71 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { extname, join } from "pathe";
|
|
3
|
+
import { htmlToStoryblokRichtext } from "@storyblok/richtext/html-parser";
|
|
4
|
+
import { markdownToStoryblokRichtext } from "@storyblok/richtext/markdown-parser";
|
|
5
|
+
|
|
6
|
+
//#region src/delete-out-of-schema-fields.ts
|
|
7
|
+
const SYSTEM_FIELDS = new Set([
|
|
8
|
+
"_uid",
|
|
9
|
+
"component",
|
|
10
|
+
"_editable"
|
|
11
|
+
]);
|
|
12
|
+
function cleanBlok(blok, schemaDefinition, removedFields) {
|
|
13
|
+
const componentName = blok.component;
|
|
14
|
+
if (!componentName) return blok;
|
|
15
|
+
const schema = schemaDefinition[componentName];
|
|
16
|
+
if (!schema) return blok;
|
|
17
|
+
const validFieldSet = new Set(Object.keys(schema));
|
|
18
|
+
const result = {};
|
|
19
|
+
for (const [key, value] of Object.entries(blok)) {
|
|
20
|
+
if (SYSTEM_FIELDS.has(key)) {
|
|
21
|
+
result[key] = value;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const baseFieldName = key.replace(/__i18n__.*/, "");
|
|
25
|
+
if (!validFieldSet.has(baseFieldName)) {
|
|
26
|
+
removedFields.push({
|
|
27
|
+
component: componentName,
|
|
28
|
+
field: key
|
|
29
|
+
});
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (Array.isArray(value) && value.some((item) => item && typeof item === "object" && !Array.isArray(item) && item.component)) result[key] = value.map((item) => {
|
|
33
|
+
if (item && typeof item === "object" && !Array.isArray(item) && item.component) return cleanBlok(item, schemaDefinition, removedFields);
|
|
34
|
+
return item;
|
|
35
|
+
});
|
|
36
|
+
else result[key] = value;
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
function deleteOutOfSchemaFields(story, schemaDefinition) {
|
|
41
|
+
const removedFields = [];
|
|
42
|
+
if (!story.content) return {
|
|
43
|
+
story,
|
|
44
|
+
removedFields
|
|
45
|
+
};
|
|
46
|
+
const newContent = cleanBlok(story.content, schemaDefinition, removedFields);
|
|
47
|
+
return {
|
|
48
|
+
story: {
|
|
49
|
+
...story,
|
|
50
|
+
content: newContent
|
|
51
|
+
},
|
|
52
|
+
removedFields
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/local-utils.ts
|
|
58
|
+
async function readLocalJsonFiles(dir) {
|
|
59
|
+
let files;
|
|
60
|
+
try {
|
|
61
|
+
files = await readdir(dir);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
if (error.code === "ENOENT") return [];
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
const jsonFiles = files.filter((f) => extname(f) === ".json");
|
|
67
|
+
return await Promise.all(jsonFiles.map(async (file) => {
|
|
68
|
+
const filePath = join(dir, file);
|
|
69
|
+
const content = await readFile(filePath, "utf8");
|
|
70
|
+
try {
|
|
71
|
+
return JSON.parse(content);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
throw new Error(`Failed to parse ${filePath}: ${error.message}`);
|
|
74
|
+
}
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
async function writeLocalJsonFile(dir, filename, data) {
|
|
78
|
+
await mkdir(dir, { recursive: true });
|
|
79
|
+
await writeFile(join(dir, filename), JSON.stringify(data, void 0, 2), "utf8");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/local-assets.ts
|
|
84
|
+
function getAssetFilename(asset) {
|
|
85
|
+
return `${(asset.short_filename || String(asset.id)).replace(/\.[^.]+$/, "")}_${asset.id}.json`;
|
|
86
|
+
}
|
|
87
|
+
async function getLocalAssets(dir) {
|
|
88
|
+
return readLocalJsonFiles(dir);
|
|
89
|
+
}
|
|
90
|
+
async function updateLocalAsset(dir, asset) {
|
|
91
|
+
await writeLocalJsonFile(dir, getAssetFilename(asset), asset);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
//#endregion
|
|
95
|
+
//#region src/local-components.ts
|
|
96
|
+
function getComponentFilename(component) {
|
|
97
|
+
return `${component.name}.json`;
|
|
98
|
+
}
|
|
99
|
+
async function getLocalComponents(dir) {
|
|
100
|
+
return readLocalJsonFiles(dir);
|
|
101
|
+
}
|
|
102
|
+
async function updateLocalComponent(dir, component) {
|
|
103
|
+
await writeLocalJsonFile(dir, getComponentFilename(component), component);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
//#endregion
|
|
107
|
+
//#region src/local-datasources.ts
|
|
108
|
+
function getDatasourceFilename(datasource) {
|
|
109
|
+
return `${datasource.slug}_${datasource.id}.json`;
|
|
110
|
+
}
|
|
111
|
+
async function getLocalDatasources(dir) {
|
|
112
|
+
return readLocalJsonFiles(dir);
|
|
113
|
+
}
|
|
114
|
+
async function updateLocalDatasource(dir, datasource) {
|
|
115
|
+
await writeLocalJsonFile(dir, getDatasourceFilename(datasource), datasource);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
//#endregion
|
|
119
|
+
//#region src/local-stories.ts
|
|
120
|
+
function getStoryFilename(story) {
|
|
121
|
+
return `${story.slug}_${story.uuid}.json`;
|
|
122
|
+
}
|
|
123
|
+
async function getLocalStories(dir) {
|
|
124
|
+
return readLocalJsonFiles(dir);
|
|
125
|
+
}
|
|
126
|
+
async function updateLocalStory(dir, story) {
|
|
127
|
+
await writeLocalJsonFile(dir, getStoryFilename(story), story);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
//#endregion
|
|
131
|
+
//#region src/map-refs.ts
|
|
132
|
+
function isRecord(value) {
|
|
133
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
134
|
+
}
|
|
135
|
+
function asRecord(value) {
|
|
136
|
+
return isRecord(value) ? value : {};
|
|
137
|
+
}
|
|
138
|
+
function asArray(value) {
|
|
139
|
+
return Array.isArray(value) ? value : [];
|
|
140
|
+
}
|
|
141
|
+
const traverseAndMapBySchema = (data, { schemas, maps, fieldRefMappers, processedFields, missingSchemas }) => {
|
|
142
|
+
if (!isRecord(data) || typeof data.component !== "string") return data ?? {};
|
|
143
|
+
const schema = schemas[data.component];
|
|
144
|
+
if (!schema) {
|
|
145
|
+
missingSchemas.add(data.component);
|
|
146
|
+
return data;
|
|
147
|
+
}
|
|
148
|
+
const dataNew = { ...data };
|
|
149
|
+
for (const [fieldName, fieldValue] of Object.entries(data)) {
|
|
150
|
+
const fieldSchema = schema[fieldName.replace(/__i18n__.*/, "")];
|
|
151
|
+
const fieldType = fieldSchema && typeof fieldSchema === "object" && "type" in fieldSchema && fieldSchema.type;
|
|
152
|
+
const fieldRefMapper = typeof fieldType === "string" && fieldRefMappers[fieldType];
|
|
153
|
+
if (fieldSchema) processedFields.add(fieldSchema);
|
|
154
|
+
if (fieldRefMapper) dataNew[fieldName] = fieldRefMapper(fieldValue, {
|
|
155
|
+
schema: fieldSchema,
|
|
156
|
+
schemas,
|
|
157
|
+
maps,
|
|
158
|
+
fieldRefMappers,
|
|
159
|
+
processedFields,
|
|
160
|
+
missingSchemas
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return dataNew;
|
|
164
|
+
};
|
|
165
|
+
const traverseAndMapRichtextDoc = (data, { schemas, maps, fieldRefMappers, processedFields, missingSchemas }) => {
|
|
166
|
+
if (Array.isArray(data)) return data.map((item) => traverseAndMapRichtextDoc(item, {
|
|
167
|
+
schemas,
|
|
168
|
+
maps,
|
|
169
|
+
fieldRefMappers,
|
|
170
|
+
processedFields,
|
|
171
|
+
missingSchemas
|
|
172
|
+
}));
|
|
173
|
+
if (isRecord(data)) {
|
|
174
|
+
if (data.type === "link" && asRecord(data.attrs).linktype === "story") return {
|
|
175
|
+
...data,
|
|
176
|
+
attrs: {
|
|
177
|
+
...asRecord(data.attrs),
|
|
178
|
+
uuid: maps.stories?.get(asRecord(data.attrs).uuid) ?? asRecord(data.attrs).uuid
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
if (data.type === "blok") return {
|
|
182
|
+
...data,
|
|
183
|
+
attrs: {
|
|
184
|
+
...asRecord(data.attrs),
|
|
185
|
+
body: asArray(asRecord(data.attrs).body).map((d) => traverseAndMapBySchema(d, {
|
|
186
|
+
schemas,
|
|
187
|
+
maps,
|
|
188
|
+
fieldRefMappers,
|
|
189
|
+
processedFields,
|
|
190
|
+
missingSchemas
|
|
191
|
+
}))
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
const newData = {};
|
|
195
|
+
for (const [k, value] of Object.entries(data)) newData[k] = traverseAndMapRichtextDoc(value, {
|
|
196
|
+
schemas,
|
|
197
|
+
maps,
|
|
198
|
+
fieldRefMappers,
|
|
199
|
+
processedFields,
|
|
200
|
+
missingSchemas
|
|
201
|
+
});
|
|
202
|
+
return newData;
|
|
203
|
+
}
|
|
204
|
+
return data;
|
|
205
|
+
};
|
|
206
|
+
const richtextFieldRefMapper = (data, { schemas, maps, fieldRefMappers, processedFields, missingSchemas }) => traverseAndMapRichtextDoc(data, {
|
|
207
|
+
schemas,
|
|
208
|
+
maps,
|
|
209
|
+
fieldRefMappers,
|
|
210
|
+
processedFields,
|
|
211
|
+
missingSchemas
|
|
212
|
+
});
|
|
213
|
+
const multilinkFieldRefMapper = (data, { maps }) => {
|
|
214
|
+
if (!isRecord(data) || data.linktype !== "story") return data;
|
|
215
|
+
return {
|
|
216
|
+
...data,
|
|
217
|
+
id: maps.stories?.get(data.id) ?? data.id
|
|
218
|
+
};
|
|
219
|
+
};
|
|
220
|
+
const bloksFieldRefMapper = (data, { schemas, maps, fieldRefMappers, processedFields, missingSchemas }) => {
|
|
221
|
+
if (!Array.isArray(data)) throw new TypeError(`Invalid bloks field: expected an array, but received ${JSON.stringify(data)}.`);
|
|
222
|
+
return data.map((d) => traverseAndMapBySchema(d, {
|
|
223
|
+
schemas,
|
|
224
|
+
maps,
|
|
225
|
+
fieldRefMappers,
|
|
226
|
+
processedFields,
|
|
227
|
+
missingSchemas
|
|
228
|
+
}));
|
|
229
|
+
};
|
|
230
|
+
const assetFieldRefMapper = (data, { maps }) => {
|
|
231
|
+
if (!isRecord(data)) return data;
|
|
232
|
+
const newId = typeof data.id === "number" ? maps.assets?.get(data.id) : void 0;
|
|
233
|
+
return newId === void 0 ? data : {
|
|
234
|
+
...data,
|
|
235
|
+
id: newId
|
|
236
|
+
};
|
|
237
|
+
};
|
|
238
|
+
const multiassetFieldRefMapper = (data, options) => {
|
|
239
|
+
if (!Array.isArray(data)) throw new TypeError(`Invalid multiasset field: expected an array, but received ${JSON.stringify(data)}.`);
|
|
240
|
+
return data.map((d) => assetFieldRefMapper(d, options));
|
|
241
|
+
};
|
|
242
|
+
const optionsFieldRefMapper = (data, { schema, maps }) => {
|
|
243
|
+
if (!Array.isArray(data)) return data;
|
|
244
|
+
const sourceMap = {
|
|
245
|
+
internal_stories: maps.stories,
|
|
246
|
+
internal_users: maps.users,
|
|
247
|
+
internal_tags: maps.tags,
|
|
248
|
+
internal_datasources: maps.datasources
|
|
249
|
+
}[schema.source ?? ""];
|
|
250
|
+
if (!sourceMap) return data;
|
|
251
|
+
return data.map((d) => sourceMap.get(d) ?? d);
|
|
252
|
+
};
|
|
253
|
+
const fieldRefMappers = {
|
|
254
|
+
asset: assetFieldRefMapper,
|
|
255
|
+
bloks: bloksFieldRefMapper,
|
|
256
|
+
multiasset: multiassetFieldRefMapper,
|
|
257
|
+
multilink: multilinkFieldRefMapper,
|
|
258
|
+
options: optionsFieldRefMapper,
|
|
259
|
+
richtext: richtextFieldRefMapper
|
|
260
|
+
};
|
|
261
|
+
function mapRefs(story, options) {
|
|
262
|
+
const { schemas, maps } = options;
|
|
263
|
+
const processedFields = /* @__PURE__ */ new Set();
|
|
264
|
+
const missingSchemas = /* @__PURE__ */ new Set();
|
|
265
|
+
const alternates = story.alternates ? story.alternates.map((alternate) => {
|
|
266
|
+
const mappedAlternate = asRecord(alternate);
|
|
267
|
+
return {
|
|
268
|
+
...mappedAlternate,
|
|
269
|
+
id: maps.stories?.get(mappedAlternate.id) ?? mappedAlternate.id,
|
|
270
|
+
parent_id: maps.stories?.get(mappedAlternate.parent_id) ?? mappedAlternate.parent_id
|
|
271
|
+
};
|
|
272
|
+
}) : story.alternates;
|
|
273
|
+
const parentId = maps.stories?.get(story.parent_id) ?? story.parent_id;
|
|
274
|
+
const mappedContentRaw = story.content?.component ? traverseAndMapBySchema(story.content, {
|
|
275
|
+
schemas,
|
|
276
|
+
maps,
|
|
277
|
+
fieldRefMappers,
|
|
278
|
+
processedFields,
|
|
279
|
+
missingSchemas
|
|
280
|
+
}) : story.content;
|
|
281
|
+
return {
|
|
282
|
+
mappedStory: {
|
|
283
|
+
...story,
|
|
284
|
+
content: mappedContentRaw,
|
|
285
|
+
id: Number(maps.stories?.get(story.id) ?? story.id),
|
|
286
|
+
uuid: String(maps.stories?.get(story.uuid) ?? story.uuid),
|
|
287
|
+
parent_id: parentId != null ? Number(parentId) : null,
|
|
288
|
+
alternates
|
|
289
|
+
},
|
|
290
|
+
processedFields,
|
|
291
|
+
missingSchemas
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
//#endregion
|
|
296
|
+
//#region src/rename-datasource-value.ts
|
|
297
|
+
function traverseRichtext(data, componentsToUpdate, oldValue, newValue, changes, path) {
|
|
298
|
+
if (Array.isArray(data)) return data.map((item, index) => traverseRichtext(item, componentsToUpdate, oldValue, newValue, changes, `${path}[${index}]`));
|
|
299
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
300
|
+
const record = data;
|
|
301
|
+
if (record.type === "blok" && record.attrs && typeof record.attrs === "object") {
|
|
302
|
+
const attrs = record.attrs;
|
|
303
|
+
if (Array.isArray(attrs.body)) return {
|
|
304
|
+
...record,
|
|
305
|
+
attrs: {
|
|
306
|
+
...attrs,
|
|
307
|
+
body: attrs.body.map((item, index) => {
|
|
308
|
+
if (item && typeof item === "object" && !Array.isArray(item)) return traverseObject(item, componentsToUpdate, oldValue, newValue, changes, `${path}.attrs.body[${index}]`);
|
|
309
|
+
return item;
|
|
310
|
+
})
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
const result = {};
|
|
315
|
+
for (const [key, value] of Object.entries(record)) result[key] = traverseRichtext(value, componentsToUpdate, oldValue, newValue, changes, `${path}.${key}`);
|
|
316
|
+
return result;
|
|
317
|
+
}
|
|
318
|
+
return data;
|
|
319
|
+
}
|
|
320
|
+
function traverseObject(obj, componentsToUpdate, oldValue, newValue, changes, path) {
|
|
321
|
+
if (!obj || typeof obj !== "object" || Array.isArray(obj)) return obj;
|
|
322
|
+
const result = { ...obj };
|
|
323
|
+
const componentName = obj.component;
|
|
324
|
+
if (componentName) for (const { field, name } of componentsToUpdate) {
|
|
325
|
+
if (name !== componentName) continue;
|
|
326
|
+
const fieldValue = result[field];
|
|
327
|
+
if (typeof fieldValue === "string" && fieldValue === oldValue) {
|
|
328
|
+
result[field] = newValue;
|
|
329
|
+
changes.push({
|
|
330
|
+
component: componentName,
|
|
331
|
+
field,
|
|
332
|
+
path: `${path}.${field}`
|
|
333
|
+
});
|
|
334
|
+
} else if (Array.isArray(fieldValue)) result[field] = fieldValue.map((item) => {
|
|
335
|
+
if (item === oldValue) {
|
|
336
|
+
changes.push({
|
|
337
|
+
component: componentName,
|
|
338
|
+
field,
|
|
339
|
+
path: `${path}.${field}[]`
|
|
340
|
+
});
|
|
341
|
+
return newValue;
|
|
342
|
+
}
|
|
343
|
+
return item;
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
for (const [key, value] of Object.entries(result)) if (Array.isArray(value)) result[key] = value.map((item, index) => {
|
|
347
|
+
if (item && typeof item === "object" && !Array.isArray(item)) return traverseObject(item, componentsToUpdate, oldValue, newValue, changes, `${path}.${key}[${index}]`);
|
|
348
|
+
return item;
|
|
349
|
+
});
|
|
350
|
+
else if (value && typeof value === "object" && !Array.isArray(value) && value.type === "doc" && Array.isArray(value.content)) result[key] = traverseRichtext(value, componentsToUpdate, oldValue, newValue, changes, `${path}.${key}`);
|
|
351
|
+
return result;
|
|
352
|
+
}
|
|
353
|
+
function renameDataSourceValue(story, componentsToUpdate, oldValue, newValue) {
|
|
354
|
+
const changes = [];
|
|
355
|
+
const newContent = traverseObject(story.content, componentsToUpdate, oldValue, newValue, changes, "content");
|
|
356
|
+
return {
|
|
357
|
+
story: {
|
|
358
|
+
...story,
|
|
359
|
+
content: newContent
|
|
360
|
+
},
|
|
361
|
+
changes
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
//#endregion
|
|
366
|
+
//#region src/url-to-asset.ts
|
|
367
|
+
function urlToAsset(url, options) {
|
|
368
|
+
return {
|
|
369
|
+
fieldtype: "asset",
|
|
370
|
+
id: 0,
|
|
371
|
+
filename: url,
|
|
372
|
+
src: url,
|
|
373
|
+
name: url.split("/").at(-1) || url,
|
|
374
|
+
alt: null,
|
|
375
|
+
title: null,
|
|
376
|
+
copyright: null,
|
|
377
|
+
focus: null,
|
|
378
|
+
meta_data: {},
|
|
379
|
+
source: null,
|
|
380
|
+
is_external_url: true,
|
|
381
|
+
is_private: false,
|
|
382
|
+
updated_at: "",
|
|
383
|
+
width: null,
|
|
384
|
+
height: null,
|
|
385
|
+
aspect_ratio: null,
|
|
386
|
+
public_id: null,
|
|
387
|
+
content_type: "",
|
|
388
|
+
...options
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
//#endregion
|
|
393
|
+
//#region src/url-to-link.ts
|
|
394
|
+
function urlToLink(url, options) {
|
|
395
|
+
if (url.startsWith("mailto:")) return {
|
|
396
|
+
fieldtype: "multilink",
|
|
397
|
+
id: "",
|
|
398
|
+
url: "",
|
|
399
|
+
cached_url: "",
|
|
400
|
+
linktype: "email",
|
|
401
|
+
email: url.slice(7),
|
|
402
|
+
...options
|
|
403
|
+
};
|
|
404
|
+
const hashIndex = url.indexOf("#");
|
|
405
|
+
const anchor = hashIndex === -1 ? void 0 : url.slice(hashIndex + 1);
|
|
406
|
+
const cleanUrl = hashIndex === -1 ? url : url.slice(0, hashIndex);
|
|
407
|
+
return {
|
|
408
|
+
fieldtype: "multilink",
|
|
409
|
+
id: "",
|
|
410
|
+
url: cleanUrl,
|
|
411
|
+
cached_url: cleanUrl,
|
|
412
|
+
linktype: "url",
|
|
413
|
+
...anchor ? { anchor } : {},
|
|
414
|
+
...options
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
//#endregion
|
|
419
|
+
export { deleteOutOfSchemaFields, getLocalAssets, getLocalComponents, getLocalDatasources, getLocalStories, htmlToStoryblokRichtext, mapRefs, markdownToStoryblokRichtext, renameDataSourceValue, updateLocalAsset, updateLocalComponent, updateLocalDatasource, updateLocalStory, urlToAsset, urlToLink };
|
|
420
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/delete-out-of-schema-fields.ts","../src/local-utils.ts","../src/local-assets.ts","../src/local-components.ts","../src/local-datasources.ts","../src/local-stories.ts","../src/map-refs.ts","../src/rename-datasource-value.ts","../src/url-to-asset.ts","../src/url-to-link.ts"],"sourcesContent":["import type { Story } from '@storyblok/management-api-client/resources/stories';\n\nimport type { ComponentSchemas } from './map-refs';\n\nconst SYSTEM_FIELDS = new Set(['_uid', 'component', '_editable']);\n\ninterface RemovedField {\n component: string;\n field: string;\n}\n\nfunction cleanBlok(\n blok: Record<string, unknown>,\n schemaDefinition: ComponentSchemas,\n removedFields: RemovedField[],\n): Record<string, unknown> {\n const componentName = blok.component as string | undefined;\n if (!componentName) {\n return blok;\n }\n\n const schema = schemaDefinition[componentName];\n if (!schema) {\n // Unknown component — leave untouched\n return blok;\n }\n\n const validFieldSet = new Set(Object.keys(schema));\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(blok)) {\n // Always keep system fields\n if (SYSTEM_FIELDS.has(key)) {\n result[key] = value;\n continue;\n }\n\n // Strip i18n suffix to get base field name\n const baseFieldName = key.replace(/__i18n__.*/, '');\n\n // Field not in schema — remove it\n if (!validFieldSet.has(baseFieldName)) {\n removedFields.push({ component: componentName, field: key });\n continue;\n }\n\n // Check if this is an array of bloks (objects with component property)\n const isBlokArray\n = Array.isArray(value)\n && value.some(\n item =>\n item\n && typeof item === 'object'\n && !Array.isArray(item)\n && (item as Record<string, unknown>).component,\n );\n\n if (isBlokArray) {\n // Traverse blok arrays and process nested bloks recursively\n result[key] = (value as unknown[]).map((item) => {\n if (\n item\n && typeof item === 'object'\n && !Array.isArray(item)\n && (item as Record<string, unknown>).component\n ) {\n return cleanBlok(\n item as Record<string, unknown>,\n schemaDefinition,\n removedFields,\n );\n }\n return item;\n });\n }\n else {\n // Valid field — keep it\n result[key] = value;\n }\n }\n\n return result;\n}\n\nexport function deleteOutOfSchemaFields(\n story: Story,\n schemaDefinition: ComponentSchemas,\n): { story: Story; removedFields: RemovedField[] } {\n const removedFields: RemovedField[] = [];\n\n if (!story.content) {\n return { story, removedFields };\n }\n\n const newContent = cleanBlok(\n story.content as Record<string, unknown>,\n schemaDefinition,\n removedFields,\n );\n\n return {\n // cleanBlok returns Record<string,unknown>; runtime shape satisfies Blok\n story: { ...story, content: newContent as unknown as Story['content'] },\n removedFields,\n };\n}\n","import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises';\nimport { extname, join } from 'pathe';\n\nexport async function readLocalJsonFiles<T>(dir: string): Promise<T[]> {\n let files: string[];\n try {\n files = await readdir(dir);\n }\n catch (error: unknown) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return [];\n }\n throw error;\n }\n\n const jsonFiles = files.filter(f => extname(f) === '.json');\n\n const items = await Promise.all(\n jsonFiles.map(async (file) => {\n const filePath = join(dir, file);\n const content = await readFile(filePath, 'utf8');\n try {\n return JSON.parse(content) as T;\n }\n catch (error: unknown) {\n throw new Error(\n `Failed to parse ${filePath}: ${(error as Error).message}`,\n );\n }\n }),\n );\n\n return items;\n}\n\nexport async function writeLocalJsonFile(\n dir: string,\n filename: string,\n data: unknown,\n): Promise<void> {\n await mkdir(dir, { recursive: true });\n const filePath = join(dir, filename);\n await writeFile(filePath, JSON.stringify(data, undefined, 2), 'utf8');\n}\n","import type { Asset } from '@storyblok/management-api-client/resources/assets';\n\nimport { readLocalJsonFiles, writeLocalJsonFile } from './local-utils';\n\nfunction getAssetFilename(asset: Pick<Asset, 'id' | 'short_filename'>): string {\n const name = (asset.short_filename || String(asset.id)).replace(\n /\\.[^.]+$/,\n '',\n ); // strip extension\n return `${name}_${asset.id}.json`;\n}\n\nexport async function getLocalAssets(dir: string): Promise<Asset[]> {\n return readLocalJsonFiles<Asset>(dir);\n}\n\nexport async function updateLocalAsset(\n dir: string,\n asset: Asset,\n): Promise<void> {\n await writeLocalJsonFile(dir, getAssetFilename(asset), asset);\n}\n","import type { Component } from '@storyblok/management-api-client/resources/components';\n\nimport { readLocalJsonFiles, writeLocalJsonFile } from './local-utils';\n\nfunction getComponentFilename(component: Pick<Component, 'name'>): string {\n return `${component.name}.json`;\n}\n\nexport async function getLocalComponents(dir: string): Promise<Component[]> {\n return readLocalJsonFiles<Component>(dir);\n}\n\nexport async function updateLocalComponent(\n dir: string,\n component: Component,\n): Promise<void> {\n await writeLocalJsonFile(dir, getComponentFilename(component), component);\n}\n","import type { Datasource } from '@storyblok/management-api-client/resources/datasources';\n\nimport { readLocalJsonFiles, writeLocalJsonFile } from './local-utils';\n\nfunction getDatasourceFilename(\n datasource: Pick<Datasource, 'slug' | 'id'>,\n): string {\n return `${datasource.slug}_${datasource.id}.json`;\n}\n\nexport async function getLocalDatasources(dir: string): Promise<Datasource[]> {\n return readLocalJsonFiles<Datasource>(dir);\n}\n\nexport async function updateLocalDatasource(\n dir: string,\n datasource: Datasource,\n): Promise<void> {\n await writeLocalJsonFile(dir, getDatasourceFilename(datasource), datasource);\n}\n\nexport type { Datasource };\n","import type { Story } from '@storyblok/management-api-client/resources/stories';\n\nimport { readLocalJsonFiles, writeLocalJsonFile } from './local-utils';\n\nfunction getStoryFilename(story: Pick<Story, 'slug' | 'uuid'>): string {\n return `${story.slug}_${story.uuid}.json`;\n}\n\nexport async function getLocalStories(dir: string): Promise<Story[]> {\n return readLocalJsonFiles<Story>(dir);\n}\n\nexport async function updateLocalStory(\n dir: string,\n story: Story,\n): Promise<void> {\n await writeLocalJsonFile(dir, getStoryFilename(story), story);\n}\n","import type { Component } from '@storyblok/management-api-client/resources/components';\nimport type { Story } from '@storyblok/management-api-client/resources/stories';\n\nexport interface RefMaps {\n assets?: Map<unknown, string | number>;\n stories?: Map<unknown, string | number>;\n users?: Map<unknown, string | number>;\n tags?: Map<unknown, string | number>;\n datasources?: Map<unknown, string | number>;\n}\n\nexport type ComponentSchemas = Record<\n string,\n Record<string, { type: string; source?: string }>\n>;\n\nexport interface MapRefsOptions {\n schemas: ComponentSchemas;\n maps: RefMaps;\n}\n\ntype ProcessedFields = Set<Component['schema']>;\ntype MissingSchemas = Set<Component['name']>;\ntype UnknownRecord = Record<string, unknown>;\n\ntype RefMapper = (\n data: unknown,\n options: {\n schema: Component['schema'];\n schemas: ComponentSchemas;\n maps: RefMaps;\n fieldRefMappers: FieldRefMappers;\n processedFields: ProcessedFields;\n missingSchemas: MissingSchemas;\n },\n) => unknown;\n\ntype FieldRefMappers = Record<string, RefMapper>;\n\nfunction isRecord(value: unknown): value is UnknownRecord {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction asRecord(value: unknown): UnknownRecord {\n return isRecord(value) ? value : {};\n}\n\nfunction asArray(value: unknown): unknown[] {\n return Array.isArray(value) ? value : [];\n}\n\nconst traverseAndMapBySchema = (\n data: unknown,\n {\n schemas,\n maps,\n fieldRefMappers,\n processedFields,\n missingSchemas,\n }: {\n schemas: ComponentSchemas;\n maps: RefMaps;\n fieldRefMappers: FieldRefMappers;\n processedFields: ProcessedFields;\n missingSchemas: MissingSchemas;\n },\n): unknown => {\n if (!isRecord(data) || typeof data.component !== 'string') {\n return data ?? {};\n }\n\n const schema = schemas[data.component];\n if (!schema) {\n missingSchemas.add(data.component);\n return data;\n }\n\n const dataNew: UnknownRecord = { ...data };\n\n for (const [fieldName, fieldValue] of Object.entries(data)) {\n const fieldSchema = schema[\n fieldName.replace(/__i18n__.*/, '')\n ] as Component['schema'];\n const fieldType\n = fieldSchema\n && typeof fieldSchema === 'object'\n && 'type' in fieldSchema\n && fieldSchema.type;\n const fieldRefMapper\n = typeof fieldType === 'string' && fieldRefMappers[fieldType];\n\n if (fieldSchema) {\n processedFields.add(fieldSchema);\n }\n\n if (fieldRefMapper) {\n dataNew[fieldName] = fieldRefMapper(fieldValue, {\n schema: fieldSchema,\n schemas,\n maps,\n fieldRefMappers,\n processedFields,\n missingSchemas,\n });\n }\n }\n\n return dataNew;\n};\n\nconst traverseAndMapRichtextDoc = (\n data: unknown,\n {\n schemas,\n maps,\n fieldRefMappers,\n processedFields,\n missingSchemas,\n }: {\n schemas: ComponentSchemas;\n maps: RefMaps;\n fieldRefMappers: FieldRefMappers;\n processedFields: ProcessedFields;\n missingSchemas: MissingSchemas;\n },\n): unknown => {\n if (Array.isArray(data)) {\n return data.map(item =>\n traverseAndMapRichtextDoc(item, {\n schemas,\n maps,\n fieldRefMappers,\n processedFields,\n missingSchemas,\n }),\n );\n }\n\n if (isRecord(data)) {\n if (data.type === 'link' && asRecord(data.attrs).linktype === 'story') {\n return {\n ...data,\n attrs: {\n ...asRecord(data.attrs),\n uuid:\n maps.stories?.get(asRecord(data.attrs).uuid)\n ?? asRecord(data.attrs).uuid,\n },\n };\n }\n\n if (data.type === 'blok') {\n return {\n ...data,\n attrs: {\n ...asRecord(data.attrs),\n body: asArray(asRecord(data.attrs).body).map(d =>\n traverseAndMapBySchema(d, {\n schemas,\n maps,\n fieldRefMappers,\n processedFields,\n missingSchemas,\n }),\n ),\n },\n };\n }\n\n const newData: UnknownRecord = {};\n for (const [k, value] of Object.entries(data)) {\n newData[k] = traverseAndMapRichtextDoc(value, {\n schemas,\n maps,\n fieldRefMappers,\n processedFields,\n missingSchemas,\n });\n }\n\n return newData;\n }\n\n return data;\n};\n\nconst richtextFieldRefMapper: RefMapper = (\n data,\n { schemas, maps, fieldRefMappers, processedFields, missingSchemas },\n) =>\n traverseAndMapRichtextDoc(data, {\n schemas,\n maps,\n fieldRefMappers,\n processedFields,\n missingSchemas,\n });\n\nconst multilinkFieldRefMapper: RefMapper = (data, { maps }) => {\n if (!isRecord(data) || data.linktype !== 'story') {\n return data;\n }\n\n return {\n ...data,\n id: maps.stories?.get(data.id) ?? data.id,\n };\n};\n\nconst bloksFieldRefMapper: RefMapper = (\n data,\n { schemas, maps, fieldRefMappers, processedFields, missingSchemas },\n) => {\n if (!Array.isArray(data)) {\n throw new TypeError(\n `Invalid bloks field: expected an array, but received ${JSON.stringify(data)}.`,\n );\n }\n\n return data.map(d =>\n traverseAndMapBySchema(d, {\n schemas,\n maps,\n fieldRefMappers,\n processedFields,\n missingSchemas,\n }),\n );\n};\n\nconst assetFieldRefMapper: RefMapper = (data, { maps }) => {\n if (!isRecord(data)) {\n return data;\n }\n\n const newId\n = typeof data.id === 'number' ? maps.assets?.get(data.id) : undefined;\n return newId === undefined ? data : { ...data, id: newId };\n};\n\nconst multiassetFieldRefMapper: RefMapper = (data, options) => {\n if (!Array.isArray(data)) {\n throw new TypeError(\n `Invalid multiasset field: expected an array, but received ${JSON.stringify(data)}.`,\n );\n }\n\n return data.map(d => assetFieldRefMapper(d, options));\n};\n\nconst optionsFieldRefMapper: RefMapper = (data, { schema, maps }) => {\n if (!Array.isArray(data)) {\n return data;\n }\n\n const sourceMapBySchema: Record<\n string,\n Map<unknown, string | number> | undefined\n > = {\n internal_stories: maps.stories,\n internal_users: maps.users,\n internal_tags: maps.tags,\n internal_datasources: maps.datasources,\n };\n\n const sourceMap\n = sourceMapBySchema[(schema as { source?: string }).source ?? ''];\n if (!sourceMap) {\n return data;\n }\n\n return data.map(d => sourceMap.get(d) ?? d);\n};\n\nconst fieldRefMappers = {\n asset: assetFieldRefMapper,\n bloks: bloksFieldRefMapper,\n multiasset: multiassetFieldRefMapper,\n multilink: multilinkFieldRefMapper,\n options: optionsFieldRefMapper,\n richtext: richtextFieldRefMapper,\n} as const;\n\nexport function mapRefs(\n story: Story,\n options: MapRefsOptions,\n): {\n mappedStory: Story;\n processedFields: ProcessedFields;\n missingSchemas: MissingSchemas;\n } {\n const { schemas, maps } = options;\n const processedFields: ProcessedFields = new Set();\n const missingSchemas: MissingSchemas = new Set();\n\n const alternatesRaw = story.alternates\n ? (story.alternates as Required<Story>['alternates']).map((alternate) => {\n const mappedAlternate = asRecord(alternate);\n return {\n ...mappedAlternate,\n id: maps.stories?.get(mappedAlternate.id) ?? mappedAlternate.id,\n parent_id:\n maps.stories?.get(mappedAlternate.parent_id)\n ?? mappedAlternate.parent_id,\n };\n })\n : story.alternates;\n // mapped ids may be string|number at runtime but shape is compatible\n const alternates = alternatesRaw as Story['alternates'];\n\n const parentId = maps.stories?.get(story.parent_id) ?? story.parent_id;\n const mappedContentRaw = story.content?.component\n ? traverseAndMapBySchema(story.content, {\n schemas,\n maps,\n fieldRefMappers,\n processedFields,\n missingSchemas,\n })\n : story.content;\n\n const mappedStory = {\n ...story,\n // traverseAndMapBySchema returns unknown; runtime shape satisfies Blok\n content: mappedContentRaw as unknown as Story['content'],\n id: Number(maps.stories?.get(story.id) ?? story.id),\n uuid: String(maps.stories?.get(story.uuid) ?? story.uuid),\n parent_id: parentId != null ? Number(parentId) : null,\n alternates,\n } satisfies Story;\n\n return {\n mappedStory,\n processedFields,\n missingSchemas,\n };\n}\n","import type { Story } from '@storyblok/management-api-client/resources/stories';\n\ninterface ComponentToUpdate {\n field: string;\n name: string;\n}\n\ninterface Change {\n component: string;\n field: string;\n path: string;\n}\n\nfunction traverseRichtext(\n data: unknown,\n componentsToUpdate: ComponentToUpdate[],\n oldValue: string,\n newValue: string,\n changes: Change[],\n path: string,\n): unknown {\n if (Array.isArray(data)) {\n return data.map((item, index) =>\n traverseRichtext(item, componentsToUpdate, oldValue, newValue, changes, `${path}[${index}]`),\n );\n }\n\n if (data && typeof data === 'object' && !Array.isArray(data)) {\n const record = data as Record<string, unknown>;\n\n if (record.type === 'blok' && record.attrs && typeof record.attrs === 'object') {\n const attrs = record.attrs as Record<string, unknown>;\n if (Array.isArray(attrs.body)) {\n return {\n ...record,\n attrs: {\n ...attrs,\n body: attrs.body.map((item: unknown, index: number) => {\n if (item && typeof item === 'object' && !Array.isArray(item)) {\n return traverseObject(\n item as Record<string, unknown>,\n componentsToUpdate,\n oldValue,\n newValue,\n changes,\n `${path}.attrs.body[${index}]`,\n );\n }\n return item;\n }),\n },\n };\n }\n }\n\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(record)) {\n result[key] = traverseRichtext(value, componentsToUpdate, oldValue, newValue, changes, `${path}.${key}`);\n }\n return result;\n }\n\n return data;\n}\n\nfunction traverseObject(\n obj: Record<string, unknown>,\n componentsToUpdate: ComponentToUpdate[],\n oldValue: string,\n newValue: string,\n changes: Change[],\n path: string,\n): Record<string, unknown> {\n if (!obj || typeof obj !== 'object' || Array.isArray(obj)) {\n return obj;\n }\n\n const result = { ...obj };\n const componentName = obj.component as string | undefined;\n\n if (componentName) {\n for (const { field, name } of componentsToUpdate) {\n if (name !== componentName) {\n continue;\n }\n\n const fieldValue = result[field];\n\n if (typeof fieldValue === 'string' && fieldValue === oldValue) {\n result[field] = newValue;\n changes.push({\n component: componentName,\n field,\n path: `${path}.${field}`,\n });\n }\n else if (Array.isArray(fieldValue)) {\n const newArray = fieldValue.map((item) => {\n if (item === oldValue) {\n changes.push({\n component: componentName,\n field,\n path: `${path}.${field}[]`,\n });\n return newValue;\n }\n return item;\n });\n result[field] = newArray;\n }\n }\n }\n\n // Traverse nested arrays (bloks fields) and richtext fields\n for (const [key, value] of Object.entries(result)) {\n if (Array.isArray(value)) {\n result[key] = value.map((item, index) => {\n if (item && typeof item === 'object' && !Array.isArray(item)) {\n return traverseObject(\n item as Record<string, unknown>,\n componentsToUpdate,\n oldValue,\n newValue,\n changes,\n `${path}.${key}[${index}]`,\n );\n }\n return item;\n });\n }\n else if (\n value\n && typeof value === 'object'\n && !Array.isArray(value)\n && (value as Record<string, unknown>).type === 'doc'\n && Array.isArray((value as Record<string, unknown>).content)\n ) {\n result[key] = traverseRichtext(value, componentsToUpdate, oldValue, newValue, changes, `${path}.${key}`);\n }\n }\n\n return result;\n}\n\nexport function renameDataSourceValue(\n story: Story,\n componentsToUpdate: ComponentToUpdate[],\n oldValue: string,\n newValue: string,\n): { story: Story; changes: Change[] } {\n const changes: Change[] = [];\n\n const newContent = traverseObject(\n story.content as Record<string, unknown>,\n componentsToUpdate,\n oldValue,\n newValue,\n changes,\n 'content',\n );\n\n return {\n // traverseObject returns Record<string,unknown>; runtime shape satisfies Blok\n story: { ...story, content: newContent as unknown as Story['content'] },\n changes,\n };\n}\n","import type { StoryblokAsset } from './types';\n\nexport interface UrlToAssetOptions {\n alt?: string | null;\n title?: string | null;\n copyright?: string | null;\n focus?: string | null;\n}\n\nexport function urlToAsset(\n url: string,\n options?: UrlToAssetOptions,\n): StoryblokAsset {\n // Derive name from last path segment\n const pathSegments = url.split('/');\n const name = pathSegments.at(-1) || url;\n\n return {\n fieldtype: 'asset',\n id: 0,\n filename: url,\n src: url,\n name,\n alt: null,\n title: null,\n copyright: null,\n focus: null,\n meta_data: {},\n source: null,\n is_external_url: true,\n is_private: false,\n updated_at: '',\n width: null,\n height: null,\n aspect_ratio: null,\n public_id: null,\n content_type: '',\n ...options,\n };\n}\n","import type { StoryblokMultilink } from './types';\n\nexport interface UrlToLinkOptions {\n target?: '_blank' | '_self';\n title?: string;\n rel?: string;\n anchor?: string;\n}\n\nexport function urlToLink(\n url: string,\n options?: UrlToLinkOptions,\n): StoryblokMultilink {\n // Detect mailto: links\n if (url.startsWith('mailto:')) {\n return {\n fieldtype: 'multilink',\n id: '',\n url: '',\n cached_url: '',\n linktype: 'email',\n email: url.slice('mailto:'.length),\n ...options,\n };\n }\n\n // Extract anchor from fragment\n const hashIndex = url.indexOf('#');\n const anchor = hashIndex === -1 ? undefined : url.slice(hashIndex + 1);\n const cleanUrl = hashIndex === -1 ? url : url.slice(0, hashIndex);\n\n return {\n fieldtype: 'multilink',\n id: '',\n url: cleanUrl,\n cached_url: cleanUrl,\n linktype: 'url',\n ...(anchor ? { anchor } : {}),\n ...options,\n };\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@storyblok/migrations",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"private": false,
|
|
6
|
+
"description": "Migration utilities for Storyblok",
|
|
7
|
+
"author": "Storyblok",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"homepage": "https://github.com/storyblok/monoblok/tree/main/packages/migrations#readme",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/storyblok/monoblok.git",
|
|
13
|
+
"directory": "packages/migrations"
|
|
14
|
+
},
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/storyblok/monoblok/issues"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"storyblok",
|
|
20
|
+
"migrations",
|
|
21
|
+
"content",
|
|
22
|
+
"cms",
|
|
23
|
+
"headless",
|
|
24
|
+
"schema",
|
|
25
|
+
"data-migration"
|
|
26
|
+
],
|
|
27
|
+
"sideEffects": false,
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"import": "./dist/index.mjs",
|
|
31
|
+
"require": "./dist/index.cjs"
|
|
32
|
+
},
|
|
33
|
+
"./package.json": "./package.json"
|
|
34
|
+
},
|
|
35
|
+
"main": "./dist/index.cjs",
|
|
36
|
+
"module": "./dist/index.mjs",
|
|
37
|
+
"types": "./dist/index.d.cts",
|
|
38
|
+
"files": [
|
|
39
|
+
"dist"
|
|
40
|
+
],
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"pathe": "^2.0.3",
|
|
46
|
+
"@storyblok/management-api-client": "0.2.0",
|
|
47
|
+
"@storyblok/richtext": "4.1.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "^22.15.18",
|
|
51
|
+
"@vitest/coverage-v8": "^3.1.3",
|
|
52
|
+
"eslint": "^9.26.0",
|
|
53
|
+
"jiti": "^2.4.2",
|
|
54
|
+
"tsdown": "^0.20.3",
|
|
55
|
+
"typescript": "5.8.3",
|
|
56
|
+
"vitest": "^3.1.3",
|
|
57
|
+
"@storyblok/eslint-config": "0.5.0"
|
|
58
|
+
},
|
|
59
|
+
"scripts": {
|
|
60
|
+
"build": "tsdown",
|
|
61
|
+
"dev": "vitest dev",
|
|
62
|
+
"play": "jiti playground",
|
|
63
|
+
"lint": "eslint .",
|
|
64
|
+
"lint:fix": "eslint . --fix",
|
|
65
|
+
"test": "pnpm lint && pnpm test:types && vitest run --coverage",
|
|
66
|
+
"test:unit": "vitest",
|
|
67
|
+
"test:unit:ci": "vitest run",
|
|
68
|
+
"test:types": "tsc --noEmit --skipLibCheck",
|
|
69
|
+
"coverage": "vitest run --coverage"
|
|
70
|
+
}
|
|
71
|
+
}
|