@kontent-ai/migration-toolkit 1.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 (240) hide show
  1. package/.npmignore +13 -0
  2. package/LICENSE.md +9 -0
  3. package/README.md +272 -0
  4. package/dist/es2022/core/helpers/workflow-helper.d.ts +37 -0
  5. package/dist/es2022/core/helpers/workflow-helper.js +67 -0
  6. package/dist/es2022/core/helpers/workflow-helper.js.map +1 -0
  7. package/dist/es2022/core/index.d.ts +15 -0
  8. package/dist/es2022/core/index.js +16 -0
  9. package/dist/es2022/core/index.js.map +1 -0
  10. package/dist/es2022/core/logs/loggers.d.ts +2 -0
  11. package/dist/es2022/core/logs/loggers.js +69 -0
  12. package/dist/es2022/core/logs/loggers.js.map +1 -0
  13. package/dist/es2022/core/models/core.models.d.ts +91 -0
  14. package/dist/es2022/core/models/core.models.js +2 -0
  15. package/dist/es2022/core/models/core.models.js.map +1 -0
  16. package/dist/es2022/core/models/log.models.d.ts +15 -0
  17. package/dist/es2022/core/models/log.models.js +2 -0
  18. package/dist/es2022/core/models/log.models.js.map +1 -0
  19. package/dist/es2022/core/models/migration.models.d.ts +136 -0
  20. package/dist/es2022/core/models/migration.models.js +2 -0
  21. package/dist/es2022/core/models/migration.models.js.map +1 -0
  22. package/dist/es2022/core/utils/array.utils.d.ts +5 -0
  23. package/dist/es2022/core/utils/array.utils.js +27 -0
  24. package/dist/es2022/core/utils/array.utils.js.map +1 -0
  25. package/dist/es2022/core/utils/binary-data.utils.d.ts +5 -0
  26. package/dist/es2022/core/utils/binary-data.utils.js +21 -0
  27. package/dist/es2022/core/utils/binary-data.utils.js.map +1 -0
  28. package/dist/es2022/core/utils/confirm.utils.d.ts +31 -0
  29. package/dist/es2022/core/utils/confirm.utils.js +73 -0
  30. package/dist/es2022/core/utils/confirm.utils.js.map +1 -0
  31. package/dist/es2022/core/utils/error.utils.d.ts +4 -0
  32. package/dist/es2022/core/utils/error.utils.js +50 -0
  33. package/dist/es2022/core/utils/error.utils.js.map +1 -0
  34. package/dist/es2022/core/utils/external-id.utils.d.ts +5 -0
  35. package/dist/es2022/core/utils/external-id.utils.js +5 -0
  36. package/dist/es2022/core/utils/external-id.utils.js.map +1 -0
  37. package/dist/es2022/core/utils/global.utils.d.ts +14 -0
  38. package/dist/es2022/core/utils/global.utils.js +45 -0
  39. package/dist/es2022/core/utils/global.utils.js.map +1 -0
  40. package/dist/es2022/core/utils/http.utils.d.ts +3 -0
  41. package/dist/es2022/core/utils/http.utils.js +29 -0
  42. package/dist/es2022/core/utils/http.utils.js.map +1 -0
  43. package/dist/es2022/core/utils/management-client-utils.d.ts +19 -0
  44. package/dist/es2022/core/utils/management-client-utils.js +129 -0
  45. package/dist/es2022/core/utils/management-client-utils.js.map +1 -0
  46. package/dist/es2022/core/utils/processing-utils.d.ts +12 -0
  47. package/dist/es2022/core/utils/processing-utils.js +39 -0
  48. package/dist/es2022/core/utils/processing-utils.js.map +1 -0
  49. package/dist/es2022/core/utils/run.utils.d.ts +10 -0
  50. package/dist/es2022/core/utils/run.utils.js +37 -0
  51. package/dist/es2022/core/utils/run.utils.js.map +1 -0
  52. package/dist/es2022/export/context/export-context-fetcher.d.ts +4 -0
  53. package/dist/es2022/export/context/export-context-fetcher.js +289 -0
  54. package/dist/es2022/export/context/export-context-fetcher.js.map +1 -0
  55. package/dist/es2022/export/export-manager.d.ts +5 -0
  56. package/dist/es2022/export/export-manager.js +167 -0
  57. package/dist/es2022/export/export-manager.js.map +1 -0
  58. package/dist/es2022/export/export.models.d.ts +55 -0
  59. package/dist/es2022/export/export.models.js +2 -0
  60. package/dist/es2022/export/export.models.js.map +1 -0
  61. package/dist/es2022/export/index.d.ts +2 -0
  62. package/dist/es2022/export/index.js +3 -0
  63. package/dist/es2022/export/index.js.map +1 -0
  64. package/dist/es2022/export/utils/export.utils.d.ts +2 -0
  65. package/dist/es2022/export/utils/export.utils.js +5 -0
  66. package/dist/es2022/export/utils/export.utils.js.map +1 -0
  67. package/dist/es2022/file/file-manager.d.ts +5 -0
  68. package/dist/es2022/file/file-manager.js +29 -0
  69. package/dist/es2022/file/file-manager.js.map +1 -0
  70. package/dist/es2022/file/index.d.ts +1 -0
  71. package/dist/es2022/file/index.js +2 -0
  72. package/dist/es2022/file/index.js.map +1 -0
  73. package/dist/es2022/import/comparers/asset-comparer.d.ts +12 -0
  74. package/dist/es2022/import/comparers/asset-comparer.js +65 -0
  75. package/dist/es2022/import/comparers/asset-comparer.js.map +1 -0
  76. package/dist/es2022/import/context/import-context-fetcher.d.ts +4 -0
  77. package/dist/es2022/import/context/import-context-fetcher.js +235 -0
  78. package/dist/es2022/import/context/import-context-fetcher.js.map +1 -0
  79. package/dist/es2022/import/import-manager.d.ts +4 -0
  80. package/dist/es2022/import/import-manager.js +80 -0
  81. package/dist/es2022/import/import-manager.js.map +1 -0
  82. package/dist/es2022/import/import.models.d.ts +45 -0
  83. package/dist/es2022/import/import.models.js +2 -0
  84. package/dist/es2022/import/import.models.js.map +1 -0
  85. package/dist/es2022/import/importers/assets-importer.d.ts +10 -0
  86. package/dist/es2022/import/importers/assets-importer.js +175 -0
  87. package/dist/es2022/import/importers/assets-importer.js.map +1 -0
  88. package/dist/es2022/import/importers/content-items-importer.d.ts +10 -0
  89. package/dist/es2022/import/importers/content-items-importer.js +97 -0
  90. package/dist/es2022/import/importers/content-items-importer.js.map +1 -0
  91. package/dist/es2022/import/importers/language-variant-importer.d.ts +11 -0
  92. package/dist/es2022/import/importers/language-variant-importer.js +215 -0
  93. package/dist/es2022/import/importers/language-variant-importer.js.map +1 -0
  94. package/dist/es2022/import/importers/workflow-importer.d.ts +18 -0
  95. package/dist/es2022/import/importers/workflow-importer.js +122 -0
  96. package/dist/es2022/import/importers/workflow-importer.js.map +1 -0
  97. package/dist/es2022/import/index.d.ts +2 -0
  98. package/dist/es2022/import/index.js +3 -0
  99. package/dist/es2022/import/index.js.map +1 -0
  100. package/dist/es2022/import/utils/import.utils.d.ts +2 -0
  101. package/dist/es2022/import/utils/import.utils.js +5 -0
  102. package/dist/es2022/import/utils/import.utils.js.map +1 -0
  103. package/dist/es2022/index.d.ts +8 -0
  104. package/dist/es2022/index.js +10 -0
  105. package/dist/es2022/index.js.map +1 -0
  106. package/dist/es2022/metadata.d.ts +5 -0
  107. package/dist/es2022/metadata.js +6 -0
  108. package/dist/es2022/metadata.js.map +1 -0
  109. package/dist/es2022/node/cli/actions/export-action.d.ts +2 -0
  110. package/dist/es2022/node/cli/actions/export-action.js +40 -0
  111. package/dist/es2022/node/cli/actions/export-action.js.map +1 -0
  112. package/dist/es2022/node/cli/actions/import-action.d.ts +2 -0
  113. package/dist/es2022/node/cli/actions/import-action.js +29 -0
  114. package/dist/es2022/node/cli/actions/import-action.js.map +1 -0
  115. package/dist/es2022/node/cli/actions/migrate-action.d.ts +2 -0
  116. package/dist/es2022/node/cli/actions/migrate-action.js +47 -0
  117. package/dist/es2022/node/cli/actions/migrate-action.js.map +1 -0
  118. package/dist/es2022/node/cli/app.d.ts +2 -0
  119. package/dist/es2022/node/cli/app.js +27 -0
  120. package/dist/es2022/node/cli/app.js.map +1 -0
  121. package/dist/es2022/node/cli/args/args-fetcher.d.ts +2 -0
  122. package/dist/es2022/node/cli/args/args-fetcher.js +46 -0
  123. package/dist/es2022/node/cli/args/args-fetcher.js.map +1 -0
  124. package/dist/es2022/node/cli/args/args-setter.d.ts +2 -0
  125. package/dist/es2022/node/cli/args/args-setter.js +31 -0
  126. package/dist/es2022/node/cli/args/args-setter.js.map +1 -0
  127. package/dist/es2022/node/cli/cli.models.d.ts +24 -0
  128. package/dist/es2022/node/cli/cli.models.js +2 -0
  129. package/dist/es2022/node/cli/cli.models.js.map +1 -0
  130. package/dist/es2022/node/cli/commands.d.ts +1 -0
  131. package/dist/es2022/node/cli/commands.js +157 -0
  132. package/dist/es2022/node/cli/commands.js.map +1 -0
  133. package/dist/es2022/toolkit/elements-builder.d.ts +14 -0
  134. package/dist/es2022/toolkit/elements-builder.js +69 -0
  135. package/dist/es2022/toolkit/elements-builder.js.map +1 -0
  136. package/dist/es2022/toolkit/export.d.ts +3 -0
  137. package/dist/es2022/toolkit/export.js +21 -0
  138. package/dist/es2022/toolkit/export.js.map +1 -0
  139. package/dist/es2022/toolkit/file.d.ts +12 -0
  140. package/dist/es2022/toolkit/file.js +50 -0
  141. package/dist/es2022/toolkit/file.js.map +1 -0
  142. package/dist/es2022/toolkit/import.d.ts +2 -0
  143. package/dist/es2022/toolkit/import.js +21 -0
  144. package/dist/es2022/toolkit/import.js.map +1 -0
  145. package/dist/es2022/toolkit/index.d.ts +5 -0
  146. package/dist/es2022/toolkit/index.js +6 -0
  147. package/dist/es2022/toolkit/index.js.map +1 -0
  148. package/dist/es2022/toolkit/migrate.d.ts +21 -0
  149. package/dist/es2022/toolkit/migrate.js +39 -0
  150. package/dist/es2022/toolkit/migrate.js.map +1 -0
  151. package/dist/es2022/translation/extraction/items-extraction.processor.d.ts +24 -0
  152. package/dist/es2022/translation/extraction/items-extraction.processor.js +108 -0
  153. package/dist/es2022/translation/extraction/items-extraction.processor.js.map +1 -0
  154. package/dist/es2022/translation/helpers/rich-text.processor.d.ts +22 -0
  155. package/dist/es2022/translation/helpers/rich-text.processor.js +209 -0
  156. package/dist/es2022/translation/helpers/rich-text.processor.js.map +1 -0
  157. package/dist/es2022/translation/index.d.ts +4 -0
  158. package/dist/es2022/translation/index.js +5 -0
  159. package/dist/es2022/translation/index.js.map +1 -0
  160. package/dist/es2022/translation/transforms/export-transforms.d.ts +3 -0
  161. package/dist/es2022/translation/transforms/export-transforms.js +196 -0
  162. package/dist/es2022/translation/transforms/export-transforms.js.map +1 -0
  163. package/dist/es2022/translation/transforms/import-transforms.d.ts +7 -0
  164. package/dist/es2022/translation/transforms/import-transforms.js +183 -0
  165. package/dist/es2022/translation/transforms/import-transforms.js.map +1 -0
  166. package/dist/es2022/zip/index.d.ts +4 -0
  167. package/dist/es2022/zip/index.js +5 -0
  168. package/dist/es2022/zip/index.js.map +1 -0
  169. package/dist/es2022/zip/zip-manager.d.ts +6 -0
  170. package/dist/es2022/zip/zip-manager.js +27 -0
  171. package/dist/es2022/zip/zip-manager.js.map +1 -0
  172. package/dist/es2022/zip/zip-packager.d.ts +3 -0
  173. package/dist/es2022/zip/zip-packager.js +69 -0
  174. package/dist/es2022/zip/zip-packager.js.map +1 -0
  175. package/dist/es2022/zip/zip-transformer.d.ts +6 -0
  176. package/dist/es2022/zip/zip-transformer.js +82 -0
  177. package/dist/es2022/zip/zip-transformer.js.map +1 -0
  178. package/dist/es2022/zip/zip.models.d.ts +13 -0
  179. package/dist/es2022/zip/zip.models.js +2 -0
  180. package/dist/es2022/zip/zip.models.js.map +1 -0
  181. package/lib/core/helpers/workflow-helper.ts +104 -0
  182. package/lib/core/index.ts +17 -0
  183. package/lib/core/logs/loggers.ts +80 -0
  184. package/lib/core/models/core.models.ts +134 -0
  185. package/lib/core/models/log.models.ts +31 -0
  186. package/lib/core/models/migration.models.ts +165 -0
  187. package/lib/core/utils/array.utils.ts +49 -0
  188. package/lib/core/utils/binary-data.utils.ts +29 -0
  189. package/lib/core/utils/confirm.utils.ts +139 -0
  190. package/lib/core/utils/error.utils.ts +65 -0
  191. package/lib/core/utils/external-id.utils.ts +9 -0
  192. package/lib/core/utils/global.utils.ts +59 -0
  193. package/lib/core/utils/http.utils.ts +35 -0
  194. package/lib/core/utils/management-client-utils.ts +182 -0
  195. package/lib/core/utils/processing-utils.ts +71 -0
  196. package/lib/core/utils/run.utils.ts +51 -0
  197. package/lib/export/context/export-context-fetcher.ts +475 -0
  198. package/lib/export/export-manager.ts +249 -0
  199. package/lib/export/export.models.ts +87 -0
  200. package/lib/export/index.ts +2 -0
  201. package/lib/export/utils/export.utils.ts +10 -0
  202. package/lib/file/file-manager.ts +37 -0
  203. package/lib/file/index.ts +1 -0
  204. package/lib/import/comparers/asset-comparer.ts +113 -0
  205. package/lib/import/context/import-context-fetcher.ts +367 -0
  206. package/lib/import/import-manager.ts +103 -0
  207. package/lib/import/import.models.ts +84 -0
  208. package/lib/import/importers/assets-importer.ts +239 -0
  209. package/lib/import/importers/content-items-importer.ts +142 -0
  210. package/lib/import/importers/language-variant-importer.ts +342 -0
  211. package/lib/import/importers/workflow-importer.ts +159 -0
  212. package/lib/import/index.ts +2 -0
  213. package/lib/import/utils/import.utils.ts +10 -0
  214. package/lib/index.ts +9 -0
  215. package/lib/metadata.ts +6 -0
  216. package/lib/node/cli/actions/export-action.ts +45 -0
  217. package/lib/node/cli/actions/import-action.ts +34 -0
  218. package/lib/node/cli/actions/migrate-action.ts +52 -0
  219. package/lib/node/cli/app.ts +29 -0
  220. package/lib/node/cli/args/args-fetcher.ts +61 -0
  221. package/lib/node/cli/args/args-setter.ts +35 -0
  222. package/lib/node/cli/cli.models.ts +28 -0
  223. package/lib/node/cli/commands.ts +161 -0
  224. package/lib/toolkit/elements-builder.ts +84 -0
  225. package/lib/toolkit/export.ts +21 -0
  226. package/lib/toolkit/file.ts +70 -0
  227. package/lib/toolkit/import.ts +21 -0
  228. package/lib/toolkit/index.ts +5 -0
  229. package/lib/toolkit/migrate.ts +71 -0
  230. package/lib/translation/extraction/items-extraction.processor.ts +181 -0
  231. package/lib/translation/helpers/rich-text.processor.ts +300 -0
  232. package/lib/translation/index.ts +4 -0
  233. package/lib/translation/transforms/export-transforms.ts +253 -0
  234. package/lib/translation/transforms/import-transforms.ts +215 -0
  235. package/lib/zip/index.ts +4 -0
  236. package/lib/zip/zip-manager.ts +33 -0
  237. package/lib/zip/zip-packager.ts +86 -0
  238. package/lib/zip/zip-transformer.ts +105 -0
  239. package/lib/zip/zip.models.ts +12 -0
  240. package/package.json +88 -0
