@kontent-ai/migration-toolkit 2.9.1 → 3.0.0-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.
Files changed (235) hide show
  1. package/README.md +19 -17
  2. package/dist/core/config.js +3 -3
  3. package/dist/core/config.js.map +1 -1
  4. package/dist/core/helpers/workflow-helper.d.ts +1 -1
  5. package/dist/core/helpers/workflow-helper.js +28 -26
  6. package/dist/core/helpers/workflow-helper.js.map +1 -1
  7. package/dist/core/logs/loggers.d.ts +1 -1
  8. package/dist/core/logs/loggers.js +15 -15
  9. package/dist/core/logs/loggers.js.map +1 -1
  10. package/dist/core/models/core.models.d.ts +27 -22
  11. package/dist/core/models/error.models.d.ts +14 -0
  12. package/dist/core/models/error.models.js +25 -0
  13. package/dist/core/models/error.models.js.map +1 -0
  14. package/dist/core/models/log.models.d.ts +2 -2
  15. package/dist/core/models/migration.models.d.ts +14 -14
  16. package/dist/core/models/migration.schema.d.ts +9 -9
  17. package/dist/core/models/migration.schema.js +28 -28
  18. package/dist/core/models/migration.schema.js.map +1 -1
  19. package/dist/core/utils/array.utils.d.ts +1 -1
  20. package/dist/core/utils/array.utils.js +4 -3
  21. package/dist/core/utils/array.utils.js.map +1 -1
  22. package/dist/core/utils/binary-data.utils.d.ts +1 -1
  23. package/dist/core/utils/binary-data.utils.js +6 -6
  24. package/dist/core/utils/binary-data.utils.js.map +1 -1
  25. package/dist/core/utils/confirm.utils.d.ts +1 -1
  26. package/dist/core/utils/confirm.utils.js +21 -20
  27. package/dist/core/utils/confirm.utils.js.map +1 -1
  28. package/dist/core/utils/error.utils.d.ts +1 -1
  29. package/dist/core/utils/error.utils.js +16 -14
  30. package/dist/core/utils/error.utils.js.map +1 -1
  31. package/dist/core/utils/external-id.utils.js +1 -1
  32. package/dist/core/utils/external-id.utils.js.map +1 -1
  33. package/dist/core/utils/global.utils.d.ts +3 -3
  34. package/dist/core/utils/global.utils.js +20 -18
  35. package/dist/core/utils/global.utils.js.map +1 -1
  36. package/dist/core/utils/http.utils.d.ts +2 -2
  37. package/dist/core/utils/http.utils.js +4 -4
  38. package/dist/core/utils/http.utils.js.map +1 -1
  39. package/dist/core/utils/management-client-utils.d.ts +4 -4
  40. package/dist/core/utils/management-client-utils.js +34 -34
  41. package/dist/core/utils/management-client-utils.js.map +1 -1
  42. package/dist/core/utils/processing-utils.d.ts +4 -4
  43. package/dist/core/utils/processing-utils.js +13 -13
  44. package/dist/core/utils/processing-utils.js.map +1 -1
  45. package/dist/core/utils/run.utils.d.ts +2 -2
  46. package/dist/core/utils/run.utils.js +7 -7
  47. package/dist/core/utils/run.utils.js.map +1 -1
  48. package/dist/export/context/export-context-fetcher.d.ts +1 -1
  49. package/dist/export/context/export-context-fetcher.js +92 -62
  50. package/dist/export/context/export-context-fetcher.js.map +1 -1
  51. package/dist/export/export-manager.d.ts +2 -2
  52. package/dist/export/export-manager.js +46 -37
  53. package/dist/export/export-manager.js.map +1 -1
  54. package/dist/export/export.models.d.ts +21 -2
  55. package/dist/export/utils/export.utils.d.ts +1 -1
  56. package/dist/export/utils/export.utils.js +3 -2
  57. package/dist/export/utils/export.utils.js.map +1 -1
  58. package/dist/file/file-manager.d.ts +2 -2
  59. package/dist/file/file-manager.js +7 -7
  60. package/dist/file/file-manager.js.map +1 -1
  61. package/dist/import/comparers/asset-comparer.d.ts +2 -2
  62. package/dist/import/comparers/asset-comparer.js +12 -11
  63. package/dist/import/comparers/asset-comparer.js.map +1 -1
  64. package/dist/import/context/import-context-fetcher.d.ts +1 -1
  65. package/dist/import/context/import-context-fetcher.js +77 -73
  66. package/dist/import/context/import-context-fetcher.js.map +1 -1
  67. package/dist/import/import-manager.d.ts +1 -1
  68. package/dist/import/import-manager.js +59 -56
  69. package/dist/import/import-manager.js.map +1 -1
  70. package/dist/import/import.models.d.ts +6 -2
  71. package/dist/import/importers/assets-importer.d.ts +3 -3
  72. package/dist/import/importers/assets-importer.js +46 -43
  73. package/dist/import/importers/assets-importer.js.map +1 -1
  74. package/dist/import/importers/content-items-importer.d.ts +3 -3
  75. package/dist/import/importers/content-items-importer.js +28 -25
  76. package/dist/import/importers/content-items-importer.js.map +1 -1
  77. package/dist/import/importers/language-variant-importer.d.ts +3 -3
  78. package/dist/import/importers/language-variant-importer.js +45 -45
  79. package/dist/import/importers/language-variant-importer.js.map +1 -1
  80. package/dist/import/importers/workflow-importer.d.ts +3 -2
  81. package/dist/import/importers/workflow-importer.js +58 -54
  82. package/dist/import/importers/workflow-importer.js.map +1 -1
  83. package/dist/import/utils/import.utils.d.ts +1 -1
  84. package/dist/import/utils/import.utils.js +3 -2
  85. package/dist/import/utils/import.utils.js.map +1 -1
  86. package/dist/index.d.ts +11 -7
  87. package/dist/index.js +10 -8
  88. package/dist/index.js.map +1 -1
  89. package/dist/metadata.js +3 -3
  90. package/dist/metadata.js.map +1 -1
  91. package/dist/node/cli/actions/export-action.d.ts +1 -1
  92. package/dist/node/cli/actions/export-action.js +28 -23
  93. package/dist/node/cli/actions/export-action.js.map +1 -1
  94. package/dist/node/cli/actions/import-action.d.ts +1 -1
  95. package/dist/node/cli/actions/import-action.js +15 -12
  96. package/dist/node/cli/actions/import-action.js.map +1 -1
  97. package/dist/node/cli/actions/migrate-action.d.ts +1 -1
  98. package/dist/node/cli/actions/migrate-action.js +25 -22
  99. package/dist/node/cli/actions/migrate-action.js.map +1 -1
  100. package/dist/node/cli/app.js +13 -12
  101. package/dist/node/cli/app.js.map +1 -1
  102. package/dist/node/cli/args/args-fetcher.d.ts +1 -1
  103. package/dist/node/cli/args/args-fetcher.js +14 -13
  104. package/dist/node/cli/args/args-fetcher.js.map +1 -1
  105. package/dist/node/cli/args/args-setter.d.ts +1 -1
  106. package/dist/node/cli/args/args-setter.js +8 -6
  107. package/dist/node/cli/args/args-setter.js.map +1 -1
  108. package/dist/node/cli/cli.models.d.ts +2 -2
  109. package/dist/node/cli/commands.js +68 -56
  110. package/dist/node/cli/commands.js.map +1 -1
  111. package/dist/toolkit/elements-builder.d.ts +1 -1
  112. package/dist/toolkit/elements-builder.js +12 -12
  113. package/dist/toolkit/elements-builder.js.map +1 -1
  114. package/dist/toolkit/export.d.ts +2 -2
  115. package/dist/toolkit/export.js +8 -8
  116. package/dist/toolkit/export.js.map +1 -1
  117. package/dist/toolkit/file.d.ts +2 -1
  118. package/dist/toolkit/file.js +18 -16
  119. package/dist/toolkit/file.js.map +1 -1
  120. package/dist/toolkit/import.d.ts +1 -1
  121. package/dist/toolkit/import.js +12 -12
  122. package/dist/toolkit/import.js.map +1 -1
  123. package/dist/toolkit/migrate.d.ts +13 -4
  124. package/dist/toolkit/migrate.js +15 -13
  125. package/dist/toolkit/migrate.js.map +1 -1
  126. package/dist/translation/extraction/items-extraction.processor.d.ts +5 -4
  127. package/dist/translation/extraction/items-extraction.processor.js +73 -35
  128. package/dist/translation/extraction/items-extraction.processor.js.map +1 -1
  129. package/dist/translation/helpers/export-placeholder.utils.d.ts +11 -0
  130. package/dist/translation/helpers/export-placeholder.utils.js +11 -0
  131. package/dist/translation/helpers/export-placeholder.utils.js.map +1 -0
  132. package/dist/translation/helpers/rich-text.processor.d.ts +6 -6
  133. package/dist/translation/helpers/rich-text.processor.js +38 -38
  134. package/dist/translation/helpers/rich-text.processor.js.map +1 -1
  135. package/dist/translation/transforms/export-transforms.d.ts +2 -2
  136. package/dist/translation/transforms/export-transforms.js +93 -67
  137. package/dist/translation/transforms/export-transforms.js.map +1 -1
  138. package/dist/translation/transforms/import-transforms.d.ts +2 -2
  139. package/dist/translation/transforms/import-transforms.js +38 -40
  140. package/dist/translation/transforms/import-transforms.js.map +1 -1
  141. package/dist/zip/zip-manager.d.ts +4 -3
  142. package/dist/zip/zip-manager.js +9 -9
  143. package/dist/zip/zip-manager.js.map +1 -1
  144. package/dist/zip/zip-packager.d.ts +2 -2
  145. package/dist/zip/zip-packager.js +19 -17
  146. package/dist/zip/zip-packager.js.map +1 -1
  147. package/dist/zip/zip-transformer.d.ts +3 -2
  148. package/dist/zip/zip-transformer.js +16 -15
  149. package/dist/zip/zip-transformer.js.map +1 -1
  150. package/dist/zip/zip.models.d.ts +2 -2
  151. package/lib/core/config.ts +6 -6
  152. package/lib/core/helpers/workflow-helper.ts +190 -185
  153. package/lib/core/logs/loggers.ts +52 -52
  154. package/lib/core/models/core.models.ts +128 -119
  155. package/lib/core/models/error.models.ts +41 -0
  156. package/lib/core/models/log.models.ts +20 -20
  157. package/lib/core/models/migration.models.ts +54 -54
  158. package/lib/core/models/migration.schema.ts +108 -108
  159. package/lib/core/utils/array.utils.ts +43 -42
  160. package/lib/core/utils/binary-data.utils.ts +16 -16
  161. package/lib/core/utils/confirm.utils.ts +106 -105
  162. package/lib/core/utils/error.utils.ts +69 -72
  163. package/lib/core/utils/external-id.utils.ts +4 -4
  164. package/lib/core/utils/global.utils.ts +81 -75
  165. package/lib/core/utils/http.utils.ts +23 -23
  166. package/lib/core/utils/management-client-utils.ts +186 -186
  167. package/lib/core/utils/processing-utils.ts +82 -82
  168. package/lib/core/utils/run.utils.ts +50 -50
  169. package/lib/export/context/export-context-fetcher.ts +472 -447
  170. package/lib/export/export-manager.ts +233 -232
  171. package/lib/export/export.models.ts +71 -56
  172. package/lib/export/utils/export.utils.ts +9 -7
  173. package/lib/file/file-manager.ts +28 -28
  174. package/lib/import/comparers/asset-comparer.ts +107 -106
  175. package/lib/import/context/import-context-fetcher.ts +462 -462
  176. package/lib/import/import-manager.ts +243 -240
  177. package/lib/import/import.models.ts +69 -67
  178. package/lib/import/importers/assets-importer.ts +240 -236
  179. package/lib/import/importers/content-items-importer.ts +126 -122
  180. package/lib/import/importers/language-variant-importer.ts +324 -328
  181. package/lib/import/importers/workflow-importer.ts +372 -367
  182. package/lib/import/utils/import.utils.ts +9 -7
  183. package/lib/index.ts +12 -8
  184. package/lib/metadata.ts +3 -4
  185. package/lib/node/cli/actions/export-action.ts +43 -38
  186. package/lib/node/cli/actions/import-action.ts +32 -29
  187. package/lib/node/cli/actions/migrate-action.ts +49 -46
  188. package/lib/node/cli/app.ts +21 -21
  189. package/lib/node/cli/args/args-fetcher.ts +55 -54
  190. package/lib/node/cli/args/args-setter.ts +34 -32
  191. package/lib/node/cli/cli.models.ts +17 -17
  192. package/lib/node/cli/commands.ts +165 -153
  193. package/lib/toolkit/elements-builder.ts +69 -69
  194. package/lib/toolkit/export.ts +21 -21
  195. package/lib/toolkit/file.ts +59 -53
  196. package/lib/toolkit/import.ts +32 -32
  197. package/lib/toolkit/migrate.ts +60 -49
  198. package/lib/translation/extraction/items-extraction.processor.ts +203 -173
  199. package/lib/translation/helpers/export-placeholder.utils.ts +10 -0
  200. package/lib/translation/helpers/rich-text.processor.ts +311 -311
  201. package/lib/translation/transforms/export-transforms.ts +313 -279
  202. package/lib/translation/transforms/import-transforms.ts +188 -191
  203. package/lib/zip/zip-manager.ts +28 -27
  204. package/lib/zip/zip-packager.ts +75 -73
  205. package/lib/zip/zip-transformer.ts +112 -107
  206. package/lib/zip/zip.models.ts +7 -7
  207. package/package.json +91 -84
  208. package/dist/core/index.d.ts +0 -16
  209. package/dist/core/index.js +0 -17
  210. package/dist/core/index.js.map +0 -1
  211. package/dist/export/index.d.ts +0 -2
  212. package/dist/export/index.js +0 -3
  213. package/dist/export/index.js.map +0 -1
  214. package/dist/file/index.d.ts +0 -1
  215. package/dist/file/index.js +0 -2
  216. package/dist/file/index.js.map +0 -1
  217. package/dist/import/index.d.ts +0 -2
  218. package/dist/import/index.js +0 -3
  219. package/dist/import/index.js.map +0 -1
  220. package/dist/toolkit/index.d.ts +0 -5
  221. package/dist/toolkit/index.js +0 -6
  222. package/dist/toolkit/index.js.map +0 -1
  223. package/dist/translation/index.d.ts +0 -4
  224. package/dist/translation/index.js +0 -5
  225. package/dist/translation/index.js.map +0 -1
  226. package/dist/zip/index.d.ts +0 -4
  227. package/dist/zip/index.js +0 -5
  228. package/dist/zip/index.js.map +0 -1
  229. package/lib/core/index.ts +0 -18
  230. package/lib/export/index.ts +0 -2
  231. package/lib/file/index.ts +0 -1
  232. package/lib/import/index.ts +0 -2
  233. package/lib/toolkit/index.ts +0 -5
  234. package/lib/translation/index.ts +0 -4
  235. package/lib/zip/index.ts +0 -4
