@kontent-ai/migration-toolkit 2.9.1 → 3.0.0-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) 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 +29 -22
  11. package/dist/core/models/error.models.d.ts +26 -0
  12. package/dist/core/models/error.models.js +104 -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 +17 -19
  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 +3 -1
  26. package/dist/core/utils/confirm.utils.js +92 -24
  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 +37 -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/core/utils/try.utils.d.ts +14 -0
  49. package/dist/core/utils/try.utils.js +18 -0
  50. package/dist/core/utils/try.utils.js.map +1 -0
  51. package/dist/export/context/export-context-fetcher.d.ts +1 -1
  52. package/dist/export/context/export-context-fetcher.js +92 -62
  53. package/dist/export/context/export-context-fetcher.js.map +1 -1
  54. package/dist/export/export-manager.d.ts +2 -2
  55. package/dist/export/export-manager.js +73 -59
  56. package/dist/export/export-manager.js.map +1 -1
  57. package/dist/export/export.models.d.ts +21 -2
  58. package/dist/export/utils/export.utils.d.ts +1 -1
  59. package/dist/export/utils/export.utils.js +3 -2
  60. package/dist/export/utils/export.utils.js.map +1 -1
  61. package/dist/file/file-manager.d.ts +2 -2
  62. package/dist/file/file-manager.js +7 -7
  63. package/dist/file/file-manager.js.map +1 -1
  64. package/dist/import/comparers/asset-comparer.d.ts +2 -2
  65. package/dist/import/comparers/asset-comparer.js +12 -11
  66. package/dist/import/comparers/asset-comparer.js.map +1 -1
  67. package/dist/import/context/import-context-fetcher.d.ts +1 -1
  68. package/dist/import/context/import-context-fetcher.js +77 -73
  69. package/dist/import/context/import-context-fetcher.js.map +1 -1
  70. package/dist/import/import-manager.d.ts +1 -1
  71. package/dist/import/import-manager.js +59 -56
  72. package/dist/import/import-manager.js.map +1 -1
  73. package/dist/import/import.models.d.ts +6 -2
  74. package/dist/import/importers/assets-importer.d.ts +3 -3
  75. package/dist/import/importers/assets-importer.js +46 -43
  76. package/dist/import/importers/assets-importer.js.map +1 -1
  77. package/dist/import/importers/content-items-importer.d.ts +3 -3
  78. package/dist/import/importers/content-items-importer.js +28 -25
  79. package/dist/import/importers/content-items-importer.js.map +1 -1
  80. package/dist/import/importers/language-variant-importer.d.ts +3 -3
  81. package/dist/import/importers/language-variant-importer.js +45 -45
  82. package/dist/import/importers/language-variant-importer.js.map +1 -1
  83. package/dist/import/importers/workflow-importer.d.ts +3 -2
  84. package/dist/import/importers/workflow-importer.js +58 -54
  85. package/dist/import/importers/workflow-importer.js.map +1 -1
  86. package/dist/import/utils/import.utils.d.ts +1 -1
  87. package/dist/import/utils/import.utils.js +3 -2
  88. package/dist/import/utils/import.utils.js.map +1 -1
  89. package/dist/index.d.ts +11 -7
  90. package/dist/index.js +10 -8
  91. package/dist/index.js.map +1 -1
  92. package/dist/metadata.js +3 -3
  93. package/dist/metadata.js.map +1 -1
  94. package/dist/node/cli/actions/export-action.d.ts +1 -1
  95. package/dist/node/cli/actions/export-action.js +29 -23
  96. package/dist/node/cli/actions/export-action.js.map +1 -1
  97. package/dist/node/cli/actions/import-action.d.ts +1 -1
  98. package/dist/node/cli/actions/import-action.js +15 -12
  99. package/dist/node/cli/actions/import-action.js.map +1 -1
  100. package/dist/node/cli/actions/migrate-action.d.ts +1 -1
  101. package/dist/node/cli/actions/migrate-action.js +26 -22
  102. package/dist/node/cli/actions/migrate-action.js.map +1 -1
  103. package/dist/node/cli/app.js +13 -12
  104. package/dist/node/cli/app.js.map +1 -1
  105. package/dist/node/cli/args/args-fetcher.d.ts +1 -1
  106. package/dist/node/cli/args/args-fetcher.js +14 -13
  107. package/dist/node/cli/args/args-fetcher.js.map +1 -1
  108. package/dist/node/cli/args/args-setter.d.ts +1 -1
  109. package/dist/node/cli/args/args-setter.js +8 -6
  110. package/dist/node/cli/args/args-setter.js.map +1 -1
  111. package/dist/node/cli/cli.models.d.ts +2 -2
  112. package/dist/node/cli/commands.js +68 -56
  113. package/dist/node/cli/commands.js.map +1 -1
  114. package/dist/toolkit/elements-builder.d.ts +1 -1
  115. package/dist/toolkit/elements-builder.js +12 -12
  116. package/dist/toolkit/elements-builder.js.map +1 -1
  117. package/dist/toolkit/export.d.ts +2 -2
  118. package/dist/toolkit/export.js +8 -8
  119. package/dist/toolkit/export.js.map +1 -1
  120. package/dist/toolkit/file.d.ts +2 -1
  121. package/dist/toolkit/file.js +18 -16
  122. package/dist/toolkit/file.js.map +1 -1
  123. package/dist/toolkit/import.d.ts +1 -1
  124. package/dist/toolkit/import.js +12 -12
  125. package/dist/toolkit/import.js.map +1 -1
  126. package/dist/toolkit/migrate.d.ts +13 -4
  127. package/dist/toolkit/migrate.js +15 -13
  128. package/dist/toolkit/migrate.js.map +1 -1
  129. package/dist/translation/extraction/items-extraction.processor.d.ts +5 -4
  130. package/dist/translation/extraction/items-extraction.processor.js +73 -35
  131. package/dist/translation/extraction/items-extraction.processor.js.map +1 -1
  132. package/dist/translation/helpers/export-placeholder.utils.d.ts +11 -0
  133. package/dist/translation/helpers/export-placeholder.utils.js +11 -0
  134. package/dist/translation/helpers/export-placeholder.utils.js.map +1 -0
  135. package/dist/translation/helpers/rich-text.processor.d.ts +6 -6
  136. package/dist/translation/helpers/rich-text.processor.js +38 -38
  137. package/dist/translation/helpers/rich-text.processor.js.map +1 -1
  138. package/dist/translation/transforms/export-transforms.d.ts +2 -2
  139. package/dist/translation/transforms/export-transforms.js +93 -67
  140. package/dist/translation/transforms/export-transforms.js.map +1 -1
  141. package/dist/translation/transforms/import-transforms.d.ts +2 -2
  142. package/dist/translation/transforms/import-transforms.js +38 -40
  143. package/dist/translation/transforms/import-transforms.js.map +1 -1
  144. package/dist/zip/zip-manager.d.ts +4 -3
  145. package/dist/zip/zip-manager.js +9 -9
  146. package/dist/zip/zip-manager.js.map +1 -1
  147. package/dist/zip/zip-packager.d.ts +2 -2
  148. package/dist/zip/zip-packager.js +19 -17
  149. package/dist/zip/zip-packager.js.map +1 -1
  150. package/dist/zip/zip-transformer.d.ts +3 -2
  151. package/dist/zip/zip-transformer.js +16 -15
  152. package/dist/zip/zip-transformer.js.map +1 -1
  153. package/dist/zip/zip.models.d.ts +2 -2
  154. package/lib/core/config.ts +6 -6
  155. package/lib/core/helpers/workflow-helper.ts +190 -185
  156. package/lib/core/logs/loggers.ts +52 -52
  157. package/lib/core/models/core.models.ts +130 -119
  158. package/lib/core/models/error.models.ts +148 -0
  159. package/lib/core/models/log.models.ts +20 -20
  160. package/lib/core/models/migration.models.ts +54 -57
  161. package/lib/core/models/migration.schema.ts +108 -108
  162. package/lib/core/utils/array.utils.ts +43 -42
  163. package/lib/core/utils/binary-data.utils.ts +16 -16
  164. package/lib/core/utils/confirm.utils.ts +184 -106
  165. package/lib/core/utils/error.utils.ts +69 -72
  166. package/lib/core/utils/external-id.utils.ts +4 -4
  167. package/lib/core/utils/global.utils.ts +81 -75
  168. package/lib/core/utils/http.utils.ts +23 -23
  169. package/lib/core/utils/management-client-utils.ts +189 -186
  170. package/lib/core/utils/processing-utils.ts +82 -82
  171. package/lib/core/utils/run.utils.ts +50 -50
  172. package/lib/core/utils/try.utils.ts +30 -0
  173. package/lib/export/context/export-context-fetcher.ts +472 -447
  174. package/lib/export/export-manager.ts +250 -232
  175. package/lib/export/export.models.ts +71 -56
  176. package/lib/export/utils/export.utils.ts +9 -7
  177. package/lib/file/file-manager.ts +28 -28
  178. package/lib/import/comparers/asset-comparer.ts +107 -106
  179. package/lib/import/context/import-context-fetcher.ts +462 -462
  180. package/lib/import/import-manager.ts +243 -240
  181. package/lib/import/import.models.ts +69 -67
  182. package/lib/import/importers/assets-importer.ts +240 -236
  183. package/lib/import/importers/content-items-importer.ts +126 -122
  184. package/lib/import/importers/language-variant-importer.ts +324 -328
  185. package/lib/import/importers/workflow-importer.ts +372 -367
  186. package/lib/import/utils/import.utils.ts +9 -7
  187. package/lib/index.ts +12 -8
  188. package/lib/metadata.ts +3 -4
  189. package/lib/node/cli/actions/export-action.ts +44 -38
  190. package/lib/node/cli/actions/import-action.ts +32 -29
  191. package/lib/node/cli/actions/migrate-action.ts +50 -46
  192. package/lib/node/cli/app.ts +21 -21
  193. package/lib/node/cli/args/args-fetcher.ts +55 -54
  194. package/lib/node/cli/args/args-setter.ts +34 -32
  195. package/lib/node/cli/cli.models.ts +17 -17
  196. package/lib/node/cli/commands.ts +165 -153
  197. package/lib/toolkit/elements-builder.ts +69 -69
  198. package/lib/toolkit/export.ts +21 -21
  199. package/lib/toolkit/file.ts +59 -53
  200. package/lib/toolkit/import.ts +32 -32
  201. package/lib/toolkit/migrate.ts +60 -49
  202. package/lib/translation/extraction/items-extraction.processor.ts +203 -173
  203. package/lib/translation/helpers/export-placeholder.utils.ts +10 -0
  204. package/lib/translation/helpers/rich-text.processor.ts +311 -311
  205. package/lib/translation/transforms/export-transforms.ts +313 -279
  206. package/lib/translation/transforms/import-transforms.ts +188 -191
  207. package/lib/zip/zip-manager.ts +28 -27
  208. package/lib/zip/zip-packager.ts +75 -73
  209. package/lib/zip/zip-transformer.ts +112 -107
  210. package/lib/zip/zip.models.ts +7 -7
  211. package/package.json +91 -84
  212. package/dist/core/index.d.ts +0 -16
  213. package/dist/core/index.js +0 -17
  214. package/dist/core/index.js.map +0 -1
  215. package/dist/export/index.d.ts +0 -2
  216. package/dist/export/index.js +0 -3
  217. package/dist/export/index.js.map +0 -1
  218. package/dist/file/index.d.ts +0 -1
  219. package/dist/file/index.js +0 -2
  220. package/dist/file/index.js.map +0 -1
  221. package/dist/import/index.d.ts +0 -2
  222. package/dist/import/index.js +0 -3
  223. package/dist/import/index.js.map +0 -1
  224. package/dist/toolkit/index.d.ts +0 -5
  225. package/dist/toolkit/index.js +0 -6
  226. package/dist/toolkit/index.js.map +0 -1
  227. package/dist/translation/index.d.ts +0 -4
  228. package/dist/translation/index.js +0 -5
  229. package/dist/translation/index.js.map +0 -1
  230. package/dist/zip/index.d.ts +0 -4
  231. package/dist/zip/index.js +0 -5
  232. package/dist/zip/index.js.map +0 -1
  233. package/lib/core/index.ts +0 -18
  234. package/lib/export/index.ts +0 -2
  235. package/lib/file/index.ts +0 -1
  236. package/lib/import/index.ts +0 -2
  237. package/lib/toolkit/index.ts +0 -5
  238. package/lib/translation/index.ts +0 -4
  239. 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
  }