@@ -0,0 +1,367 @@
1
+ import { AssetModels, ContentItemModels, LanguageVariantModels } from '@kontent-ai/management-sdk';
2
+ import {
3
+ AssetStateInTargetEnvironmentByCodename,
4
+ ItemStateInTargetEnvironmentByCodename,
5
+ LanguageVariantStateInTargetEnvironmentByCodename,
6
+ MigrationItem,
7
+ findRequired,
8
+ is404Error,
9
+ isNotUndefined,
10
+ managementClientUtils,
11
+ processItemsAsync,
12
+ runMapiRequestAsync,
13
+ workflowHelper
14
+ } from '../../core/index.js';
15
+ import {
16
+ GetFlattenedElementByCodenames,
17
+ ImportContext,
18
+ ImportContextConfig,
19
+ ImportContextEnvironmentData
20
+ } from '../import.models.js';
21
+ import { ExtractItemByCodename, itemsExtractionProcessor } from '../../translation/index.js';
22
+ import chalk from 'chalk';
23
+
24
+ interface LanguageVariantWrapper {
25
+ readonly languageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant>;
26
+ readonly migrationItem: MigrationItem;
27
+ }
28
+
29
+ export async function importContextFetcherAsync(config: ImportContextConfig) {
30
+ const getEnvironmentDataAsync = async (): Promise<ImportContextEnvironmentData> => {
31
+ const mapiUtils = managementClientUtils(config.managementClient, config.logger);
32
+
33
+ return await config.logger.logWithSpinnerAsync(async (spinnerData) => {
34
+ spinnerData({ type: 'info', message: `Loading environment data` });
35
+
36
+ const environmentData: ImportContextEnvironmentData = {
37
+ collections: await mapiUtils.getAllCollectionsAsync(spinnerData),
38
+ languages: await mapiUtils.getAllLanguagesAsync(spinnerData),
39
+ workflows: await mapiUtils.getAllWorkflowsAsync(spinnerData),
40
+ types: await mapiUtils.getFlattenedContentTypesAsync(spinnerData)
41
+ };
42
+
43
+ spinnerData({ type: 'info', message: `Environmental data loaded` });
44
+
45
+ return environmentData;
46
+ });
47
+ };
48
+
49
+ const environmentData = await getEnvironmentDataAsync();
50
+
51
+ const getElement = () => {
52
+ const getFlattenedElement: GetFlattenedElementByCodenames = (
53
+ contentTypeCodename,
54
+ elementCodename,
55
+ sourceType
56
+ ) => {
57
+ const contentType = findRequired(
58
+ environmentData.types,
59
+ (type) => type.contentTypeCodename === contentTypeCodename,
60
+ `Content type with codename '${chalk.red(contentTypeCodename)}' was not found.`
61
+ );
62
+
63
+ const element = findRequired(
64
+ contentType.elements,
65
+ (element) => element.codename === elementCodename,
66
+ `Element type with codename '${chalk.red(elementCodename)}' was not found in content type '${chalk.red(
67
+ contentTypeCodename
68
+ )}'. Available elements are '${contentType.elements
69
+ .map((element) => chalk.yellow(element.codename))
70
+ .join(', ')}'`
71
+ );
72
+
73
+ if (sourceType !== element.type) {
74
+ throw Error(
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 getLanguageVariantsAsync = async (
88
+ migrationItems: readonly MigrationItem[]
89
+ ): Promise<readonly LanguageVariantWrapper[]> => {
90
+ return (
91
+ await processItemsAsync<MigrationItem, LanguageVariantWrapper | undefined>({
92
+ action: 'Fetching language variants',
93
+ logger: config.logger,
94
+ parallelLimit: 1,
95
+ items: migrationItems,
96
+ itemInfo: (item) => {
97
+ return {
98
+ itemType: 'languageVariant',
99
+ title: `${item.system.codename} (${item.system.language.codename})`
100
+ };
101
+ },
102
+ processAsync: async (item, logSpinner) => {
103
+ try {
104
+ const languageVariant = await runMapiRequestAsync({
105
+ logger: config.logger,
106
+ func: async () =>
107
+ (
108
+ await config.managementClient
109
+ .viewLanguageVariant()
110
+ .byItemCodename(item.system.codename)
111
+ .byLanguageCodename(item.system.language.codename)
112
+ .toPromise()
113
+ ).data,
114
+ action: 'view',
115
+ type: 'languageVariant',
116
+ logSpinner: logSpinner,
117
+ itemName: `codename -> ${item.system.codename} (${item.system.language.codename})`
118
+ });
119
+
120
+ return {
121
+ languageVariant: languageVariant,
122
+ migrationItem: item
123
+ };
124
+ } catch (error) {
125
+ if (!is404Error(error)) {
126
+ throw error;
127
+ }
128
+
129
+ return undefined;
130
+ }
131
+ }
132
+ })
133
+ ).filter(isNotUndefined);
134
+ };
135
+
136
+ const getContentItemsByCodenamesAsync = async (
137
+ itemCodenames: ReadonlySet<string>
138
+ ): Promise<readonly ContentItemModels.ContentItem[]> => {
139
+ return (
140
+ await processItemsAsync<string, Readonly<ContentItemModels.ContentItem> | undefined>({
141
+ action: 'Fetching content items',
142
+ logger: config.logger,
143
+ parallelLimit: 1,
144
+ items: Array.from(itemCodenames),
145
+ itemInfo: (codename) => {
146
+ return {
147
+ itemType: 'contentItem',
148
+ title: codename
149
+ };
150
+ },
151
+ processAsync: async (codename, logSpinner) => {
152
+ try {
153
+ return await runMapiRequestAsync({
154
+ logger: config.logger,
155
+ func: async () =>
156
+ (
157
+ await config.managementClient.viewContentItem().byItemCodename(codename).toPromise()
158
+ ).data,
159
+ action: 'view',
160
+ type: 'contentItem',
161
+ logSpinner: logSpinner,
162
+ itemName: `codename -> ${codename}`
163
+ });
164
+ } catch (error) {
165
+ if (!is404Error(error)) {
166
+ throw error;
167
+ }
168
+
169
+ return undefined;
170
+ }
171
+ }
172
+ })
173
+ ).filter(isNotUndefined);
174
+ };
175
+
176
+ const getAssetsByCodenamesAsync = async (
177
+ assetCodenames: ReadonlySet<string>
178
+ ): Promise<readonly AssetModels.Asset[]> => {
179
+ return (
180
+ await processItemsAsync<string, Readonly<AssetModels.Asset> | undefined>({
181
+ action: 'Fetching assets',
182
+ logger: config.logger,
183
+ parallelLimit: 1,
184
+ items: Array.from(assetCodenames),
185
+ itemInfo: (codename) => {
186
+ return {
187
+ itemType: 'asset',
188
+ title: codename
189
+ };
190
+ },
191
+ processAsync: async (codename, logSpinner) => {
192
+ try {
193
+ return await runMapiRequestAsync({
194
+ logger: config.logger,
195
+ func: async () =>
196
+ (
197
+ await config.managementClient.viewAsset().byAssetCodename(codename).toPromise()
198
+ ).data,
199
+ action: 'view',
200
+ type: 'asset',
201
+ logSpinner: logSpinner,
202
+ itemName: `codename -> ${codename}`
203
+ });
204
+ } catch (error) {
205
+ if (!is404Error(error)) {
206
+ throw error;
207
+ }
208
+
209
+ return undefined;
210
+ }
211
+ }
212
+ })
213
+ ).filter(isNotUndefined);
214
+ };
215
+
216
+ const getVariantStatesAsync = async (
217
+ migrationItems: readonly MigrationItem[]
218
+ ): Promise<readonly LanguageVariantStateInTargetEnvironmentByCodename[]> => {
219
+ const variants = await getLanguageVariantsAsync(migrationItems);
220
+
221
+ return migrationItems.map<LanguageVariantStateInTargetEnvironmentByCodename>((migrationItem) => {
222
+ const variant = variants.find(
223
+ (m) =>
224
+ m.migrationItem.system.codename === migrationItem.system.codename &&
225
+ m.migrationItem.system.language === migrationItem.system.language
226
+ );
227
+
228
+ const variantWorkflowId = variant?.languageVariant?.workflow?.workflowIdentifier?.id;
229
+ const variantStepId = variant?.languageVariant?.workflow?.stepIdentifier?.id;
230
+
231
+ const workflow = environmentData.workflows.find((workflow) => workflow.id === variantWorkflowId);
232
+
233
+ return {
234
+ itemCodename: migrationItem.system.codename,
235
+ languageCodename: migrationItem.system.language.codename,
236
+ languageVariant: variant?.languageVariant,
237
+ workflow: workflow,
238
+ step: workflow
239
+ ? workflowHelper(environmentData.workflows).getWorkflowStep(workflow, {
240
+ errorMessage: `Could not workflow step with id '${chalk.red(
241
+ variantStepId
242
+ )}' in workflow '${chalk.yellow(workflow.codename)}'`,
243
+ match: (step) => step.id == variantStepId
244
+ })
245
+ : undefined,
246
+ state: variant ? 'exists' : 'doesNotExists'
247
+ };
248
+ });
249
+ };
250
+
251
+ const getItemStatesAsync = async (
252
+ itemCodenames: ReadonlySet<string>
253
+ ): Promise<readonly ItemStateInTargetEnvironmentByCodename[]> => {
254
+ const items = await getContentItemsByCodenamesAsync(itemCodenames);
255
+
256
+ return Array.from(itemCodenames).map<ItemStateInTargetEnvironmentByCodename>((codename) => {
257
+ const item = items.find((m) => m.codename === codename);
258
+ return {
259
+ itemCodename: codename,
260
+ item: item,
261
+ state: item ? 'exists' : 'doesNotExists',
262
+ externalIdToUse: config.externalIdGenerator.contentItemExternalId(codename)
263
+ };
264
+ });
265
+ };
266
+
267
+ const getAssetStatesAsync = async (
268
+ assetCodenames: ReadonlySet<string>
269
+ ): Promise<readonly AssetStateInTargetEnvironmentByCodename[]> => {
270
+ const assets = await getAssetsByCodenamesAsync(assetCodenames);
271
+
272
+ return Array.from(assetCodenames).map<AssetStateInTargetEnvironmentByCodename>((codename) => {
273
+ const asset = assets.find((m) => m.codename === codename);
274
+ return {
275
+ assetCodename: codename,
276
+ asset: asset,
277
+ state: asset ? 'exists' : 'doesNotExists',
278
+ externalIdToUse: config.externalIdGenerator.assetExternalId(codename)
279
+ };
280
+ });
281
+ };
282
+
283
+ const getImportContextAsync = async (): Promise<ImportContext> => {
284
+ const getElementByCodenames: GetFlattenedElementByCodenames = getElement();
285
+
286
+ const referencedData = itemsExtractionProcessor().extractReferencedItemsFromMigrationItems(
287
+ config.migrationData.items.reduce<ExtractItemByCodename[]>((items, item) => {
288
+ return [
289
+ ...items,
290
+ ...item.versions.map((version) => {
291
+ const extractionItem: ExtractItemByCodename = {
292
+ contentTypeCodename: item.system.type.codename,
293
+ elements: version.elements
294
+ };
295
+ return extractionItem;
296
+ })
297
+ ];
298
+ }, []),
299
+ getElementByCodenames
300
+ );
301
+ // fetch all items, including referenced items in content
302
+ const itemCodenamesToCheckInTargetEnv: ReadonlySet<string> = new Set<string>([
303
+ ...referencedData.itemCodenames,
304
+ ...config.migrationData.items.map((m) => m.system.codename)
305
+ ]);
306
+
307
+ // fetch all assets, including referenced assets in content
308
+ const assetCodenamesToCheckInTargetEnv: ReadonlySet<string> = new Set<string>([
309
+ ...referencedData.assetCodenames,
310
+ ...config.migrationData.assets.map((m) => m.codename)
311
+ ]);
312
+
313
+ // prepare state of objects in target environment
314
+ const itemStates: readonly ItemStateInTargetEnvironmentByCodename[] = await getItemStatesAsync(
315
+ itemCodenamesToCheckInTargetEnv
316
+ );
317
+
318
+ const variantStates: readonly LanguageVariantStateInTargetEnvironmentByCodename[] = await getVariantStatesAsync(
319
+ config.migrationData.items
320
+ );
321
+
322
+ const assetStates: readonly AssetStateInTargetEnvironmentByCodename[] = await getAssetStatesAsync(
323
+ assetCodenamesToCheckInTargetEnv
324
+ );
325
+
326
+ return {
327
+ environmentData,
328
+ referencedData,
329
+ categorizedImportData: {
330
+ assets: config.migrationData.assets,
331
+ contentItems: config.migrationData.items
332
+ },
333
+ getItemStateInTargetEnvironment: (itemCodename) => {
334
+ return findRequired(
335
+ itemStates,
336
+ (state) => state.itemCodename === itemCodename,
337
+ `Invalid state for item '${chalk.red(
338
+ itemCodename
339
+ )}'. It is expected that all item states will be initialized`
340
+ );
341
+ },
342
+ getLanguageVariantStateInTargetEnvironment: (itemCodename, languageCodename) => {
343
+ return findRequired(
344
+ variantStates,
345
+ (state) => state.itemCodename === itemCodename && state.languageCodename === languageCodename,
346
+ `Invalid state for language variant '${chalk.red(itemCodename)}' in language '${chalk.red(
347
+ languageCodename
348
+ )}'. It is expected that all variant states will be initialized`
349
+ );
350
+ },
351
+ getAssetStateInTargetEnvironment: (assetCodename) => {
352
+ return findRequired(
353
+ assetStates,
354
+ (state) => state.assetCodename === assetCodename,
355
+ `Invalid state for asset '${chalk.red(
356
+ assetCodename
357
+ )}'. It is expected that all asset states will be initialized`
358
+ );
359
+ },
360
+ getElement: getElementByCodenames
361
+ };
362
+ };
363
+
364
+ return {
365
+ getImportContextAsync
366
+ };
367
+ }
@@ -0,0 +1,103 @@
1
+ import { ContentItemModels, LanguageVariantModels, ManagementClient } from '@kontent-ai/management-sdk';
2
+
3
+ import { defaultExternalIdGenerator, Logger, getDefaultLogger, getMigrationManagementClient } from '../core/index.js';
4
+ import { ImportConfig, ImportContext, ImportResult } from './import.models.js';
5
+ import { assetsImporter } from './importers/assets-importer.js';
6
+ import { contentItemsImporter } from './importers/content-items-importer.js';
7
+ import { languageVariantImporter } from './importers/language-variant-importer.js';
8
+ import { importContextFetcherAsync } from './context/import-context-fetcher.js';
9
+
10
+ export function importManager(config: ImportConfig) {
11
+ const logger: Logger = config.logger ?? getDefaultLogger();
12
+ const targetEnvironmentClient: ManagementClient = getMigrationManagementClient(config);
13
+
14
+ const importAssetsAsync = async (
15
+ importContext: ImportContext
16
+ ): Promise<Pick<ImportResult, 'editedAssets' | 'uploadedAssets'>> => {
17
+ if (!importContext.categorizedImportData.assets.length) {
18
+ logger.log({
19
+ type: 'info',
20
+ message: `There are no assets to import`
21
+ });
22
+ return {
23
+ editedAssets: [],
24
+ uploadedAssets: []
25
+ };
26
+ }
27
+
28
+ return await assetsImporter({
29
+ client: targetEnvironmentClient,
30
+ importContext: importContext,
31
+ logger: logger
32
+ }).importAsync();
33
+ };
34
+ const importContentItemsAsync = async (
35
+ importContext: ImportContext
36
+ ): Promise<readonly Readonly<ContentItemModels.ContentItem>[]> => {
37
+ if (!importContext.categorizedImportData.contentItems.length) {
38
+ logger.log({
39
+ type: 'info',
40
+ message: `There are no content items to import`
41
+ });
42
+ }
43
+
44
+ return await contentItemsImporter({
45
+ client: targetEnvironmentClient,
46
+ importContext: importContext,
47
+ logger: logger
48
+ }).importAsync();
49
+ };
50
+
51
+ const importLanguageVariantsAsync = async (
52
+ importContext: ImportContext,
53
+ contentItems: readonly Readonly<ContentItemModels.ContentItem>[]
54
+ ): Promise<readonly Readonly<LanguageVariantModels.ContentItemLanguageVariant>[]> => {
55
+ if (!importContext.categorizedImportData.contentItems.length) {
56
+ logger.log({
57
+ type: 'info',
58
+ message: `There are no language variants to import`
59
+ });
60
+ }
61
+
62
+ return await languageVariantImporter({
63
+ client: targetEnvironmentClient,
64
+ importContext: importContext,
65
+ logger: logger,
66
+ preparedContentItems: contentItems
67
+ }).importAsync();
68
+ };
69
+
70
+ return {
71
+ async importAsync(): Promise<ImportResult> {
72
+ const importContext = await (
73
+ await importContextFetcherAsync({
74
+ migrationData: config.data,
75
+ externalIdGenerator: config.externalIdGenerator ?? defaultExternalIdGenerator,
76
+ logger: logger,
77
+ managementClient: targetEnvironmentClient
78
+ })
79
+ ).getImportContextAsync();
80
+
81
+ // #1 Assets
82
+ const { editedAssets, uploadedAssets } = await importAssetsAsync(importContext);
83
+
84
+ // #2 Content items
85
+ const contentItems = await importContentItemsAsync(importContext);
86
+
87
+ // #3 Language variants
88
+ const languageVariants = await importLanguageVariantsAsync(importContext, contentItems);
89
+
90
+ logger.log({
91
+ type: 'completed',
92
+ message: `Finished import`
93
+ });
94
+
95
+ return {
96
+ editedAssets,
97
+ uploadedAssets,
98
+ contentItems,
99
+ languageVariants
100
+ };
101
+ }
102
+ };
103
+ }
@@ -0,0 +1,84 @@
1
+ import {
2
+ MigrationItem,
3
+ MigrationAsset,
4
+ Logger,
5
+ AssetStateInTargetEnvironmentByCodename,
6
+ ItemStateInTargetEnvironmentByCodename,
7
+ ReferencedDataInMigrationItems,
8
+ LanguageVariantStateInTargetEnvironmentByCodename,
9
+ ExternalIdGenerator,
10
+ FlattenedContentTypeElement,
11
+ MigrationElementValue,
12
+ MigrationElementType,
13
+ MigrationData,
14
+ ManagementClientConfig,
15
+ FlattenedContentType
16
+ } from '../core/index.js';
17
+ import {
18
+ AssetModels,
19
+ CollectionModels,
20
+ ContentItemModels,
21
+ ElementContracts,
22
+ LanguageModels,
23
+ LanguageVariantModels,
24
+ ManagementClient,
25
+ WorkflowModels
26
+ } from '@kontent-ai/management-sdk';
27
+
28
+ export interface ImportContextConfig {
29
+ readonly logger: Logger;
30
+ readonly managementClient: Readonly<ManagementClient>;
31
+ readonly externalIdGenerator: ExternalIdGenerator;
32
+ readonly migrationData: MigrationData;
33
+ }
34
+
35
+ export interface ImportContextEnvironmentData {
36
+ readonly languages: readonly Readonly<LanguageModels.LanguageModel>[];
37
+ readonly collections: readonly Readonly<CollectionModels.Collection>[];
38
+ readonly workflows: readonly Readonly<WorkflowModels.Workflow>[];
39
+ readonly types: readonly Readonly<FlattenedContentType>[];
40
+ }
41
+
42
+ export type GetFlattenedElementByCodenames = (
43
+ contentTypeCodename: string,
44
+ elementCodename: string,
45
+ expectedElementType: MigrationElementType
46
+ ) => FlattenedContentTypeElement;
47
+
48
+ export interface CategorizedImportData {
49
+ readonly assets: readonly MigrationAsset[];
50
+ readonly contentItems: readonly MigrationItem[];
51
+ }
52
+
53
+ export interface ImportContext {
54
+ readonly categorizedImportData: CategorizedImportData;
55
+ readonly referencedData: ReferencedDataInMigrationItems;
56
+ readonly environmentData: ImportContextEnvironmentData;
57
+ readonly getItemStateInTargetEnvironment: (itemCodename: string) => ItemStateInTargetEnvironmentByCodename;
58
+ readonly getLanguageVariantStateInTargetEnvironment: (
59
+ itemCodename: string,
60
+ languageCodename: string
61
+ ) => LanguageVariantStateInTargetEnvironmentByCodename;
62
+ readonly getAssetStateInTargetEnvironment: (assetCodename: string) => AssetStateInTargetEnvironmentByCodename;
63
+ readonly getElement: GetFlattenedElementByCodenames;
64
+ }
65
+
66
+ export type ImportTransformFunc = (data: {
67
+ readonly value: MigrationElementValue;
68
+ readonly elementCodename: string;
69
+ readonly importContext: ImportContext;
70
+ readonly migrationItems: readonly MigrationItem[];
71
+ }) => ElementContracts.IContentItemElementContract;
72
+
73
+ export interface ImportConfig extends ManagementClientConfig {
74
+ readonly data: MigrationData;
75
+ readonly externalIdGenerator?: ExternalIdGenerator;
76
+ readonly logger?: Logger;
77
+ }
78
+
79
+ export interface ImportResult {
80
+ readonly uploadedAssets: readonly Readonly<AssetModels.Asset>[];
81
+ readonly editedAssets: readonly Readonly<AssetModels.Asset>[];
82
+ readonly contentItems: readonly Readonly<ContentItemModels.ContentItem>[];
83
+ readonly languageVariants: readonly Readonly<LanguageVariantModels.ContentItemLanguageVariant>[];
84
+ }