@@ -1,453 +1,478 @@
1
1
  import type {
2
- AssetModels,
3
- CollectionModels,
4
- ContentItemModels,
5
- LanguageModels,
6
- LanguageVariantModels,
7
- WorkflowModels
8
- } from '@kontent-ai/management-sdk';
9
- import chalk from 'chalk';
2
+ AssetModels,
3
+ CollectionModels,
4
+ ContentItemModels,
5
+ LanguageModels,
6
+ LanguageVariantModels,
7
+ WorkflowModels,
8
+ } from "@kontent-ai/management-sdk";
9
+ import chalk from "chalk";
10
+ import { workflowHelper } from "../../core/helpers/workflow-helper.js";
10
11
  import type {
11
- AssetStateInSourceEnvironmentById,
12
- FlattenedContentType,
13
- ItemStateInSourceEnvironmentById,
14
- LogSpinnerData
15
- } from '../../core/index.js';
16
- import {
17
- findRequired,
18
- is404Error,
19
- managementClientUtils,
20
- processItemsAsync,
21
- runMapiRequestAsync,
22
- workflowHelper
23
- } from '../../core/index.js';
24
- import { itemsExtractionProcessor } from '../../translation/index.js';
12
+ AssetStateInSourceEnvironmentById,
13
+ FlattenedContentType,
14
+ ItemStateInSourceEnvironmentById,
15
+ } from "../../core/models/core.models.js";
16
+ import type { LogSpinnerData } from "../../core/models/log.models.js";
17
+ import { findRequired } from "../../core/utils/array.utils.js";
18
+ import { is404Error } from "../../core/utils/error.utils.js";
19
+ import { managementClientUtils } from "../../core/utils/management-client-utils.js";
20
+ import { processItemsAsync } from "../../core/utils/processing-utils.js";
21
+ import { runMapiRequestAsync } from "../../core/utils/run.utils.js";
22
+ import { itemsExtractionProcessor } from "../../translation/extraction/items-extraction.processor.js";
25
23
  import type {
26
- DefaultExportContextConfig,
27
- ExportContext,
28
- ExportContextEnvironmentData,
29
- ExportItem,
30
- ExportItemVersion,
31
- GetFlattenedElementByIds,
32
- SourceExportItem
33
- } from '../export.models.js';
34
- import { throwErrorForItemRequest } from '../utils/export.utils.js';
24
+ DefaultExportContextConfig,
25
+ ExportContext,
26
+ ExportContextEnvironmentData,
27
+ ExportItem,
28
+ ExportItemVersion,
29
+ GetFlattenedElementByIds,
30
+ SourceExportItem,
31
+ } from "../export.models.js";
32
+ import { throwErrorForItemRequest } from "../utils/export.utils.js";
35
33
 
