@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,469 +1,469 @@
1
- import type { AssetModels, ContentItemModels, LanguageVariantModels } from '@kontent-ai/management-sdk';
2
- import chalk from 'chalk';
3
- import { match } from 'ts-pattern';
1
+ import type { AssetModels, ContentItemModels, LanguageVariantModels } from "@kontent-ai/management-sdk";
2
+ import chalk from "chalk";
3
+ import { match } from "ts-pattern";
4
+ import type { WorkflowStep } from "../../core/helpers/workflow-helper.js";
5
+ import { workflowHelper as workflowHelperInit } from "../../core/helpers/workflow-helper.js";
4
6
  import type {
5
- AssetStateInTargetEnvironmentByCodename,
6
- ItemStateInTargetEnvironmentByCodename,
7
- LanguageVariantSchedulesStateValues,
8
- LanguageVariantStateData,
9
- LanguageVariantStateInTargetEnvironmentByCodename,
10
- LanguageVariantWorkflowState,
11
- LanguageVariantWorkflowStateValues,
12
- LogSpinnerData,
13
- MigrationItem,
14
- WorkflowStep
15
- } from '../../core/index.js';
16
- import {
17
- findRequired,
18
- is404Error,
19
- managementClientUtils,
20
- processItemsAsync,
21
- runMapiRequestAsync,
22
- workflowHelper as workflowHelperInit
23
- } from '../../core/index.js';
24
- import type { ExtractItemByCodename } from '../../translation/index.js';
25
- import { itemsExtractionProcessor } from '../../translation/index.js';
26
- import type { GetFlattenedElementByCodenames, ImportContext, ImportContextConfig, ImportContextEnvironmentData } from '../import.models.js';
7
+ AssetStateInTargetEnvironmentByCodename,
8
+ ItemStateInTargetEnvironmentByCodename,
9
+ LanguageVariantSchedulesStateValues,
10
+ LanguageVariantStateData,
11
+ LanguageVariantStateInTargetEnvironmentByCodename,
12
+ LanguageVariantWorkflowState,
13
+ LanguageVariantWorkflowStateValues,
14
+ } from "../../core/models/core.models.js";
15
+ import { MigrationToolkitError } from "../../core/models/error.models.js";
16
+ import type { LogSpinnerData } from "../../core/models/log.models.js";
17
+ import type { MigrationItem } from "../../core/models/migration.models.js";
18
+ import { findRequired } from "../../core/utils/array.utils.js";
19
+ import { is404Error } from "../../core/utils/error.utils.js";
20
+ import { managementClientUtils } from "../../core/utils/management-client-utils.js";
21
+ import { processItemsAsync } from "../../core/utils/processing-utils.js";
22
+ import { runMapiRequestAsync } from "../../core/utils/run.utils.js";
23
+ import { type ExtractItemByCodename, itemsExtractionProcessor } from "../../translation/extraction/items-extraction.processor.js";
24
+ import type { GetFlattenedElementByCodenames, ImportContext, ImportContextConfig, ImportContextEnvironmentData } from "../import.models.js";
27
25
 
28
26
  interface LanguageVariantWrapper {
29
- readonly draftLanguageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined;
30
- readonly publishedLanguageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined;
31
- readonly migrationItem: MigrationItem;
27
+ readonly draftLanguageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined;
28
+ readonly publishedLanguageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined;
29
+ readonly migrationItem: MigrationItem;
32
30
  }
33
31
 
