storyblok 4.14.3 → 4.15.1
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/dist/index.mjs +305 -132
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -11,7 +11,7 @@ import { Command } from 'commander';
|
|
|
11
11
|
import path, { join, resolve as resolve$1, parse, dirname as dirname$1, extname, relative, basename } from 'node:path';
|
|
12
12
|
import { MultiBar, Presets } from 'cli-progress';
|
|
13
13
|
import { Spinner } from '@topcli/spinner';
|
|
14
|
-
import fs, { mkdir, writeFile, readFile as readFile$1, appendFile, access, constants, readdir, unlink
|
|
14
|
+
import fs, { mkdir, writeFile, readFile as readFile$1, appendFile, access, constants, readdir, unlink } from 'node:fs/promises';
|
|
15
15
|
import filenamify from 'filenamify';
|
|
16
16
|
import { ManagementApiClient } from '@storyblok/management-api-client';
|
|
17
17
|
import { RateLimit, Sema } from 'async-sema';
|
|
@@ -103,6 +103,44 @@ const regionNames = {
|
|
|
103
103
|
({
|
|
104
104
|
SB_Agent_Version: process.env.npm_package_version || "4.x"
|
|
105
105
|
});
|
|
106
|
+
const SUPPORTED_ASSET_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
107
|
+
// Images: image/png, image/x-png, image/gif, image/jpeg, image/avif, image/svg+xml, image/webp
|
|
108
|
+
".jpg",
|
|
109
|
+
".jpeg",
|
|
110
|
+
".png",
|
|
111
|
+
".gif",
|
|
112
|
+
".webp",
|
|
113
|
+
".avif",
|
|
114
|
+
".svg",
|
|
115
|
+
// Video: video/*, application/mp4, application/x-mpegurl, application/vnd.apple.mpegurl
|
|
116
|
+
".mp4",
|
|
117
|
+
".mov",
|
|
118
|
+
".avi",
|
|
119
|
+
".webm",
|
|
120
|
+
".wmv",
|
|
121
|
+
".mkv",
|
|
122
|
+
".flv",
|
|
123
|
+
".ogv",
|
|
124
|
+
".3gp",
|
|
125
|
+
".m4v",
|
|
126
|
+
".mpg",
|
|
127
|
+
".mpeg",
|
|
128
|
+
".m3u8",
|
|
129
|
+
// Audio: audio/*
|
|
130
|
+
".mp3",
|
|
131
|
+
".wav",
|
|
132
|
+
".ogg",
|
|
133
|
+
".aac",
|
|
134
|
+
".flac",
|
|
135
|
+
".wma",
|
|
136
|
+
".m4a",
|
|
137
|
+
".opus",
|
|
138
|
+
// Documents: application/msword, text/plain, application/pdf, application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
|
139
|
+
".pdf",
|
|
140
|
+
".doc",
|
|
141
|
+
".docx",
|
|
142
|
+
".txt"
|
|
143
|
+
]);
|
|
106
144
|
const directories = {
|
|
107
145
|
assets: "assets",
|
|
108
146
|
components: "components",
|
|
@@ -651,25 +689,38 @@ const API_ACTIONS = {
|
|
|
651
689
|
const API_ERRORS = {
|
|
652
690
|
unauthorized: "The user is not authorized to access the API",
|
|
653
691
|
network_error: "No response from server, please check if you are correctly connected to internet",
|
|
692
|
+
server_error: "The server returned an error",
|
|
654
693
|
invalid_credentials: "The provided credentials are invalid",
|
|
655
694
|
timeout: "The API request timed out",
|
|
656
695
|
generic: "Error fetching data from the API",
|
|
657
696
|
not_found: "The requested resource was not found",
|
|
658
697
|
unprocessable_entity: "The request was well-formed but was unable to be followed due to semantic errors"
|
|
659
698
|
};
|
|
699
|
+
function getErrorId(status) {
|
|
700
|
+
switch (status) {
|
|
701
|
+
case 401:
|
|
702
|
+
return "unauthorized";
|
|
703
|
+
case 404:
|
|
704
|
+
return "not_found";
|
|
705
|
+
case 422:
|
|
706
|
+
return "unprocessable_entity";
|
|
707
|
+
default:
|
|
708
|
+
return status >= 500 ? "server_error" : "generic";
|
|
709
|
+
}
|
|
710
|
+
}
|
|
660
711
|
function handleAPIError(action, error, customMessage) {
|
|
661
712
|
if (error instanceof FetchError) {
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
713
|
+
const errorId = getErrorId(error.response.status);
|
|
714
|
+
throw new APIError(errorId, action, error, customMessage);
|
|
715
|
+
}
|
|
716
|
+
const response = error?.response;
|
|
717
|
+
if (response?.status) {
|
|
718
|
+
const wrappedError = new FetchError(
|
|
719
|
+
response.statusText ?? error.message,
|
|
720
|
+
{ status: response.status, statusText: response.statusText ?? "", data: response.data }
|
|
721
|
+
);
|
|
722
|
+
const errorId = getErrorId(response.status);
|
|
723
|
+
throw new APIError(errorId, action, wrappedError, customMessage);
|
|
673
724
|
}
|
|
674
725
|
throw new APIError("generic", action, error, customMessage);
|
|
675
726
|
}
|
|
@@ -1888,34 +1939,10 @@ const getUser = async (token, region) => {
|
|
|
1888
1939
|
});
|
|
1889
1940
|
return data?.user;
|
|
1890
1941
|
} catch (error) {
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
throw new APIError("unauthorized", "get_user", error, `The token provided ${chalk.bold(maskToken(token))} is invalid.
|
|
1896
|
-
Please make sure you are using the correct token and try again.`);
|
|
1897
|
-
default:
|
|
1898
|
-
throw new APIError("network_error", "get_user", error);
|
|
1899
|
-
}
|
|
1900
|
-
}
|
|
1901
|
-
if (typeof error === "string" && error === "Unauthorized") {
|
|
1902
|
-
const mockFetchError = new FetchError("Non-JSON response", {
|
|
1903
|
-
status: 401,
|
|
1904
|
-
statusText: "Unauthorized",
|
|
1905
|
-
data: null
|
|
1906
|
-
});
|
|
1907
|
-
throw new APIError("unauthorized", "get_user", mockFetchError, `The token provided ${chalk.bold(maskToken(token))} is invalid.
|
|
1908
|
-
Please make sure you are using the correct token and try again.`);
|
|
1909
|
-
}
|
|
1910
|
-
if (typeof error === "object" && error !== null && Object.keys(error).length === 0) {
|
|
1911
|
-
const mockFetchError = new FetchError("Network Error", {
|
|
1912
|
-
status: 500,
|
|
1913
|
-
statusText: "Internal Server Error",
|
|
1914
|
-
data: null
|
|
1915
|
-
});
|
|
1916
|
-
throw new APIError("network_error", "get_user", mockFetchError);
|
|
1917
|
-
}
|
|
1918
|
-
throw new APIError("generic", "get_user", error);
|
|
1942
|
+
const status = error?.response?.status;
|
|
1943
|
+
const customMessage = status === 401 ? `The token provided ${chalk.bold(maskToken(token))} is invalid.
|
|
1944
|
+
Please make sure you are using the correct token and try again.` : void 0;
|
|
1945
|
+
handleAPIError("get_user", error, customMessage);
|
|
1919
1946
|
}
|
|
1920
1947
|
};
|
|
1921
1948
|
|
|
@@ -1926,17 +1953,7 @@ const loginWithToken = async (token, region) => {
|
|
|
1926
1953
|
if (error instanceof APIError) {
|
|
1927
1954
|
throw error;
|
|
1928
1955
|
}
|
|
1929
|
-
|
|
1930
|
-
const status = error.response.status;
|
|
1931
|
-
switch (status) {
|
|
1932
|
-
case 401:
|
|
1933
|
-
throw new APIError("unauthorized", "login_with_token", error, `The token provided ${chalk.bold(maskToken(token))} is invalid.
|
|
1934
|
-
Please make sure you are using the correct token and try again.`);
|
|
1935
|
-
default:
|
|
1936
|
-
throw new APIError("network_error", "login_with_token", error);
|
|
1937
|
-
}
|
|
1938
|
-
}
|
|
1939
|
-
throw new APIError("generic", "login_with_token", error, "The provided credentials are invalid");
|
|
1956
|
+
handleAPIError("login_with_token", error);
|
|
1940
1957
|
}
|
|
1941
1958
|
};
|
|
1942
1959
|
const loginWithEmailAndPassword = async (email, password, region) => {
|
|
@@ -4025,13 +4042,13 @@ const createStory = async (spaceId, payload) => {
|
|
|
4025
4042
|
},
|
|
4026
4043
|
body: {
|
|
4027
4044
|
story: payload.story,
|
|
4028
|
-
publish: payload.publish
|
|
4045
|
+
...payload.publish ? { publish: payload.publish } : {}
|
|
4029
4046
|
},
|
|
4030
4047
|
throwOnError: true
|
|
4031
4048
|
});
|
|
4032
4049
|
return data?.story;
|
|
4033
|
-
} catch (
|
|
4034
|
-
handleAPIError("create_story",
|
|
4050
|
+
} catch (error) {
|
|
4051
|
+
handleAPIError("create_story", error);
|
|
4035
4052
|
}
|
|
4036
4053
|
};
|
|
4037
4054
|
const updateStory = async (spaceId, storyId, payload) => {
|
|
@@ -4045,18 +4062,20 @@ const updateStory = async (spaceId, storyId, payload) => {
|
|
|
4045
4062
|
body: {
|
|
4046
4063
|
story: payload.story,
|
|
4047
4064
|
force_update: payload.force_update === "1" ? "1" : "0",
|
|
4048
|
-
publish: payload.publish
|
|
4065
|
+
...payload.publish ? { publish: payload.publish } : {}
|
|
4049
4066
|
},
|
|
4050
4067
|
throwOnError: true
|
|
4051
4068
|
});
|
|
4052
|
-
const
|
|
4069
|
+
const story = data?.story;
|
|
4053
4070
|
if (!story) {
|
|
4054
4071
|
throw new Error("Failed to update story");
|
|
4055
4072
|
}
|
|
4056
4073
|
return story;
|
|
4057
|
-
} catch (
|
|
4058
|
-
|
|
4059
|
-
|
|
4074
|
+
} catch (error) {
|
|
4075
|
+
if (error instanceof Error && error.message === "Failed to update story") {
|
|
4076
|
+
throw error;
|
|
4077
|
+
}
|
|
4078
|
+
handleAPIError("update_story", error);
|
|
4060
4079
|
}
|
|
4061
4080
|
};
|
|
4062
4081
|
|
|
@@ -5299,6 +5318,121 @@ const storyblokSchemas = /* @__PURE__ */ new Map([
|
|
|
5299
5318
|
["richtext", getRichtextJSONSchema]
|
|
5300
5319
|
]);
|
|
5301
5320
|
|
|
5321
|
+
function generateStoryblokImports(storyblokPropertyTypes, STORY_TYPE) {
|
|
5322
|
+
const imports = [];
|
|
5323
|
+
const needsISbStoryData = storyblokPropertyTypes.has(STORY_TYPE);
|
|
5324
|
+
if (needsISbStoryData) {
|
|
5325
|
+
imports.push(`import type { ${STORY_TYPE} } from '@storyblok/js';`);
|
|
5326
|
+
storyblokPropertyTypes.delete(STORY_TYPE);
|
|
5327
|
+
}
|
|
5328
|
+
if (storyblokPropertyTypes.size > 0) {
|
|
5329
|
+
const typeImports = Array.from(storyblokPropertyTypes).map((type) => {
|
|
5330
|
+
const pascalType = toPascalCase(type);
|
|
5331
|
+
return `Storyblok${pascalType}`;
|
|
5332
|
+
});
|
|
5333
|
+
imports.push(`import type { ${typeImports.join(", ")} } from '../storyblok.d.ts';`);
|
|
5334
|
+
}
|
|
5335
|
+
return imports;
|
|
5336
|
+
}
|
|
5337
|
+
function escapeRegExp(value) {
|
|
5338
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5339
|
+
}
|
|
5340
|
+
function hasIdentifier(content, identifier) {
|
|
5341
|
+
const regex = new RegExp(`\\b${escapeRegExp(identifier)}\\b`, "g");
|
|
5342
|
+
return regex.test(content);
|
|
5343
|
+
}
|
|
5344
|
+
function detectUsedStoryblokTypes(content, storyblokPropertyTypes, STORY_TYPE) {
|
|
5345
|
+
const usedTypes = [];
|
|
5346
|
+
if (content.includes(STORY_TYPE)) {
|
|
5347
|
+
usedTypes.push(STORY_TYPE);
|
|
5348
|
+
}
|
|
5349
|
+
Array.from(storyblokPropertyTypes).forEach((type) => {
|
|
5350
|
+
const pascalType = toPascalCase(type);
|
|
5351
|
+
if (content.includes(`Storyblok${pascalType}`)) {
|
|
5352
|
+
usedTypes.push(type);
|
|
5353
|
+
}
|
|
5354
|
+
});
|
|
5355
|
+
return usedTypes;
|
|
5356
|
+
}
|
|
5357
|
+
function detectUsedDatasourceTypes(content, datasourceResults) {
|
|
5358
|
+
return datasourceResults.filter((ds) => hasIdentifier(content, ds.title)).map((ds) => ds.title);
|
|
5359
|
+
}
|
|
5360
|
+
function detectReferencedComponents(content, currentTitle, componentResults) {
|
|
5361
|
+
return componentResults.filter((c) => c.title !== currentTitle && hasIdentifier(content, c.title)).map((c) => c.title);
|
|
5362
|
+
}
|
|
5363
|
+
function generateComponentImports(componentContent, componentTitle, storyblokPropertyTypes, datasourceResults, componentResults, STORY_TYPE) {
|
|
5364
|
+
const imports = [];
|
|
5365
|
+
const usedStoryblokTypes = detectUsedStoryblokTypes(
|
|
5366
|
+
componentContent,
|
|
5367
|
+
storyblokPropertyTypes,
|
|
5368
|
+
STORY_TYPE
|
|
5369
|
+
);
|
|
5370
|
+
if (usedStoryblokTypes.length > 0) {
|
|
5371
|
+
const hasISbStoryData = usedStoryblokTypes.includes(STORY_TYPE);
|
|
5372
|
+
const otherTypes = usedStoryblokTypes.filter((t) => t !== STORY_TYPE);
|
|
5373
|
+
if (hasISbStoryData) {
|
|
5374
|
+
imports.push(`import type { ${STORY_TYPE} } from '@storyblok/js';`);
|
|
5375
|
+
}
|
|
5376
|
+
if (otherTypes.length > 0) {
|
|
5377
|
+
const typeImports = otherTypes.map((type) => {
|
|
5378
|
+
const pascalType = toPascalCase(type);
|
|
5379
|
+
return `Storyblok${pascalType}`;
|
|
5380
|
+
});
|
|
5381
|
+
imports.push(`import type { ${typeImports.join(", ")} } from '../storyblok.d.ts';`);
|
|
5382
|
+
}
|
|
5383
|
+
}
|
|
5384
|
+
const usedDatasourceTypes = detectUsedDatasourceTypes(componentContent, datasourceResults);
|
|
5385
|
+
if (usedDatasourceTypes.length > 0) {
|
|
5386
|
+
imports.push(`import type { ${usedDatasourceTypes.join(", ")} } from './datasource-types.d.ts';`);
|
|
5387
|
+
}
|
|
5388
|
+
const referencedComponents = detectReferencedComponents(
|
|
5389
|
+
componentContent,
|
|
5390
|
+
componentTitle,
|
|
5391
|
+
componentResults
|
|
5392
|
+
);
|
|
5393
|
+
if (referencedComponents.length > 0) {
|
|
5394
|
+
const componentImportsStr = referencedComponents.map((name) => `import type { ${name} } from './${name}.d.ts';`).join("\n");
|
|
5395
|
+
imports.push(componentImportsStr);
|
|
5396
|
+
}
|
|
5397
|
+
return imports;
|
|
5398
|
+
}
|
|
5399
|
+
function createDatasourcesFile(datasourceResults, typeDefs) {
|
|
5400
|
+
if (datasourceResults.length === 0) {
|
|
5401
|
+
return null;
|
|
5402
|
+
}
|
|
5403
|
+
const content = [
|
|
5404
|
+
...typeDefs,
|
|
5405
|
+
...datasourceResults.map((r) => r.content)
|
|
5406
|
+
].join("\n");
|
|
5407
|
+
return { name: "datasource-types", content };
|
|
5408
|
+
}
|
|
5409
|
+
function createContentTypesFile(contentTypeBloks, typeDefs) {
|
|
5410
|
+
if (contentTypeBloks.size === 0) {
|
|
5411
|
+
return null;
|
|
5412
|
+
}
|
|
5413
|
+
const contentTypeNames = Array.from(contentTypeBloks);
|
|
5414
|
+
const imports = contentTypeNames.map((name) => `import type { ${name} } from './${name}.d.ts';`).join("\n");
|
|
5415
|
+
const typeUnion = contentTypeNames.length > 0 ? contentTypeNames.join("\n | ") : "never";
|
|
5416
|
+
const typeDefinition = `export type ContentType =
|
|
5417
|
+
| ${typeUnion};`;
|
|
5418
|
+
const content = [
|
|
5419
|
+
...typeDefs,
|
|
5420
|
+
imports,
|
|
5421
|
+
typeDefinition
|
|
5422
|
+
].join("\n");
|
|
5423
|
+
return { name: "content-types", content };
|
|
5424
|
+
}
|
|
5425
|
+
function createComponentFile(componentResult, typeDefs, componentImports) {
|
|
5426
|
+
return {
|
|
5427
|
+
name: componentResult.title,
|
|
5428
|
+
content: [
|
|
5429
|
+
...typeDefs,
|
|
5430
|
+
...componentImports,
|
|
5431
|
+
componentResult.content
|
|
5432
|
+
].join("\n")
|
|
5433
|
+
};
|
|
5434
|
+
}
|
|
5435
|
+
|
|
5302
5436
|
const STORY_TYPE = "ISbStoryData";
|
|
5303
5437
|
const DEFAULT_COMPONENT_FILENAME = "storyblok-components";
|
|
5304
5438
|
const DEFAULT_TYPEDEFS_HEADER = [
|
|
@@ -5390,6 +5524,9 @@ const getComponentType = (componentName, options) => {
|
|
|
5390
5524
|
return isFirstCharacterNumber ? `_${componentType}` : componentType;
|
|
5391
5525
|
};
|
|
5392
5526
|
const getComponentPropertiesTypeAnnotations = async (component, options, spaceData, customFieldsParser) => {
|
|
5527
|
+
if (!component.schema || typeof component.schema !== "object") {
|
|
5528
|
+
return {};
|
|
5529
|
+
}
|
|
5393
5530
|
return Object.entries(component.schema).reduce(async (accPromise, [key, value]) => {
|
|
5394
5531
|
const acc = await accPromise;
|
|
5395
5532
|
if (key.startsWith("tab-")) {
|
|
@@ -5551,6 +5688,9 @@ const generateTypes = async (spaceData, options = {
|
|
|
5551
5688
|
const datasourcesSchema = spaceData.datasources.map(async (datasource) => {
|
|
5552
5689
|
const allComponentTypes = resolvedComponentsSchema.map((schema) => schema.title);
|
|
5553
5690
|
const enumValues = datasource.entries?.filter((d) => d.value).map((d) => d.value);
|
|
5691
|
+
if (!datasource.slug) {
|
|
5692
|
+
return null;
|
|
5693
|
+
}
|
|
5554
5694
|
const type = getDatasourceTypeTitle(datasource.slug);
|
|
5555
5695
|
if (allComponentTypes.includes(type)) {
|
|
5556
5696
|
console.warn(`Warning: Datasource type "${type}" conflicts with existing component type`);
|
|
@@ -5563,7 +5703,10 @@ const generateTypes = async (spaceData, options = {
|
|
|
5563
5703
|
};
|
|
5564
5704
|
return datasourceSchema;
|
|
5565
5705
|
});
|
|
5566
|
-
const
|
|
5706
|
+
const resolvedDatasourcesSchemaWithNulls = await Promise.all(datasourcesSchema);
|
|
5707
|
+
const resolvedDatasourcesSchema = resolvedDatasourcesSchemaWithNulls.filter((s) => s !== null);
|
|
5708
|
+
const componentTitles = new Set(resolvedComponentsSchema.map((s) => s.title).filter(Boolean));
|
|
5709
|
+
const datasourceTitles = new Set(resolvedDatasourcesSchema.map((s) => s.title).filter(Boolean));
|
|
5567
5710
|
const contentTypeSchema = {
|
|
5568
5711
|
$id: `#/ContentType`,
|
|
5569
5712
|
title: "ContentType",
|
|
@@ -5576,26 +5719,48 @@ const generateTypes = async (spaceData, options = {
|
|
|
5576
5719
|
contentTypeSchema
|
|
5577
5720
|
];
|
|
5578
5721
|
const result = await Promise.all(schemas.map(async (schema) => {
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5722
|
+
const title = schema.title || schema.$id.replace("#/", "");
|
|
5723
|
+
return {
|
|
5724
|
+
title,
|
|
5725
|
+
content: await compile(schema, title, {
|
|
5726
|
+
additionalProperties: !options.strict,
|
|
5727
|
+
bannerComment: "",
|
|
5728
|
+
...compilerOptions
|
|
5729
|
+
}),
|
|
5730
|
+
isComponent: componentTitles.has(title),
|
|
5731
|
+
isDatasource: datasourceTitles.has(title)
|
|
5732
|
+
};
|
|
5584
5733
|
}));
|
|
5585
|
-
const imports =
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5734
|
+
const imports = generateStoryblokImports(storyblokPropertyTypes, STORY_TYPE);
|
|
5735
|
+
if (options.separateFiles) {
|
|
5736
|
+
const files = [];
|
|
5737
|
+
const datasourceResults = result.filter((r) => r.isDatasource);
|
|
5738
|
+
const componentResults = result.filter((r) => r.isComponent);
|
|
5739
|
+
const datasourcesFile = createDatasourcesFile(datasourceResults, typeDefs);
|
|
5740
|
+
if (datasourcesFile) {
|
|
5741
|
+
files.push(datasourcesFile);
|
|
5742
|
+
}
|
|
5743
|
+
const contentTypesFile = createContentTypesFile(
|
|
5744
|
+
contentTypeBloks,
|
|
5745
|
+
typeDefs
|
|
5746
|
+
);
|
|
5747
|
+
if (contentTypesFile) {
|
|
5748
|
+
files.push(contentTypesFile);
|
|
5749
|
+
}
|
|
5750
|
+
for (const componentResult of componentResults) {
|
|
5751
|
+
const componentImports = generateComponentImports(
|
|
5752
|
+
componentResult.content,
|
|
5753
|
+
componentResult.title,
|
|
5754
|
+
storyblokPropertyTypes,
|
|
5755
|
+
datasourceResults,
|
|
5756
|
+
componentResults,
|
|
5757
|
+
STORY_TYPE
|
|
5758
|
+
);
|
|
5759
|
+
files.push(createComponentFile(componentResult, typeDefs, componentImports));
|
|
5760
|
+
}
|
|
5761
|
+
return files;
|
|
5597
5762
|
}
|
|
5598
|
-
const finalTypeDef = [...typeDefs, ...imports, ...result];
|
|
5763
|
+
const finalTypeDef = [...typeDefs, ...imports, ...result.map((r) => r.content)];
|
|
5599
5764
|
return [
|
|
5600
5765
|
...finalTypeDef
|
|
5601
5766
|
].join("\n");
|
|
@@ -5603,11 +5768,17 @@ const generateTypes = async (spaceData, options = {
|
|
|
5603
5768
|
handleError(error);
|
|
5604
5769
|
}
|
|
5605
5770
|
};
|
|
5606
|
-
const saveTypesToComponentsFile = async (space,
|
|
5607
|
-
const { filename = DEFAULT_COMPONENT_FILENAME, path } = options;
|
|
5771
|
+
const saveTypesToComponentsFile = async (space, typedefData, options) => {
|
|
5772
|
+
const { filename = DEFAULT_COMPONENT_FILENAME, path, separateFiles } = options;
|
|
5608
5773
|
const resolvedPath = path ? resolve$1(process.cwd(), path, "types", space) : resolvePath(path, `types/${space}`);
|
|
5609
5774
|
try {
|
|
5610
|
-
|
|
5775
|
+
if (separateFiles && Array.isArray(typedefData)) {
|
|
5776
|
+
for (const { name, content } of typedefData) {
|
|
5777
|
+
await saveToFile(join(resolvedPath, `${name}.d.ts`), content);
|
|
5778
|
+
}
|
|
5779
|
+
} else if (typeof typedefData === "string") {
|
|
5780
|
+
await saveToFile(join(resolvedPath, `${filename}.d.ts`), typedefData);
|
|
5781
|
+
}
|
|
5611
5782
|
} catch (error) {
|
|
5612
5783
|
handleFileSystemError("write", error);
|
|
5613
5784
|
}
|
|
@@ -5801,16 +5972,18 @@ generateCmd.action(async (options, command) => {
|
|
|
5801
5972
|
try {
|
|
5802
5973
|
spinner.start(`Generating types...`);
|
|
5803
5974
|
const componentsData = await readComponentsFiles({
|
|
5804
|
-
...options,
|
|
5805
5975
|
from: space,
|
|
5806
|
-
path
|
|
5976
|
+
path,
|
|
5977
|
+
suffix: options.suffix,
|
|
5978
|
+
verbose
|
|
5807
5979
|
});
|
|
5808
5980
|
let dataSourceData;
|
|
5809
5981
|
try {
|
|
5810
5982
|
dataSourceData = await readDatasourcesFiles({
|
|
5811
|
-
...options,
|
|
5812
5983
|
from: space,
|
|
5813
|
-
path
|
|
5984
|
+
path,
|
|
5985
|
+
suffix: options.suffix,
|
|
5986
|
+
verbose
|
|
5814
5987
|
});
|
|
5815
5988
|
} catch (error) {
|
|
5816
5989
|
if (error instanceof FileSystemError && error.errorId === "file_not_found") {
|
|
@@ -5826,17 +5999,21 @@ generateCmd.action(async (options, command) => {
|
|
|
5826
5999
|
...componentsData,
|
|
5827
6000
|
...dataSourceData
|
|
5828
6001
|
};
|
|
5829
|
-
const
|
|
6002
|
+
const typedefData = await generateTypes(spaceDataWithComponentsAndDatasources, {
|
|
5830
6003
|
...options,
|
|
5831
6004
|
path
|
|
5832
6005
|
});
|
|
5833
|
-
if (
|
|
5834
|
-
await saveTypesToComponentsFile(space,
|
|
6006
|
+
if (typedefData) {
|
|
6007
|
+
await saveTypesToComponentsFile(space, typedefData, {
|
|
5835
6008
|
filename: options.filename,
|
|
5836
|
-
path
|
|
6009
|
+
path,
|
|
6010
|
+
separateFiles: options.separateFiles
|
|
5837
6011
|
});
|
|
5838
6012
|
}
|
|
5839
6013
|
spinner.succeed();
|
|
6014
|
+
if (options.separateFiles && options.filename) {
|
|
6015
|
+
konsola.warn(`The --filename option is ignored when using --separate-files`);
|
|
6016
|
+
}
|
|
5840
6017
|
konsola.ok(`Successfully generated types for space ${space}`, true);
|
|
5841
6018
|
konsola.br();
|
|
5842
6019
|
} catch (error) {
|
|
@@ -7302,31 +7479,25 @@ const readLocalAssetsStream = ({
|
|
|
7302
7479
|
const iterator = async function* readAssets() {
|
|
7303
7480
|
try {
|
|
7304
7481
|
const files = await readdir(directoryPath);
|
|
7305
|
-
const
|
|
7306
|
-
setTotalAssets?.(
|
|
7307
|
-
for (const file of
|
|
7308
|
-
const
|
|
7482
|
+
const binaryFiles = files.filter((f) => SUPPORTED_ASSET_EXTENSIONS.has(extname(f).toLowerCase()));
|
|
7483
|
+
setTotalAssets?.(binaryFiles.length);
|
|
7484
|
+
for (const file of binaryFiles) {
|
|
7485
|
+
const binaryFilePath = join(directoryPath, file);
|
|
7309
7486
|
try {
|
|
7310
|
-
const
|
|
7311
|
-
|
|
7312
|
-
continue;
|
|
7313
|
-
}
|
|
7314
|
-
const metadataContent = await readFile$1(filePath, "utf8");
|
|
7315
|
-
const assetRaw = JSON.parse(metadataContent);
|
|
7487
|
+
const sidecar = await loadSidecarAssetData(binaryFilePath);
|
|
7488
|
+
const shortFilename = sidecar.short_filename || (sidecar.filename ? basename(sidecar.filename) : void 0) || file;
|
|
7316
7489
|
const asset = {
|
|
7317
|
-
...
|
|
7318
|
-
short_filename:
|
|
7490
|
+
...sidecar,
|
|
7491
|
+
short_filename: shortFilename
|
|
7319
7492
|
};
|
|
7320
|
-
const
|
|
7321
|
-
const
|
|
7322
|
-
const assetBinaryPath = join(directoryPath, `${baseName}${extFromMetadata}`);
|
|
7323
|
-
const fileBuffer = await readFile$1(assetBinaryPath);
|
|
7493
|
+
const fileBuffer = await readFile$1(binaryFilePath);
|
|
7494
|
+
const sidecarPath = getSidecarFilename(binaryFilePath);
|
|
7324
7495
|
yield {
|
|
7325
7496
|
asset,
|
|
7326
7497
|
context: {
|
|
7327
7498
|
fileBuffer,
|
|
7328
|
-
assetBinaryPath,
|
|
7329
|
-
assetPath:
|
|
7499
|
+
assetBinaryPath: binaryFilePath,
|
|
7500
|
+
assetPath: sidecarPath
|
|
7330
7501
|
}
|
|
7331
7502
|
};
|
|
7332
7503
|
} catch (maybeError) {
|
|
@@ -7710,6 +7881,9 @@ const traverseAndMapBySchema = (data, {
|
|
|
7710
7881
|
processedFields,
|
|
7711
7882
|
missingSchemas
|
|
7712
7883
|
}) => {
|
|
7884
|
+
if (!data?.component) {
|
|
7885
|
+
return data ?? {};
|
|
7886
|
+
}
|
|
7713
7887
|
const schema = schemas[data.component];
|
|
7714
7888
|
if (!schema) {
|
|
7715
7889
|
missingSchemas.add(data.component);
|
|
@@ -7753,7 +7927,7 @@ const traverseAndMapRichtextDoc = (data, {
|
|
|
7753
7927
|
}));
|
|
7754
7928
|
}
|
|
7755
7929
|
if (data && typeof data === "object") {
|
|
7756
|
-
if (data.type === "link" && data.attrs
|
|
7930
|
+
if (data.type === "link" && data.attrs?.linktype === "story") {
|
|
7757
7931
|
return {
|
|
7758
7932
|
...data,
|
|
7759
7933
|
attrs: {
|
|
@@ -7767,7 +7941,7 @@ const traverseAndMapRichtextDoc = (data, {
|
|
|
7767
7941
|
...data,
|
|
7768
7942
|
attrs: {
|
|
7769
7943
|
...data.attrs,
|
|
7770
|
-
body: data.attrs
|
|
7944
|
+
body: (data.attrs?.body ?? []).map((d) => traverseAndMapBySchema(d, {
|
|
7771
7945
|
schemas,
|
|
7772
7946
|
maps,
|
|
7773
7947
|
fieldRefMappers: fieldRefMappers2,
|
|
@@ -7809,7 +7983,7 @@ const multilinkFieldRefMapper = (data, { maps }) => {
|
|
|
7809
7983
|
};
|
|
7810
7984
|
const bloksFieldRefMapper = (data, { schemas, maps, fieldRefMappers: fieldRefMappers2, processedFields, missingSchemas }) => {
|
|
7811
7985
|
if (!Array.isArray(data)) {
|
|
7812
|
-
throw new TypeError(
|
|
7986
|
+
throw new TypeError(`Invalid bloks field: expected an array, but received ${JSON.stringify(data)}. Please make sure your bloks field value is an array of components (e.g. [{ component: "my_blok", ... }]).`);
|
|
7813
7987
|
}
|
|
7814
7988
|
return data.map((d) => traverseAndMapBySchema(d, {
|
|
7815
7989
|
schemas,
|
|
@@ -7828,7 +8002,7 @@ const assetFieldRefMapper = (data, { maps }) => {
|
|
|
7828
8002
|
};
|
|
7829
8003
|
const multiassetFieldRefMapper = (data, options) => {
|
|
7830
8004
|
if (!Array.isArray(data)) {
|
|
7831
|
-
throw new TypeError(
|
|
8005
|
+
throw new TypeError(`Invalid multiasset field: expected an array, but received ${JSON.stringify(data)}. Please make sure your multiasset field value is an array of asset objects (e.g. [{ filename: "...", id: 123 }]).`);
|
|
7832
8006
|
}
|
|
7833
8007
|
return data.map((d) => assetFieldRefMapper(d, options));
|
|
7834
8008
|
};
|
|
@@ -7851,23 +8025,23 @@ const storyRefMapper = (story, { schemas, maps }) => {
|
|
|
7851
8025
|
const missingSchemas = /* @__PURE__ */ new Set();
|
|
7852
8026
|
const alternates = story.alternates ? story.alternates.map((a) => ({
|
|
7853
8027
|
...a,
|
|
7854
|
-
id: maps.stories?.get(a.id)
|
|
7855
|
-
parent_id: maps.stories?.get(a.parent_id)
|
|
8028
|
+
id: maps.stories?.get(a.id) ?? a.id,
|
|
8029
|
+
parent_id: maps.stories?.get(a.parent_id) ?? a.parent_id
|
|
7856
8030
|
})) : story.alternates;
|
|
7857
|
-
const parentId = maps.stories?.get(story.parent_id)
|
|
8031
|
+
const parentId = maps.stories?.get(story.parent_id) ?? story.parent_id;
|
|
7858
8032
|
const mappedStory = {
|
|
7859
8033
|
...story,
|
|
7860
|
-
content: traverseAndMapBySchema(story.content, {
|
|
8034
|
+
content: story.content?.component ? traverseAndMapBySchema(story.content, {
|
|
7861
8035
|
schemas,
|
|
7862
8036
|
maps,
|
|
7863
8037
|
fieldRefMappers,
|
|
7864
8038
|
processedFields,
|
|
7865
8039
|
missingSchemas
|
|
7866
|
-
}),
|
|
7867
|
-
id: Number(maps.stories?.get(story.id)
|
|
7868
|
-
uuid: String(maps.stories?.get(story.uuid)
|
|
8040
|
+
}) : story.content,
|
|
8041
|
+
id: Number(maps.stories?.get(story.id) ?? story.id),
|
|
8042
|
+
uuid: String(maps.stories?.get(story.uuid) ?? story.uuid),
|
|
7869
8043
|
// @ts-expect-error Our types are wrong.
|
|
7870
|
-
parent_id: parentId ? Number(parentId) : null,
|
|
8044
|
+
parent_id: parentId != null ? Number(parentId) : null,
|
|
7871
8045
|
alternates
|
|
7872
8046
|
};
|
|
7873
8047
|
return {
|
|
@@ -8029,14 +8203,14 @@ const getRemoteStory = async ({ spaceId, storyId }) => {
|
|
|
8029
8203
|
return data?.story;
|
|
8030
8204
|
};
|
|
8031
8205
|
const makeCreateStoryAPITransport = ({ spaceId }) => async (localStory) => {
|
|
8032
|
-
const { id: _id, uuid: _uuid,
|
|
8206
|
+
const { id: _id, uuid: _uuid, parent_id: _parentId, content, ...newStoryData } = localStory;
|
|
8207
|
+
if (!localStory.is_folder && !content?.component) {
|
|
8208
|
+
throw new Error(`Story "${localStory.slug}" is missing a content type (content.component). Every story must define a content field with a valid component.`);
|
|
8209
|
+
}
|
|
8033
8210
|
const remoteStory = await createStory(spaceId, {
|
|
8034
8211
|
story: {
|
|
8035
8212
|
...newStoryData,
|
|
8036
|
-
content: {
|
|
8037
|
-
_uid: "",
|
|
8038
|
-
component: "__tmp__"
|
|
8039
|
-
}
|
|
8213
|
+
...content?.component ? { content: { _uid: "", component: "__migration_artifact__" } } : {}
|
|
8040
8214
|
},
|
|
8041
8215
|
publish: 0
|
|
8042
8216
|
});
|
|
@@ -8112,7 +8286,7 @@ const makeWriteStoryFSTransport = ({ directoryPath }) => async (story) => {
|
|
|
8112
8286
|
};
|
|
8113
8287
|
const makeWriteStoryAPITransport = ({ spaceId, publish }) => (mappedLocalStory) => updateStory(spaceId, mappedLocalStory.id, {
|
|
8114
8288
|
story: mappedLocalStory,
|
|
8115
|
-
publish: publish ?? (mappedLocalStory
|
|
8289
|
+
publish: publish ?? (isStoryPublishedWithoutChanges(mappedLocalStory) ? 1 : 0)
|
|
8116
8290
|
});
|
|
8117
8291
|
const makeCleanupStoryFSTransport = ({ directoryPath, maps }) => async (mappedStory) => {
|
|
8118
8292
|
const mapEntry = maps.stories?.entries().find(([_, v]) => v === mappedStory.uuid);
|
|
@@ -8738,14 +8912,14 @@ pushCmd.action(async (options, command) => {
|
|
|
8738
8912
|
processProgress.setTotal(total);
|
|
8739
8913
|
updateProgress.setTotal(total);
|
|
8740
8914
|
},
|
|
8741
|
-
onStoryError(error) {
|
|
8915
|
+
onStoryError(error, filename) {
|
|
8742
8916
|
summary.creationResults.failed += 1;
|
|
8743
8917
|
summary.processResults.total -= 1;
|
|
8744
8918
|
summary.updateResults.total -= 1;
|
|
8745
8919
|
processProgress.setTotal(summary.processResults.total);
|
|
8746
8920
|
updateProgress.setTotal(summary.updateResults.total);
|
|
8747
8921
|
creationProgress.increment();
|
|
8748
|
-
handleError(error, verbose);
|
|
8922
|
+
handleError(error, verbose, { storyFile: filename });
|
|
8749
8923
|
}
|
|
8750
8924
|
}),
|
|
8751
8925
|
// Create remote stories.
|
|
@@ -8754,7 +8928,6 @@ pushCmd.action(async (options, command) => {
|
|
|
8754
8928
|
spaceId: space,
|
|
8755
8929
|
transports: {
|
|
8756
8930
|
createStory: options.dryRun ? async (story) => story : makeCreateStoryAPITransport({
|
|
8757
|
-
maps,
|
|
8758
8931
|
spaceId: space
|
|
8759
8932
|
}),
|
|
8760
8933
|
appendStoryManifest: options.dryRun ? () => Promise.resolve() : makeAppendToManifestFSTransport({
|
|
@@ -8779,13 +8952,13 @@ pushCmd.action(async (options, command) => {
|
|
|
8779
8952
|
logger.info("Skipped creating story", { storyId: localStory.uuid });
|
|
8780
8953
|
summary.creationResults.skipped += 1;
|
|
8781
8954
|
},
|
|
8782
|
-
onStoryError(error) {
|
|
8955
|
+
onStoryError(error, localStory) {
|
|
8783
8956
|
summary.creationResults.failed += 1;
|
|
8784
8957
|
summary.processResults.total -= 1;
|
|
8785
8958
|
summary.updateResults.total -= 1;
|
|
8786
8959
|
processProgress.setTotal(summary.processResults.total);
|
|
8787
8960
|
updateProgress.setTotal(summary.updateResults.total);
|
|
8788
|
-
handleError(error, verbose);
|
|
8961
|
+
handleError(error, verbose, { storyId: localStory?.uuid });
|
|
8789
8962
|
},
|
|
8790
8963
|
onIncrement() {
|
|
8791
8964
|
creationProgress.increment();
|
|
@@ -8805,13 +8978,13 @@ pushCmd.action(async (options, command) => {
|
|
|
8805
8978
|
processProgress.setTotal(total);
|
|
8806
8979
|
updateProgress.setTotal(total);
|
|
8807
8980
|
},
|
|
8808
|
-
onStoryError(error) {
|
|
8981
|
+
onStoryError(error, filename) {
|
|
8809
8982
|
summary.creationResults.failed += 1;
|
|
8810
8983
|
summary.processResults.total -= 1;
|
|
8811
8984
|
summary.updateResults.total -= 1;
|
|
8812
8985
|
processProgress.setTotal(summary.processResults.total);
|
|
8813
8986
|
updateProgress.setTotal(summary.updateResults.total);
|
|
8814
|
-
handleError(error, verbose);
|
|
8987
|
+
handleError(error, verbose, { storyFile: filename });
|
|
8815
8988
|
}
|
|
8816
8989
|
}),
|
|
8817
8990
|
// Map all references to numeric ids and uuids.
|