36
34
  export async function exportContextFetcherAsync(config: DefaultExportContextConfig) {
37
- const getEnvironmentDataAsync = async (): Promise<ExportContextEnvironmentData> => {
38
- const mapiUtils = managementClientUtils(config.managementClient, config.logger);
39
-
40
- return await config.logger.logWithSpinnerAsync(async (spinnerData) => {
41
- spinnerData({ type: 'info', message: `Loading environment data` });
42
-
43
- const environmentData: ExportContextEnvironmentData = {
44
- collections: await mapiUtils.getAllCollectionsAsync(spinnerData),
45
- contentTypes: await mapiUtils.getFlattenedContentTypesAsync(spinnerData),
46
- languages: await mapiUtils.getAllLanguagesAsync(spinnerData),
47
- workflows: await mapiUtils.getAllWorkflowsAsync(spinnerData),
48
- taxonomies: await mapiUtils.getAllTaxonomiesAsync(spinnerData),
49
- assetFolders: await mapiUtils.getAllAssetFoldersAsync(spinnerData)
50
- };
51
-
52
- spinnerData({ type: 'info', message: `Environmental data loaded` });
53
-
54
- return environmentData;
55
- });
56
- };
57
-
58
- const environmentData = await getEnvironmentDataAsync();
59
-
60
- const getContentItemAsync = async (
61
- sourceItem: SourceExportItem,
62
- logSpinner: LogSpinnerData
63
- ): Promise<Readonly<ContentItemModels.ContentItem>> => {
64
- return await runMapiRequestAsync({
65
- logger: config.logger,
66
- logSpinner: logSpinner,
67
- func: async () => {
68
- return (await config.managementClient.viewContentItem().byItemCodename(sourceItem.itemCodename).toPromise()).data;
69
- },
70
- action: 'view',
71
- type: 'contentItem',
72
- itemName: `codename -> ${sourceItem.itemCodename}`
73
- });
74
- };
75
-
76
- const getLatestLanguageVariantAsync = async (
77
- sourceItem: SourceExportItem,
78
- logSpinner: LogSpinnerData
79
- ): Promise<Readonly<LanguageVariantModels.ContentItemLanguageVariant>> => {
80
- return await runMapiRequestAsync({
81
- logger: config.logger,
82
- logSpinner: logSpinner,
83
- func: async () => {
84
- return (
85
- await config.managementClient
86
- .viewLanguageVariant()
87
- .byItemCodename(sourceItem.itemCodename)
88
- .byLanguageCodename(sourceItem.languageCodename)
89
- .toPromise()
90
- ).data;
91
- },
92
-
93
- action: 'view',
94
- type: 'languageVariant',
95
- itemName: `codename -> ${sourceItem.itemCodename} -> latest (${sourceItem.languageCodename})`
96
- });
97
- };
98
-
99
- const isLanguageVariantPublished = (languageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant>): boolean => {
100
- return environmentData.workflows.find((workflow) => workflow.publishedStep.id === languageVariant.workflow.stepIdentifier.id)
101
- ? true
102
- : false;
103
- };
104
-
105
- const mapToExportVersionItem = (
106
- sourceItem: SourceExportItem,
107
- contentItem: Readonly<ContentItemModels.ContentItem>,
108
- languageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant>
109
- ): ExportItemVersion => {
110
- return {
111
- languageVariant: languageVariant,
112
- workflowStepCodename: validateExportItem({
113
- sourceItem: sourceItem,
114
- contentItem: contentItem,
115
- languageVariant: languageVariant
116
- }).workflowStepCodename
117
- };
118
- };
119
-
120
- const getExportItemVersionsAsync = async (
121
- sourceItem: SourceExportItem,
122
- contentItem: Readonly<ContentItemModels.ContentItem>,
123
- logSpinner: LogSpinnerData
124
- ): Promise<readonly ExportItemVersion[]> => {
125
- const latestLanguageVariant = await getLatestLanguageVariantAsync(sourceItem, logSpinner);
126
- const latestExportVersion = mapToExportVersionItem(sourceItem, contentItem, latestLanguageVariant);
127
-
128
- if (isLanguageVariantPublished(latestLanguageVariant)) {
129
- // latest language variant is also published = no need to fetch published version
130
- return [latestExportVersion];
131
- }
132
-
133
- const publishedLanguageVariant = await getPublishedLanguageVariantAsync(sourceItem, logSpinner);
134
-
135
- if (!publishedLanguageVariant) {
136
- return [latestExportVersion];
137
- }
138
-
139
- return [latestExportVersion, mapToExportVersionItem(sourceItem, contentItem, publishedLanguageVariant)];
140
- };
141
-
142
- const getPublishedLanguageVariantAsync = async (
143
- sourceItem: SourceExportItem,
144
- logSpinner: LogSpinnerData
145
- ): Promise<Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined> => {
146
- return await runMapiRequestAsync({
147
- logger: config.logger,
148
- logSpinner: logSpinner,
149
- func: async () => {
150
- try {
151
- return (
152
- await config.managementClient
153
- .viewLanguageVariant()
154
- .byItemCodename(sourceItem.itemCodename)
155
- .byLanguageCodename(sourceItem.languageCodename)
156
- .published()
157
- .toPromise()
158
- ).data;
159
- } catch (error) {
160
- if (is404Error(error)) {
161
- return undefined;
162
- }
163
- throw error;
164
- }
165
- },
166
- action: 'view',
167
- type: 'languageVariant',
168
- itemName: `codename -> ${sourceItem.itemCodename} -> published (${sourceItem.languageCodename})`
169
- });
170
- };
171
-
172
- const validateExportItem = (data: {
173
- readonly sourceItem: SourceExportItem;
174
- readonly contentItem: Readonly<ContentItemModels.ContentItem>;
175
- readonly languageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant>;
176
- }): {
177
- readonly collection: Readonly<CollectionModels.Collection>;
178
- readonly language: Readonly<LanguageModels.LanguageModel>;
179
- readonly workflow: Readonly<WorkflowModels.Workflow>;
180
- readonly contentType: Readonly<FlattenedContentType>;
181
- readonly workflowStepCodename: string;
182
- } => {
183
- const collection = findRequired(
184
- environmentData.collections,
185
- (collection) => collection.id === data.contentItem.collection.id,
186
- () => {
187
- throwErrorForItemRequest(data.sourceItem, `Invalid collection '${chalk.yellow(data.contentItem.collection.id ?? '')}'`);
188
- }
189
- );
190
-
191
- const contentType = findRequired(
192
- environmentData.contentTypes,
193
- (contentType) => contentType.contentTypeId === data.contentItem.type.id,
194
- () => {
195
- throwErrorForItemRequest(data.sourceItem, `Invalid content type '${chalk.red(data.contentItem.type.id)}'`);
196
- }
197
- );
198
-
199
- const language = findRequired(
200
- environmentData.languages,
201
- (language) => language.id === data.languageVariant.language.id,
202
- () => {
203
- throwErrorForItemRequest(data.sourceItem, `Invalid language '${chalk.red(data.languageVariant.language.id ?? '')}'`);
204
- }
205
- );
206
-
207
- const workflow = findRequired(
208
- environmentData.workflows,
209
- (workflow) => workflow.id === data.languageVariant.workflow.workflowIdentifier.id,
210
- () => {
211
- throwErrorForItemRequest(
212
- data.sourceItem,
213
- `Invalid workflow '${chalk.red(data.languageVariant.workflow.workflowIdentifier.id ?? '')}'`
214
- );
215
- }
216
- );
217
-
218
- const workflowStep = workflowHelper(environmentData.workflows).getWorkflowStep(workflow, {
219
- match: (step) => step.id === data.languageVariant.workflow.stepIdentifier.id,
220
- errorMessage: `Invalid workflow step '${chalk.red(data.languageVariant.workflow.stepIdentifier.id ?? '')}'`
221
- });
222
-
223
- return {
224
- collection,
225
- language,
226
- workflow,
227
- contentType,
228
- workflowStepCodename: workflowStep.codename
229
- };
230
- };
231
-
232
- const prepareExportItemsAsync = async (exportItems: readonly SourceExportItem[]): Promise<readonly ExportItem[]> => {
233
- config.logger.log({
234
- type: 'info',
235
- message: `Preparing '${chalk.yellow(config.exportItems.length.toString())}' items for export`
236
- });
237
-
238
- return (
239
- await processItemsAsync<SourceExportItem, ExportItem>({
240
- logger: config.logger,
241
- action: 'Preparing content items & language variants',
242
- parallelLimit: 1,
243
- itemInfo: (input) => {
244
- return {
245
- title: `${input.itemCodename} (${input.languageCodename})`,
246
- itemType: 'exportItem'
247
- };
248
- },
249
- items: exportItems,
250
- processAsync: async (requestItem, logSpinner) => {
251
- const contentItem = await getContentItemAsync(requestItem, logSpinner);
252
- const versions = await getExportItemVersionsAsync(requestItem, contentItem, logSpinner);
253
-
254
- // get shared attributes from any version
255
- const anyVersion = versions[0];
256
- if (!anyVersion) {
257
- throwErrorForItemRequest(requestItem, `Expected at least 1 version of the content item`);
258
- }
259
-
260
- const { collection, contentType, language, workflow } = validateExportItem({
261
- sourceItem: requestItem,
262
- contentItem: contentItem,
263
- languageVariant: anyVersion.languageVariant
264
- });
265
-
266
- return {
267
- contentItem,
268
- versions,
269
- contentType,
270
- requestItem,
271
- workflow,
272
- collection,
273
- language
274
- };
275
- }
276
- })
277
- )
278
- .filter((m) => m.state === 'valid')
279
- .map((m) => m.outputItem);
280
- };
281
-
282
- const getContentItemsByIdsAsync = async (itemIds: ReadonlySet<string>): Promise<readonly Readonly<ContentItemModels.ContentItem>[]> => {
283
- return (
284
- await processItemsAsync<string, Readonly<ContentItemModels.ContentItem>>({
285
- logger: config.logger,
286
- action: 'Fetching content items',
287
- parallelLimit: 1,
288
- items: Array.from(itemIds),
289
- itemInfo: (id) => {
290
- return {
291
- itemType: 'contentItem',
292
- title: id
293
- };
294
- },
295
- processAsync: async (id, logSpinner) => {
296
- try {
297
- return await runMapiRequestAsync({
298
- logSpinner: logSpinner,
299
- logger: config.logger,
300
- func: async () => (await config.managementClient.viewContentItem().byItemId(id).toPromise()).data,
301
- action: 'view',
302
- type: 'contentItem',
303
- itemName: `id -> ${id}`
304
- });
305
- } catch (error) {
306
- if (!is404Error(error)) {
307
- throw error;
308
- }
309
-
310
- return '404';
311
- }
312
- }
313
- })
314
- )
315
- .filter((m) => m.state === 'valid')
316
- .map((m) => m.outputItem);
317
- };
318
-
319
- const getAssetsByIdsAsync = async (itemIds: ReadonlySet<string>): Promise<readonly Readonly<AssetModels.Asset>[]> => {
320
- return (
321
- await processItemsAsync<string, Readonly<AssetModels.Asset>>({
322
- logger: config.logger,
323
- action: 'Fetching assets',
324
- parallelLimit: 1,
325
- items: Array.from(itemIds),
326
- itemInfo: (id) => {
327
- return {
328
- itemType: 'asset',
329
- title: id
330
- };
331
- },
332
- processAsync: async (id, logSpinner) => {
333
- try {
334
- return await runMapiRequestAsync({
335
- logger: config.logger,
336
- logSpinner: logSpinner,
337
- func: async () => (await config.managementClient.viewAsset().byAssetId(id).toPromise()).data,
338
- action: 'view',
339
- type: 'asset',
340
- itemName: `id -> ${id}`
341
- });
342
- } catch (error) {
343
- if (!is404Error(error)) {
344
- throw error;
345
- }
346
-
347
- return '404';
348
- }
349
- }
350
- })
351
- )
352
- .filter((m) => m.state === 'valid')
353
- .map((m) => m.outputItem);
354
- };
355
-
356
- const getItemStatesAsync = async (itemIds: ReadonlySet<string>): Promise<readonly ItemStateInSourceEnvironmentById[]> => {
357
- const items = await getContentItemsByIdsAsync(itemIds);
358
-
359
- return Array.from(itemIds).map<ItemStateInSourceEnvironmentById>((itemId) => {
360
- const item = items.find((m) => m.id === itemId);
361
- return {
362
- id: itemId,
363
- item: item,
364
- state: item ? 'exists' : 'doesNotExists'
365
- };
366
- });
367
- };
368
-
369
- const getAssetStatesAsync = async (assetIds: ReadonlySet<string>): Promise<readonly AssetStateInSourceEnvironmentById[]> => {
370
- const assets = await getAssetsByIdsAsync(assetIds);
371
-
372
- return Array.from(assetIds).map<AssetStateInSourceEnvironmentById>((assetId) => {
373
- const asset = assets.find((m) => m.id === assetId);
374
- return {
375
- id: assetId,
376
- asset: asset,
377
- state: asset ? 'exists' : 'doesNotExists'
378
- };
379
- });
380
- };
381
-
382
- const getElementByIds = (): GetFlattenedElementByIds => {
383
- const getFunc: GetFlattenedElementByIds = (contentTypeId: string, elementId: string) => {
384
- const contentType = findRequired(
385
- environmentData.contentTypes,
386
- (contentType) => contentType.contentTypeId === contentTypeId,
387
- `Could not find content type with id '${chalk.red(contentTypeId)}'`
388
- );
389
-
390
- const element = findRequired(
391
- contentType.elements,
392
- (element) => element.id === elementId,
393
- `Could not find element with id '${chalk.red(elementId)}' in content type '${chalk.red(contentType.contentTypeCodename)}'`
394
- );
395
-
396
- return element;
397
- };
398
-
399
- return getFunc;
400
- };
401
-
402
- const getExportContextAsync = async (): Promise<ExportContext> => {
403
- const preparedItems = await prepareExportItemsAsync(config.exportItems);
404
-
405
- config.logger.log({
406
- type: 'info',
407
- message: `Extracting referenced items & assets from content`
408
- });
409
-
410
- const referencedData = itemsExtractionProcessor().extractReferencedDataFromExtractItems(
411
- preparedItems.map((exportItem) => {
412
- return {
413
- contentTypeId: exportItem.contentType.contentTypeId,
414
- elements: exportItem.versions.flatMap((m) => m.languageVariant).flatMap((s) => s.elements)
415
- };
416
- }),
417
- getElementByIds()
418
- );
419
-
420
- const itemStates: readonly ItemStateInSourceEnvironmentById[] = await getItemStatesAsync(
421
- // fetch both referenced items and items that are set to be exported
422
- new Set<string>([...referencedData.itemIds, ...preparedItems.map((m) => m.contentItem.id)])
423
- );
424
- const assetStates: readonly AssetStateInSourceEnvironmentById[] = await getAssetStatesAsync(
425
- new Set<string>([...referencedData.assetIds])
426
- );
427
-
428
- const exportContext: ExportContext = {
429
- getElement: getElementByIds(),
430
- exportItems: preparedItems,
431
- environmentData: environmentData,
432
- referencedData: referencedData,
433
- getAssetStateInSourceEnvironment: (id) =>
434
- findRequired(
435
- assetStates,
436
- (m) => m.id === id,
437
- `Invalid state for asset '${chalk.red(id)}'. It is expected that all asset states will be initialized`
438
- ),
439
- getItemStateInSourceEnvironment: (id) =>
440
- findRequired(
441
- itemStates,
442
- (m) => m.id === id,
443
- `Invalid state for item '${chalk.red(id)}'. It is expected that all item states will be initialized`
444
- )
445
- };
446
-
447
- return exportContext;
448
- };
449
-
450
- return {
451
- getExportContextAsync
452
- };
35
+ const getEnvironmentDataAsync = async (): Promise<ExportContextEnvironmentData> => {
36
+ const mapiUtils = managementClientUtils(config.managementClient, config.logger);
37
+
38
+ return await config.logger.logWithSpinnerAsync(async (spinnerData) => {
39
+ spinnerData({ type: "info", message: `Loading environment data` });
40
+
41
+ const environmentData: ExportContextEnvironmentData = {
42
+ collections: await mapiUtils.getAllCollectionsAsync(spinnerData),
43
+ contentTypes: await mapiUtils.getFlattenedContentTypesAsync(spinnerData),
44
+ languages: await mapiUtils.getAllLanguagesAsync(spinnerData),
45
+ workflows: await mapiUtils.getAllWorkflowsAsync(spinnerData),
46
+ taxonomies: await mapiUtils.getAllTaxonomiesAsync(spinnerData),
47
+ assetFolders: await mapiUtils.getAllAssetFoldersAsync(spinnerData),
48
+ };
49
+
50
+ spinnerData({ type: "info", message: `Environmental data loaded` });
51
+
52
+ return environmentData;
53
+ });
54
+ };
55
+
56
+ const environmentData = await getEnvironmentDataAsync();
57
+
58
+ const getContentItemAsync = async (
59
+ sourceItem: SourceExportItem,
60
+ logSpinner: LogSpinnerData,
61
+ ): Promise<Readonly<ContentItemModels.ContentItem>> => {
62
+ return await runMapiRequestAsync({
63
+ logger: config.logger,
64
+ logSpinner: logSpinner,
65
+ func: async () => {
66
+ return (await config.managementClient.viewContentItem().byItemCodename(sourceItem.itemCodename).toPromise()).data;
67
+ },
68
+ action: "view",
69
+ type: "contentItem",
70
+ itemName: `codename -> ${sourceItem.itemCodename}`,
71
+ });
72
+ };
73
+
74
+ const getLatestLanguageVariantAsync = async (
75
+ sourceItem: SourceExportItem,
76
+ logSpinner: LogSpinnerData,
77
+ ): Promise<Readonly<LanguageVariantModels.ContentItemLanguageVariant>> => {
78
+ return await runMapiRequestAsync({
79
+ logger: config.logger,
80
+ logSpinner: logSpinner,
81
+ func: async () => {
82
+ return (
83
+ await config.managementClient
84
+ .viewLanguageVariant()
85
+ .byItemCodename(sourceItem.itemCodename)
86
+ .byLanguageCodename(sourceItem.languageCodename)
87
+ .toPromise()
88
+ ).data;
89
+ },
90
+
91
+ action: "view",
92
+ type: "languageVariant",
93
+ itemName: `codename -> ${sourceItem.itemCodename} -> latest (${sourceItem.languageCodename})`,
94
+ });
95
+ };
96
+
97
+ const isLanguageVariantPublished = (languageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant>): boolean => {
98
+ return environmentData.workflows.some((workflow) => workflow.publishedStep.id === languageVariant.workflow.stepIdentifier.id);
99
+ };
100
+
101
+ const mapToExportVersionItem = (
102
+ sourceItem: SourceExportItem,
103
+ contentItem: Readonly<ContentItemModels.ContentItem>,
104
+ languageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant>,
105
+ ): ExportItemVersion => {
106
+ return {
107
+ languageVariant: languageVariant,
108
+ workflowStepCodename: validateExportItem({
109
+ sourceItem: sourceItem,
110
+ contentItem: contentItem,
111
+ languageVariant: languageVariant,
112
+ }).workflowStepCodename,
113
+ };
114
+ };
115
+
116
+ const getExportItemVersionsAsync = async (
117
+ sourceItem: SourceExportItem,
118
+ contentItem: Readonly<ContentItemModels.ContentItem>,
119
+ logSpinner: LogSpinnerData,
120
+ ): Promise<readonly ExportItemVersion[]> => {
121
+ const latestLanguageVariant = await getLatestLanguageVariantAsync(sourceItem, logSpinner);
122
+ const latestExportVersion = mapToExportVersionItem(sourceItem, contentItem, latestLanguageVariant);
123
+
124
+ if (isLanguageVariantPublished(latestLanguageVariant)) {
125
+ // latest language variant is also published = no need to fetch published version
126
+ return [latestExportVersion];
127
+ }
128
+
129
+ const publishedLanguageVariant = await getPublishedLanguageVariantAsync(sourceItem, logSpinner);
130
+
131
+ if (!publishedLanguageVariant) {
132
+ return [latestExportVersion];
133
+ }
134
+
135
+ return [latestExportVersion, mapToExportVersionItem(sourceItem, contentItem, publishedLanguageVariant)];
136
+ };
137
+
138
+ const getPublishedLanguageVariantAsync = async (
139
+ sourceItem: SourceExportItem,
140
+ logSpinner: LogSpinnerData,
141
+ ): Promise<Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined> => {
142
+ return await runMapiRequestAsync({
143
+ logger: config.logger,
144
+ logSpinner: logSpinner,
145
+ func: async () => {
146
+ try {
147
+ return (
148
+ await config.managementClient
149
+ .viewLanguageVariant()
150
+ .byItemCodename(sourceItem.itemCodename)
151
+ .byLanguageCodename(sourceItem.languageCodename)
152
+ .published()
153
+ .toPromise()
154
+ ).data;
155
+ } catch (error) {
156
+ if (is404Error(error)) {
157
+ return undefined;
158
+ }
159
+ throw error;
160
+ }
161
+ },
162
+ action: "view",
163
+ type: "languageVariant",
164
+ itemName: `codename -> ${sourceItem.itemCodename} -> published (${sourceItem.languageCodename})`,
165
+ });
166
+ };
167
+
168
+ const validateExportItem = (data: {
169
+ readonly sourceItem: SourceExportItem;
170
+ readonly contentItem: Readonly<ContentItemModels.ContentItem>;
171
+ readonly languageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant>;
172
+ }): {
173
+ readonly collection: Readonly<CollectionModels.Collection>;
174
+ readonly language: Readonly<LanguageModels.LanguageModel>;
175
+ readonly workflow: Readonly<WorkflowModels.Workflow>;
176
+ readonly contentType: Readonly<FlattenedContentType>;
177
+ readonly workflowStepCodename: string;
178
+ } => {
179
+ const collection = findRequired(
180
+ environmentData.collections,
181
+ (collection) => collection.id === data.contentItem.collection.id,
182
+ () => {
183
+ throwErrorForItemRequest(data.sourceItem, `Invalid collection '${chalk.yellow(data.contentItem.collection.id)}'`);
184
+ },
185
+ );
186
+
187
+ const contentType = findRequired(
188
+ environmentData.contentTypes,
189
+ (contentType) => contentType.contentTypeId === data.contentItem.type.id,
190
+ () => {
191
+ throwErrorForItemRequest(data.sourceItem, `Invalid content type '${chalk.red(data.contentItem.type.id)}'`);
192
+ },
193
+ );
194
+
195
+ const language = findRequired(
196
+ environmentData.languages,
197
+ (language) => language.id === data.languageVariant.language.id,
198
+ () => {
199
+ throwErrorForItemRequest(data.sourceItem, `Invalid language '${chalk.red(data.languageVariant.language.id ?? "")}'`);
200
+ },
201
+ );
202
+
203
+ const workflow = findRequired(
204
+ environmentData.workflows,
205
+ (workflow) => workflow.id === data.languageVariant.workflow.workflowIdentifier.id,
206
+ () => {
207
+ throwErrorForItemRequest(
208
+ data.sourceItem,
209
+ `Invalid workflow '${chalk.red(data.languageVariant.workflow.workflowIdentifier.id ?? "")}'`,
210
+ );
211
+ },
212
+ );
213
+
214
+ const workflowStep = workflowHelper(environmentData.workflows).getWorkflowStep(workflow, {
215
+ match: (step) => step.id === data.languageVariant.workflow.stepIdentifier.id,
216
+ errorMessage: `Invalid workflow step '${chalk.red(data.languageVariant.workflow.stepIdentifier.id ?? "")}'`,
217
+ });
218
+
219
+ return {
220
+ collection,
221
+ language,
222
+ workflow,
223
+ contentType,
224
+ workflowStepCodename: workflowStep.codename,
225
+ };
226
+ };
227
+
228
+ const prepareExportItemsAsync = async (exportItems: readonly SourceExportItem[]): Promise<readonly ExportItem[]> => {
229
+ config.logger.log({
230
+ type: "info",
231
+ message: `Preparing '${chalk.yellow(config.exportItems.length.toString())}' items for export`,
232
+ });
233
+
234
+ return (
235
+ await processItemsAsync<SourceExportItem, ExportItem>({
236
+ logger: config.logger,
237
+ action: "Preparing content items & language variants",
238
+ parallelLimit: 1,
239
+ itemInfo: (input) => {
240
+ return {
241
+ title: `${input.itemCodename} (${input.languageCodename})`,
242
+ itemType: "exportItem",
243
+ };
244
+ },
245
+ items: exportItems,
246
+ processAsync: async (requestItem, logSpinner) => {
247
+ const contentItem = await getContentItemAsync(requestItem, logSpinner);
248
+ const versions = await getExportItemVersionsAsync(requestItem, contentItem, logSpinner);
249
+
250
+ // get shared attributes from any version
251
+ const anyVersion = versions.length ? versions[0] : undefined;
252
+ if (!anyVersion) {
253
+ throwErrorForItemRequest(requestItem, `Expected at least 1 version of the content item`);
254
+ }
255
+
256
+ const { collection, contentType, language, workflow } = validateExportItem({
257
+ sourceItem: requestItem,
258
+ contentItem: contentItem,
259
+ languageVariant: anyVersion.languageVariant,
260
+ });
261
+
262
+ return {
263
+ contentItem,
264
+ versions,
265
+ contentType,
266
+ requestItem,
267
+ workflow,
268
+ collection,
269
+ language,
270
+ };
271
+ },
272
+ })
273
+ )
274
+ .filter((m) => m.state === "valid")
275
+ .map((m) => m.outputItem);
276
+ };
277
+
278
+ const getContentItemsByIdsAsync = async (itemIds: ReadonlySet<string>): Promise<readonly Readonly<ContentItemModels.ContentItem>[]> => {
279
+ return (
280
+ await processItemsAsync<string, Readonly<ContentItemModels.ContentItem>>({
281
+ logger: config.logger,
282
+ action: "Fetching content items",
283
+ parallelLimit: 1,
284
+ items: Array.from(itemIds),
285
+ itemInfo: (id) => {
286
+ return {
287
+ itemType: "contentItem",
288
+ title: id,
289
+ };
290
+ },
291
+ processAsync: async (id, logSpinner) => {
292
+ try {
293
+ return await runMapiRequestAsync({
294
+ logSpinner: logSpinner,
295
+ logger: config.logger,
296
+ func: async () => (await config.managementClient.viewContentItem().byItemId(id).toPromise()).data,
297
+ action: "view",
298
+ type: "contentItem",
299
+ itemName: `id -> ${id}`,
300
+ });
301
+ } catch (error) {
302
+ if (!is404Error(error)) {
303
+ throw error;
304
+ }
305
+
306
+ return "404";
307
+ }
308
+ },
309
+ })
310
+ )
311
+ .filter((m) => m.state === "valid")
312
+ .map((m) => m.outputItem);
313
+ };
314
+
315
+ const getAssetsByIdsAsync = async (itemIds: ReadonlySet<string>): Promise<readonly Readonly<AssetModels.Asset>[]> => {
316
+ return (
317
+ await processItemsAsync<string, Readonly<AssetModels.Asset>>({
318
+ logger: config.logger,
319
+ action: "Fetching assets",
320
+ parallelLimit: 1,
321
+ items: Array.from(itemIds),
322
+ itemInfo: (id) => {
323
+ return {
324
+ itemType: "asset",
325
+ title: id,
326
+ };
327
+ },
328
+ processAsync: async (id, logSpinner) => {
329
+ try {
330
+ return await runMapiRequestAsync({
331
+ logger: config.logger,
332
+ logSpinner: logSpinner,
333
+ func: async () => (await config.managementClient.viewAsset().byAssetId(id).toPromise()).data,
334
+ action: "view",
335
+ type: "asset",
336
+ itemName: `id -> ${id}`,
337
+ });
338
+ } catch (error) {
339
+ if (!is404Error(error)) {
340
+ throw error;
341
+ }
342
+
343
+ return "404";
344
+ }
345
+ },
346
+ })
347
+ )
348
+ .filter((m) => m.state === "valid")
349
+ .map((m) => m.outputItem);
350
+ };
351
+
352
+ const getItemStatesAsync = async (itemIds: ReadonlySet<string>): Promise<readonly ItemStateInSourceEnvironmentById[]> => {
353
+ const items = await getContentItemsByIdsAsync(itemIds);
354
+
355
+ return Array.from(itemIds).map<ItemStateInSourceEnvironmentById>((itemId) => {
356
+ const item = items.find((m) => m.id === itemId);
357
+
358
+ if (item) {
359
+ return {
360
+ id: itemId,
361
+ data: item,
362
+ state: "exists",
363
+ };
364
+ }
365
+ if (config.skipMissingReferences) {
366
+ return {
367
+ id: itemId,
368
+ state: "skip",
369
+ };
370
+ }
371
+ return {
372
+ id: itemId,
373
+ state: "doesNotExists",
374
+ };
375
+ });
376
+ };
377
+
378
+ const getAssetStatesAsync = async (assetIds: ReadonlySet<string>): Promise<readonly AssetStateInSourceEnvironmentById[]> => {
379
+ const assets = await getAssetsByIdsAsync(assetIds);
380
+
381
+ return Array.from(assetIds).map<AssetStateInSourceEnvironmentById>((assetId) => {
382
+ const asset = assets.find((m) => m.id === assetId);
383
+
384
+ if (asset) {
385
+ return {
386
+ id: assetId,
387
+ data: asset,
388
+ state: "exists",
389
+ };
390
+ }
391
+ if (config.skipMissingReferences) {
392
+ return {
393
+ id: assetId,
394
+ state: "skip",
395
+ };
396
+ }
397
+ return {
398
+ id: assetId,
399
+ state: "doesNotExists",
400
+ };
401
+ });
402
+ };
403
+
404
+ const getElementByIds = (): GetFlattenedElementByIds => {
405
+ const getFunc: GetFlattenedElementByIds = (contentTypeId: string, elementId: string) => {
406
+ const contentType = findRequired(
407
+ environmentData.contentTypes,
408
+ (contentType) => contentType.contentTypeId === contentTypeId,
409
+ `Could not find content type with id '${chalk.red(contentTypeId)}'`,
410
+ );
411
+
412
+ const element = findRequired(
413
+ contentType.elements,
414
+ (element) => element.id === elementId,
415
+ `Could not find element with id '${chalk.red(elementId)}' in content type '${chalk.red(contentType.contentTypeCodename)}'`,
416
+ );
417
+
418
+ return element;
419
+ };
420
+
421
+ return getFunc;
422
+ };
423
+
424
+ const getExportContextAsync = async (): Promise<ExportContext> => {
425
+ const preparedItems = await prepareExportItemsAsync(config.exportItems);
426
+
427
+ config.logger.log({
428
+ type: "info",
429
+ message: `Extracting referenced items & assets from content`,
430
+ });
431
+
432
+ const referencedData = itemsExtractionProcessor().extractReferencedDataFromExtractItems(
433
+ preparedItems.map((exportItem) => {
434
+ return {
435
+ contentTypeId: exportItem.contentType.contentTypeId,
436
+ elements: exportItem.versions.flatMap((m) => m.languageVariant).flatMap((s) => s.elements),
437
+ };
438
+ }),
439
+ getElementByIds(),
440
+ );
441
+
442
+ const itemStates: readonly ItemStateInSourceEnvironmentById[] = await getItemStatesAsync(
443
+ // fetch both referenced items and items that are set to be exported
444
+ new Set<string>([...referencedData.itemIds, ...preparedItems.map((m) => m.contentItem.id)]),
445
+ );
446
+ const assetStates: readonly AssetStateInSourceEnvironmentById[] = await getAssetStatesAsync(
447
+ new Set<string>([...referencedData.assetIds]),
448
+ );
449
+
450
+ const exportContext: ExportContext = {
451
+ getElement: getElementByIds(),
452
+ exportItems: preparedItems,
453
+ environmentData: environmentData,
454
+ referencedData: referencedData,
455
+ exportContextOptions: {
456
+ skipMissingReferences: config.skipMissingReferences,
457
+ },
458
+ getAssetStateInSourceEnvironment: (id) =>
459
+ findRequired(
460
+ assetStates,
461
+ (m) => m.id === id,
462
+ `Invalid state for asset '${chalk.red(id)}'. It is expected that all asset states will be initialized`,
463
+ ),
464
+ getItemStateInSourceEnvironment: (id) =>
465
+ findRequired(
466
+ itemStates,
467
+ (m) => m.id === id,
468
+ `Invalid state for item '${chalk.red(id)}'. It is expected that all item states will be initialized`,
469
+ ),
470
+ };
471
+
472
+ return exportContext;
473
+ };
474
+
475
+ return {
476
+ getExportContextAsync,
477
+ };
453
478
  }