34
32
  export async function importContextFetcherAsync(config: ImportContextConfig) {
35
- const getEnvironmentDataAsync = async (): Promise<ImportContextEnvironmentData> => {
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: ImportContextEnvironmentData = {
42
- collections: await mapiUtils.getAllCollectionsAsync(spinnerData),
43
- languages: await mapiUtils.getAllLanguagesAsync(spinnerData),
44
- workflows: await mapiUtils.getAllWorkflowsAsync(spinnerData),
45
- types: await mapiUtils.getFlattenedContentTypesAsync(spinnerData),
46
- assetFolders: await mapiUtils.getAllAssetFoldersAsync(spinnerData)
47
- };
48
-
49
- spinnerData({ type: 'info', message: `Environmental data loaded` });
50
-
51
- return environmentData;
52
- });
53
- };
54
-
55
- const environmentData = await getEnvironmentDataAsync();
56
- const workflowHelper = workflowHelperInit(environmentData.workflows);
57
-
58
- const getElement = () => {
59
- const getFlattenedElement: GetFlattenedElementByCodenames = (contentTypeCodename, elementCodename, sourceType) => {
60
- const contentType = findRequired(
61
- environmentData.types,
62
- (type) => type.contentTypeCodename === contentTypeCodename,
63
- `Content type with codename '${chalk.red(contentTypeCodename)}' was not found.`
64
- );
65
-
66
- const element = findRequired(
67
- contentType.elements,
68
- (element) => element.codename === elementCodename,
69
- `Element type with codename '${chalk.red(elementCodename)}' was not found in content type '${chalk.red(
70
- contentTypeCodename
71
- )}'. Available elements are '${contentType.elements.map((element) => chalk.yellow(element.codename)).join(', ')}'`
72
- );
73
-
74
- if (sourceType !== element.type) {
75
- throw Error(
76
- `Element '${chalk.red(element.codename)}' in content type '${chalk.yellow(
77
- contentType.contentTypeCodename
78
- )}' is of type '${chalk.red(element.type)}', but source type is '${chalk.yellow(sourceType)}'.`
79
- );
80
- }
81
-
82
- return element;
83
- };
84
-
85
- return getFlattenedElement;
86
- };
87
-
88
- const getLatestLanguageVariantAsync = async (
89
- logSpinner: LogSpinnerData,
90
- migrationItem: MigrationItem
91
- ): Promise<Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined> => {
92
- try {
93
- const latestLanguageVariant = await runMapiRequestAsync({
94
- logger: config.logger,
95
- func: async () =>
96
- (
97
- await config.managementClient
98
- .viewLanguageVariant()
99
- .byItemCodename(migrationItem.system.codename)
100
- .byLanguageCodename(migrationItem.system.language.codename)
101
- .toPromise()
102
- ).data,
103
- action: 'view',
104
- type: 'languageVariant',
105
- logSpinner: logSpinner,
106
- itemName: `latest -> codename -> ${migrationItem.system.codename} (${migrationItem.system.language.codename})`
107
- });
108
-
109
- return latestLanguageVariant;
110
- } catch (error) {
111
- if (!is404Error(error)) {
112
- throw error;
113
- }
114
-
115
- return undefined;
116
- }
117
- };
118
-
119
- const getPublishedLanguageVariantAsync = async (
120
- logSpinner: LogSpinnerData,
121
- migrationItem: MigrationItem
122
- ): Promise<Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined> => {
123
- try {
124
- const draftLanguageVariant = await runMapiRequestAsync({
125
- logger: config.logger,
126
- func: async () =>
127
- (
128
- await config.managementClient
129
- .viewLanguageVariant()
130
- .byItemCodename(migrationItem.system.codename)
131
- .byLanguageCodename(migrationItem.system.language.codename)
132
- .published()
133
- .toPromise()
134
- ).data,
135
- action: 'view',
136
- type: 'languageVariant',
137
- logSpinner: logSpinner,
138
- itemName: `published -> codename -> ${migrationItem.system.codename} (${migrationItem.system.language.codename})`
139
- });
140
-
141
- return draftLanguageVariant;
142
- } catch (error) {
143
- if (!is404Error(error)) {
144
- throw error;
145
- }
146
-
147
- return undefined;
148
- }
149
- };
150
-
151
- const getLanguageVariantWrappersAsync = async (
152
- migrationItems: readonly MigrationItem[]
153
- ): Promise<readonly LanguageVariantWrapper[]> => {
154
- return (
155
- await processItemsAsync<MigrationItem, LanguageVariantWrapper>({
156
- action: 'Fetching language variants',
157
- logger: config.logger,
158
- parallelLimit: 1,
159
- items: migrationItems,
160
- itemInfo: (item) => {
161
- return {
162
- itemType: 'languageVariant',
163
- title: `${item.system.codename} (${item.system.language.codename})`
164
- };
165
- },
166
- processAsync: async (item, logSpinner) => {
167
- const latestLanguageVariant = await getLatestLanguageVariantAsync(logSpinner, item);
168
-
169
- if (!latestLanguageVariant) {
170
- // there is neither published or draft version as latest version does not exist at all
171
- return '404';
172
- }
173
-
174
- if (workflowHelper.isPublishedStepById(latestLanguageVariant.workflow.stepIdentifier.id ?? '')) {
175
- // if latest version is published, it means that there is no draft, but there is published version
176
- return {
177
- migrationItem: item,
178
- draftLanguageVariant: undefined,
179
- publishedLanguageVariant: latestLanguageVariant
180
- };
181
- }
182
-
183
- // if latest version is a draft version, check if there is published version as well
184
- return {
185
- migrationItem: item,
186
- draftLanguageVariant: latestLanguageVariant,
187
- publishedLanguageVariant: await getPublishedLanguageVariantAsync(logSpinner, item)
188
- };
189
- }
190
- })
191
- )
192
- .filter((m) => m.state === 'valid')
193
- .map((m) => m.outputItem);
194
- };
195
-
196
- const getContentItemsByCodenamesAsync = async (
197
- itemCodenames: ReadonlySet<string>
198
- ): Promise<readonly ContentItemModels.ContentItem[]> => {
199
- return (
200
- await processItemsAsync<string, Readonly<ContentItemModels.ContentItem>>({
201
- action: 'Fetching content items',
202
- logger: config.logger,
203
- parallelLimit: 1,
204
- items: Array.from(itemCodenames),
205
- itemInfo: (codename) => {
206
- return {
207
- itemType: 'contentItem',
208
- title: codename
209
- };
210
- },
211
- processAsync: async (codename, logSpinner) => {
212
- try {
213
- return await runMapiRequestAsync({
214
- logger: config.logger,
215
- func: async () => (await config.managementClient.viewContentItem().byItemCodename(codename).toPromise()).data,
216
- action: 'view',
217
- type: 'contentItem',
218
- logSpinner: logSpinner,
219
- itemName: `codename -> ${codename}`
220
- });
221
- } catch (error) {
222
- if (!is404Error(error)) {
223
- throw error;
224
- }
225
-
226
- return '404';
227
- }
228
- }
229
- })
230
- )
231
- .filter((m) => m.state === 'valid')
232
- .map((m) => m.outputItem);
233
- };
234
-
235
- const getAssetsByCodenamesAsync = async (assetCodenames: ReadonlySet<string>): Promise<readonly AssetModels.Asset[]> => {
236
- return (
237
- await processItemsAsync<string, Readonly<AssetModels.Asset>>({
238
- action: 'Fetching assets',
239
- logger: config.logger,
240
- parallelLimit: 1,
241
- items: Array.from(assetCodenames),
242
- itemInfo: (codename) => {
243
- return {
244
- itemType: 'asset',
245
- title: codename
246
- };
247
- },
248
- processAsync: async (codename, logSpinner) => {
249
- try {
250
- return await runMapiRequestAsync({
251
- logger: config.logger,
252
- func: async () => (await config.managementClient.viewAsset().byAssetCodename(codename).toPromise()).data,
253
- action: 'view',
254
- type: 'asset',
255
- logSpinner: logSpinner,
256
- itemName: `codename -> ${codename}`
257
- });
258
- } catch (error) {
259
- if (!is404Error(error)) {
260
- throw error;
261
- }
262
-
263
- return '404';
264
- }
265
- }
266
- })
267
- )
268
- .filter((m) => m.state === 'valid')
269
- .map((m) => m.outputItem);
270
- };
271
-
272
- const getVariantState = (languageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant>): LanguageVariantStateData => {
273
- const variantWorkflowId = languageVariant.workflow.workflowIdentifier.id;
274
- const variantStepId = languageVariant.workflow.stepIdentifier.id;
275
- const { workflow, step } = workflowHelper.getWorkflowAndStep({
276
- workflowMatcher: {
277
- errorMessage: `Could not workflow with id '${chalk.red(variantWorkflowId)}' in target project`,
278
- match: (workflow) => workflow.id == variantWorkflowId
279
- },
280
- stepMatcher: {
281
- errorMessage: `Could not workflow step with id '${chalk.red(variantStepId)}' in workflow '${chalk.yellow(
282
- variantWorkflowId
283
- )}'`,
284
- match: (step) => step.id == variantStepId
285
- }
286
- });
287
-
288
- return {
289
- languageVariant: languageVariant,
290
- workflow: workflow,
291
- workflowState: getWorkflowState(step, languageVariant)
292
- };
293
- };
294
-
295
- const getVariantStatesAsync = async (
296
- migrationItems: readonly MigrationItem[]
297
- ): Promise<readonly LanguageVariantStateInTargetEnvironmentByCodename[]> => {
298
- const variantWrappers = await getLanguageVariantWrappersAsync(migrationItems);
299
-
300
- return migrationItems.map<LanguageVariantStateInTargetEnvironmentByCodename>((migrationItem) => {
301
- const variantWrapper = variantWrappers.find(
302
- (m) =>
303
- m.migrationItem.system.codename === migrationItem.system.codename &&
304
- m.migrationItem.system.language === migrationItem.system.language
305
- );
306
-
307
- return {
308
- itemCodename: migrationItem.system.codename,
309
- languageCodename: migrationItem.system.language.codename,
310
- draftLanguageVariant: variantWrapper?.draftLanguageVariant
311
- ? getVariantState(variantWrapper.draftLanguageVariant)
312
- : undefined,
313
- publishedLanguageVariant: variantWrapper?.publishedLanguageVariant
314
- ? getVariantState(variantWrapper.publishedLanguageVariant)
315
- : undefined,
316
- state: variantWrapper ? 'exists' : 'doesNotExists'
317
- };
318
- });
319
- };
320
-
321
- const getWorkflowState = (
322
- step: Readonly<WorkflowStep>,
323
- variant: Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined
324
- ): LanguageVariantWorkflowState => {
325
- if (!variant) {
326
- return undefined;
327
- }
328
-
329
- const getScheduledState = (): LanguageVariantSchedulesStateValues => {
330
- return match(variant.schedule)
331
- .returnType<LanguageVariantSchedulesStateValues>()
332
- .when(
333
- (schedule) => schedule.publishTime && schedule.publishDisplayTimezone,
334
- () => 'scheduledPublish'
335
- )
336
- .when(
337
- (schedule) => schedule.unpublishTime && schedule.unpublishDisplayTimezone,
338
- () => 'scheduledUnpublish'
339
- )
340
- .otherwise(() => 'n/a');
341
- };
342
-
343
- const getWorkflowState = (): LanguageVariantWorkflowStateValues => {
344
- return match(step.codename)
345
- .returnType<LanguageVariantWorkflowStateValues>()
346
- .when(
347
- (stepCodename) => workflowHelper.isPublishedStepByCodename(stepCodename),
348
- () => 'published'
349
- )
350
- .when(
351
- (stepCodename) => workflowHelper.isArchivedStepByCodename(stepCodename),
352
- () => 'archived'
353
- )
354
- .otherwise(() => 'draft');
355
- };
356
-
357
- return {
358
- workflowState: getWorkflowState(),
359
- scheduledState: getScheduledState()
360
- };
361
- };
362
-
363
- const getItemStatesAsync = async (itemCodenames: ReadonlySet<string>): Promise<readonly ItemStateInTargetEnvironmentByCodename[]> => {
364
- const items = await getContentItemsByCodenamesAsync(itemCodenames);
365
-
366
- return Array.from(itemCodenames).map<ItemStateInTargetEnvironmentByCodename>((codename) => {
367
- const item = items.find((m) => m.codename === codename);
368
- return {
369
- itemCodename: codename,
370
- item: item,
371
- state: item ? 'exists' : 'doesNotExists',
372
- externalIdToUse: config.externalIdGenerator.contentItemExternalId(codename)
373
- };
374
- });
375
- };
376
-
377
- const getAssetStatesAsync = async (
378
- assetCodenames: ReadonlySet<string>
379
- ): Promise<readonly AssetStateInTargetEnvironmentByCodename[]> => {
380
- const assets = await getAssetsByCodenamesAsync(assetCodenames);
381
-
382
- return Array.from(assetCodenames).map<AssetStateInTargetEnvironmentByCodename>((codename) => {
383
- const asset = assets.find((m) => m.codename === codename);
384
- return {
385
- assetCodename: codename,
386
- asset: asset,
387
- state: asset ? 'exists' : 'doesNotExists',
388
- externalIdToUse: config.externalIdGenerator.assetExternalId(codename)
389
- };
390
- });
391
- };
392
-
393
- const getImportContextAsync = async (): Promise<ImportContext> => {
394
- const getElementByCodenames: GetFlattenedElementByCodenames = getElement();
395
-
396
- const referencedData = itemsExtractionProcessor().extractReferencedItemsFromMigrationItems(
397
- config.migrationData.items.reduce<ExtractItemByCodename[]>((items, item) => {
398
- return [
399
- ...items,
400
- ...item.versions.map((version) => {
401
- const extractionItem: ExtractItemByCodename = {
402
- contentTypeCodename: item.system.type.codename,
403
- elements: version.elements
404
- };
405
- return extractionItem;
406
- })
407
- ];
408
- }, []),
409
- getElementByCodenames
410
- );
411
- // fetch all items, including referenced items in content
412
- const itemCodenamesToCheckInTargetEnv: ReadonlySet<string> = new Set<string>([
413
- ...referencedData.itemCodenames,
414
- ...config.migrationData.items.map((m) => m.system.codename)
415
- ]);
416
-
417
- // fetch all assets, including referenced assets in content
418
- const assetCodenamesToCheckInTargetEnv: ReadonlySet<string> = new Set<string>([
419
- ...referencedData.assetCodenames,
420
- ...config.migrationData.assets.map((m) => m.codename)
421
- ]);
422
-
423
- // prepare state of objects in target environment
424
- const itemStates: readonly ItemStateInTargetEnvironmentByCodename[] = await getItemStatesAsync(itemCodenamesToCheckInTargetEnv);
425
-
426
- const variantStates: readonly LanguageVariantStateInTargetEnvironmentByCodename[] = await getVariantStatesAsync(
427
- config.migrationData.items
428
- );
429
-
430
- const assetStates: readonly AssetStateInTargetEnvironmentByCodename[] = await getAssetStatesAsync(assetCodenamesToCheckInTargetEnv);
431
-
432
- return {
433
- environmentData,
434
- referencedData,
435
- categorizedImportData: {
436
- assets: config.migrationData.assets,
437
- contentItems: config.migrationData.items
438
- },
439
- getItemStateInTargetEnvironment: (itemCodename) => {
440
- return findRequired(
441
- itemStates,
442
- (state) => state.itemCodename === itemCodename,
443
- `Invalid state for item '${chalk.red(itemCodename)}'. It is expected that all item states will be initialized`
444
- );
445
- },
446
- getLanguageVariantStateInTargetEnvironment: (itemCodename, languageCodename) => {
447
- return findRequired(
448
- variantStates,
449
- (state) => state.itemCodename === itemCodename && state.languageCodename === languageCodename,
450
- `Invalid state for language variant '${chalk.red(itemCodename)}' in language '${chalk.red(
451
- languageCodename
452
- )}'. It is expected that all variant states will be initialized`
453
- );
454
- },
455
- getAssetStateInTargetEnvironment: (assetCodename) => {
456
- return findRequired(
457
- assetStates,
458
- (state) => state.assetCodename === assetCodename,
459
- `Invalid state for asset '${chalk.red(assetCodename)}'. It is expected that all asset states will be initialized`
460
- );
461
- },
462
- getElement: getElementByCodenames
463
- };
464
- };
465
-
466
- return {
467
- getImportContextAsync
468
- };
33
+ const getEnvironmentDataAsync = async (): Promise<ImportContextEnvironmentData> => {
34
+ const mapiUtils = managementClientUtils(config.managementClient, config.logger);
35
+
36
+ return await config.logger.logWithSpinnerAsync(async (spinnerData) => {
37
+ spinnerData({ type: "info", message: `Loading environment data` });
38
+
39
+ const environmentData: ImportContextEnvironmentData = {
40
+ collections: await mapiUtils.getAllCollectionsAsync(spinnerData),
41
+ languages: await mapiUtils.getAllLanguagesAsync(spinnerData),
42
+ workflows: await mapiUtils.getAllWorkflowsAsync(spinnerData),
43
+ types: await mapiUtils.getFlattenedContentTypesAsync(spinnerData),
44
+ assetFolders: await mapiUtils.getAllAssetFoldersAsync(spinnerData),
45
+ };
46
+
47
+ spinnerData({ type: "info", message: `Environmental data loaded` });
48
+
49
+ return environmentData;
50
+ });
51
+ };
52
+
53
+ const environmentData = await getEnvironmentDataAsync();
54
+ const workflowHelper = workflowHelperInit(environmentData.workflows);
55
+
56
+ const getElement = () => {
57
+ const getFlattenedElement: GetFlattenedElementByCodenames = (contentTypeCodename, elementCodename, sourceType) => {
58
+ const contentType = findRequired(
59
+ environmentData.types,
60
+ (type) => type.contentTypeCodename === contentTypeCodename,
61
+ `Content type with codename '${chalk.red(contentTypeCodename)}' was not found.`,
62
+ );
63
+
64
+ const element = findRequired(
65
+ contentType.elements,
66
+ (element) => element.codename === elementCodename,
67
+ `Element type with codename '${chalk.red(elementCodename)}' was not found in content type '${chalk.red(
68
+ contentTypeCodename,
69
+ )}'. Available elements are '${contentType.elements.map((element) => chalk.yellow(element.codename)).join(", ")}'`,
70
+ );
71
+
72
+ if (sourceType !== element.type) {
73
+ throw new MigrationToolkitError(
74
+ "invalidElement",
75
+ `Element '${chalk.red(element.codename)}' in content type '${chalk.yellow(
76
+ contentType.contentTypeCodename,
77
+ )}' is of type '${chalk.red(element.type)}', but source type is '${chalk.yellow(sourceType)}'.`,
78
+ );
79
+ }
80
+
81
+ return element;
82
+ };
83
+
84
+ return getFlattenedElement;
85
+ };
86
+
87
+ const getLatestLanguageVariantAsync = async (
88
+ logSpinner: LogSpinnerData,
89
+ migrationItem: MigrationItem,
90
+ ): Promise<Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined> => {
91
+ try {
92
+ const latestLanguageVariant = await runMapiRequestAsync({
93
+ logger: config.logger,
94
+ func: async () =>
95
+ (
96
+ await config.managementClient
97
+ .viewLanguageVariant()
98
+ .byItemCodename(migrationItem.system.codename)
99
+ .byLanguageCodename(migrationItem.system.language.codename)
100
+ .toPromise()
101
+ ).data,
102
+ action: "view",
103
+ type: "languageVariant",
104
+ logSpinner: logSpinner,
105
+ itemName: `latest -> codename -> ${migrationItem.system.codename} (${migrationItem.system.language.codename})`,
106
+ });
107
+
108
+ return latestLanguageVariant;
109
+ } catch (error) {
110
+ if (!is404Error(error)) {
111
+ throw error;
112
+ }
113
+
114
+ return undefined;
115
+ }
116
+ };
117
+
118
+ const getPublishedLanguageVariantAsync = async (
119
+ logSpinner: LogSpinnerData,
120
+ migrationItem: MigrationItem,
121
+ ): Promise<Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined> => {
122
+ try {
123
+ const draftLanguageVariant = await runMapiRequestAsync({
124
+ logger: config.logger,
125
+ func: async () =>
126
+ (
127
+ await config.managementClient
128
+ .viewLanguageVariant()
129
+ .byItemCodename(migrationItem.system.codename)
130
+ .byLanguageCodename(migrationItem.system.language.codename)
131
+ .published()
132
+ .toPromise()
133
+ ).data,
134
+ action: "view",
135
+ type: "languageVariant",
136
+ logSpinner: logSpinner,
137
+ itemName: `published -> codename -> ${migrationItem.system.codename} (${migrationItem.system.language.codename})`,
138
+ });
139
+
140
+ return draftLanguageVariant;
141
+ } catch (error) {
142
+ if (!is404Error(error)) {
143
+ throw error;
144
+ }
145
+
146
+ return undefined;
147
+ }
148
+ };
149
+
150
+ const getLanguageVariantWrappersAsync = async (
151
+ migrationItems: readonly MigrationItem[],
152
+ ): Promise<readonly LanguageVariantWrapper[]> => {
153
+ return (
154
+ await processItemsAsync<MigrationItem, LanguageVariantWrapper>({
155
+ action: "Fetching language variants",
156
+ logger: config.logger,
157
+ parallelLimit: 1,
158
+ items: migrationItems,
159
+ itemInfo: (item) => {
160
+ return {
161
+ itemType: "languageVariant",
162
+ title: `${item.system.codename} (${item.system.language.codename})`,
163
+ };
164
+ },
165
+ processAsync: async (item, logSpinner) => {
166
+ const latestLanguageVariant = await getLatestLanguageVariantAsync(logSpinner, item);
167
+
168
+ if (!latestLanguageVariant) {
169
+ // there is neither published or draft version as latest version does not exist at all
170
+ return "404";
171
+ }
172
+
173
+ if (workflowHelper.isPublishedStepById(latestLanguageVariant.workflow.stepIdentifier.id ?? "")) {
174
+ // if latest version is published, it means that there is no draft, but there is published version
175
+ return {
176
+ migrationItem: item,
177
+ draftLanguageVariant: undefined,
178
+ publishedLanguageVariant: latestLanguageVariant,
179
+ };
180
+ }
181
+
182
+ // if latest version is a draft version, check if there is published version as well
183
+ return {
184
+ migrationItem: item,
185
+ draftLanguageVariant: latestLanguageVariant,
186
+ publishedLanguageVariant: await getPublishedLanguageVariantAsync(logSpinner, item),
187
+ };
188
+ },
189
+ })
190
+ )
191
+ .filter((m) => m.state === "valid")
192
+ .map((m) => m.outputItem);
193
+ };
194
+
195
+ const getContentItemsByCodenamesAsync = async (
196
+ itemCodenames: ReadonlySet<string>,
197
+ ): Promise<readonly ContentItemModels.ContentItem[]> => {
198
+ return (
199
+ await processItemsAsync<string, Readonly<ContentItemModels.ContentItem>>({
200
+ action: "Fetching content items",
201
+ logger: config.logger,
202
+ parallelLimit: 1,
203
+ items: Array.from(itemCodenames),
204
+ itemInfo: (codename) => {
205
+ return {
206
+ itemType: "contentItem",
207
+ title: codename,
208
+ };
209
+ },
210
+ processAsync: async (codename, logSpinner) => {
211
+ try {
212
+ return await runMapiRequestAsync({
213
+ logger: config.logger,
214
+ func: async () => (await config.managementClient.viewContentItem().byItemCodename(codename).toPromise()).data,
215
+ action: "view",
216
+ type: "contentItem",
217
+ logSpinner: logSpinner,
218
+ itemName: `codename -> ${codename}`,
219
+ });
220
+ } catch (error) {
221
+ if (!is404Error(error)) {
222
+ throw error;
223
+ }
224
+
225
+ return "404";
226
+ }
227
+ },
228
+ })
229
+ )
230
+ .filter((m) => m.state === "valid")
231
+ .map((m) => m.outputItem);
232
+ };
233
+
234
+ const getAssetsByCodenamesAsync = async (assetCodenames: ReadonlySet<string>): Promise<readonly AssetModels.Asset[]> => {
235
+ return (
236
+ await processItemsAsync<string, Readonly<AssetModels.Asset>>({
237
+ action: "Fetching assets",
238
+ logger: config.logger,
239
+ parallelLimit: 1,
240
+ items: Array.from(assetCodenames),
241
+ itemInfo: (codename) => {
242
+ return {
243
+ itemType: "asset",
244
+ title: codename,
245
+ };
246
+ },
247
+ processAsync: async (codename, logSpinner) => {
248
+ try {
249
+ return await runMapiRequestAsync({
250
+ logger: config.logger,
251
+ func: async () => (await config.managementClient.viewAsset().byAssetCodename(codename).toPromise()).data,
252
+ action: "view",
253
+ type: "asset",
254
+ logSpinner: logSpinner,
255
+ itemName: `codename -> ${codename}`,
256
+ });
257
+ } catch (error) {
258
+ if (!is404Error(error)) {
259
+ throw error;
260
+ }
261
+
262
+ return "404";
263
+ }
264
+ },
265
+ })
266
+ )
267
+ .filter((m) => m.state === "valid")
268
+ .map((m) => m.outputItem);
269
+ };
270
+
271
+ const getVariantState = (languageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant>): LanguageVariantStateData => {
272
+ const variantWorkflowId = languageVariant.workflow.workflowIdentifier.id;
273
+ const variantStepId = languageVariant.workflow.stepIdentifier.id;
274
+ const { workflow, step } = workflowHelper.getWorkflowAndStep({
275
+ workflowMatcher: {
276
+ errorMessage: `Could not workflow with id '${chalk.red(variantWorkflowId)}' in target project`,
277
+ match: (workflow) => workflow.id === variantWorkflowId,
278
+ },
279
+ stepMatcher: {
280
+ errorMessage: `Could not workflow step with id '${chalk.red(variantStepId)}' in workflow '${chalk.yellow(
281
+ variantWorkflowId,
282
+ )}'`,
283
+ match: (step) => step.id === variantStepId,
284
+ },
285
+ });
286
+
287
+ return {
288
+ languageVariant: languageVariant,
289
+ workflow: workflow,
290
+ workflowState: getWorkflowState(step, languageVariant),
291
+ };
292
+ };
293
+
294
+ const getVariantStatesAsync = async (
295
+ migrationItems: readonly MigrationItem[],
296
+ ): Promise<readonly LanguageVariantStateInTargetEnvironmentByCodename[]> => {
297
+ const variantWrappers = await getLanguageVariantWrappersAsync(migrationItems);
298
+
299
+ return migrationItems.map<LanguageVariantStateInTargetEnvironmentByCodename>((migrationItem) => {
300
+ const variantWrapper = variantWrappers.find(
301
+ (m) =>
302
+ m.migrationItem.system.codename === migrationItem.system.codename &&
303
+ m.migrationItem.system.language === migrationItem.system.language,
304
+ );
305
+
306
+ return {
307
+ itemCodename: migrationItem.system.codename,
308
+ languageCodename: migrationItem.system.language.codename,
309
+ draftLanguageVariant: variantWrapper?.draftLanguageVariant
310
+ ? getVariantState(variantWrapper.draftLanguageVariant)
311
+ : undefined,
312
+ publishedLanguageVariant: variantWrapper?.publishedLanguageVariant
313
+ ? getVariantState(variantWrapper.publishedLanguageVariant)
314
+ : undefined,
315
+ state: variantWrapper ? "exists" : "doesNotExists",
316
+ };
317
+ });
318
+ };
319
+
320
+ const getWorkflowState = (
321
+ step: Readonly<WorkflowStep>,
322
+ variant: Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined,
323
+ ): LanguageVariantWorkflowState => {
324
+ if (!variant) {
325
+ return undefined;
326
+ }
327
+
328
+ const getScheduledState = (): LanguageVariantSchedulesStateValues => {
329
+ return match(variant.schedule)
330
+ .returnType<LanguageVariantSchedulesStateValues>()
331
+ .when(
332
+ (schedule) => schedule.publishTime && schedule.publishDisplayTimezone,
333
+ () => "scheduledPublish",
334
+ )
335
+ .when(
336
+ (schedule) => schedule.unpublishTime && schedule.unpublishDisplayTimezone,
337
+ () => "scheduledUnpublish",
338
+ )
339
+ .otherwise(() => "n/a");
340
+ };
341
+
342
+ const getWorkflowState = (): LanguageVariantWorkflowStateValues => {
343
+ return match(step.codename)
344
+ .returnType<LanguageVariantWorkflowStateValues>()
345
+ .when(
346
+ (stepCodename) => workflowHelper.isPublishedStepByCodename(stepCodename),
347
+ () => "published",
348
+ )
349
+ .when(
350
+ (stepCodename) => workflowHelper.isArchivedStepByCodename(stepCodename),
351
+ () => "archived",
352
+ )
353
+ .otherwise(() => "draft");
354
+ };
355
+
356
+ return {
357
+ workflowState: getWorkflowState(),
358
+ scheduledState: getScheduledState(),
359
+ };
360
+ };
361
+
362
+ const getItemStatesAsync = async (itemCodenames: ReadonlySet<string>): Promise<readonly ItemStateInTargetEnvironmentByCodename[]> => {
363
+ const items = await getContentItemsByCodenamesAsync(itemCodenames);
364
+
365
+ return Array.from(itemCodenames).map<ItemStateInTargetEnvironmentByCodename>((codename) => {
366
+ const item = items.find((m) => m.codename === codename);
367
+ return {
368
+ itemCodename: codename,
369
+ item: item,
370
+ state: item ? "exists" : "doesNotExists",
371
+ externalIdToUse: config.externalIdGenerator.contentItemExternalId(codename),
372
+ };
373
+ });
374
+ };
375
+
376
+ const getAssetStatesAsync = async (
377
+ assetCodenames: ReadonlySet<string>,
378
+ ): Promise<readonly AssetStateInTargetEnvironmentByCodename[]> => {
379
+ const assets = await getAssetsByCodenamesAsync(assetCodenames);
380
+
381
+ return Array.from(assetCodenames).map<AssetStateInTargetEnvironmentByCodename>((codename) => {
382
+ const asset = assets.find((m) => m.codename === codename);
383
+ return {
384
+ assetCodename: codename,
385
+ asset: asset,
386
+ state: asset ? "exists" : "doesNotExists",
387
+ externalIdToUse: config.externalIdGenerator.assetExternalId(codename),
388
+ };
389
+ });
390
+ };
391
+
392
+ const getImportContextAsync = async (): Promise<ImportContext> => {
393
+ const getElementByCodenames: GetFlattenedElementByCodenames = getElement();
394
+
395
+ const referencedData = itemsExtractionProcessor().extractReferencedItemsFromMigrationItems(
396
+ config.migrationData.items.reduce<ExtractItemByCodename[]>((items, item) => {
397
+ items.push(
398
+ ...item.versions.map((version) => {
399
+ const extractionItem: ExtractItemByCodename = {
400
+ contentTypeCodename: item.system.type.codename,
401
+ elements: version.elements,
402
+ };
403
+ return extractionItem;
404
+ }),
405
+ );
406
+
407
+ return items;
408
+ }, []),
409
+ getElementByCodenames,
410
+ );
411
+ // fetch all items, including referenced items in content
412
+ const itemCodenamesToCheckInTargetEnv: ReadonlySet<string> = new Set<string>([
413
+ ...referencedData.itemCodenames,
414
+ ...config.migrationData.items.map((m) => m.system.codename),
415
+ ]);
416
+
417
+ // fetch all assets, including referenced assets in content
418
+ const assetCodenamesToCheckInTargetEnv: ReadonlySet<string> = new Set<string>([
419
+ ...referencedData.assetCodenames,
420
+ ...config.migrationData.assets.map((m) => m.codename),
421
+ ]);
422
+
423
+ // prepare state of objects in target environment
424
+ const itemStates: readonly ItemStateInTargetEnvironmentByCodename[] = await getItemStatesAsync(itemCodenamesToCheckInTargetEnv);
425
+
426
+ const variantStates: readonly LanguageVariantStateInTargetEnvironmentByCodename[] = await getVariantStatesAsync(
427
+ config.migrationData.items,
428
+ );
429
+
430
+ const assetStates: readonly AssetStateInTargetEnvironmentByCodename[] = await getAssetStatesAsync(assetCodenamesToCheckInTargetEnv);
431
+
432
+ return {
433
+ environmentData,
434
+ referencedData,
435
+ categorizedImportData: {
436
+ assets: config.migrationData.assets,
437
+ contentItems: config.migrationData.items,
438
+ },
439
+ getItemStateInTargetEnvironment: (itemCodename) => {
440
+ return findRequired(
441
+ itemStates,
442
+ (state) => state.itemCodename === itemCodename,
443
+ `Invalid state for item '${chalk.red(itemCodename)}'. It is expected that all item states will be initialized`,
444
+ );
445
+ },
446
+ getLanguageVariantStateInTargetEnvironment: (itemCodename, languageCodename) => {
447
+ return findRequired(
448
+ variantStates,
449
+ (state) => state.itemCodename === itemCodename && state.languageCodename === languageCodename,
450
+ `Invalid state for language variant '${chalk.red(itemCodename)}' in language '${chalk.red(
451
+ languageCodename,
452
+ )}'. It is expected that all variant states will be initialized`,
453
+ );
454
+ },
455
+ getAssetStateInTargetEnvironment: (assetCodename) => {
456
+ return findRequired(
457
+ assetStates,
458
+ (state) => state.assetCodename === assetCodename,
459
+ `Invalid state for asset '${chalk.red(assetCodename)}'. It is expected that all asset states will be initialized`,
460
+ );
461
+ },
462
+ getElement: getElementByCodenames,
463
+ };
464
+ };
465
+
466
+ return {
467
+ getImportContextAsync,
468
+ };
469
469
  }