@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.
- package/.npmignore +13 -0
- package/LICENSE.md +9 -0
- package/README.md +272 -0
- package/dist/es2022/core/helpers/workflow-helper.d.ts +37 -0
- package/dist/es2022/core/helpers/workflow-helper.js +67 -0
- package/dist/es2022/core/helpers/workflow-helper.js.map +1 -0
- package/dist/es2022/core/index.d.ts +15 -0
- package/dist/es2022/core/index.js +16 -0
- package/dist/es2022/core/index.js.map +1 -0
- package/dist/es2022/core/logs/loggers.d.ts +2 -0
- package/dist/es2022/core/logs/loggers.js +69 -0
- package/dist/es2022/core/logs/loggers.js.map +1 -0
- package/dist/es2022/core/models/core.models.d.ts +91 -0
- package/dist/es2022/core/models/core.models.js +2 -0
- package/dist/es2022/core/models/core.models.js.map +1 -0
- package/dist/es2022/core/models/log.models.d.ts +15 -0
- package/dist/es2022/core/models/log.models.js +2 -0
- package/dist/es2022/core/models/log.models.js.map +1 -0
- package/dist/es2022/core/models/migration.models.d.ts +136 -0
- package/dist/es2022/core/models/migration.models.js +2 -0
- package/dist/es2022/core/models/migration.models.js.map +1 -0
- package/dist/es2022/core/utils/array.utils.d.ts +5 -0
- package/dist/es2022/core/utils/array.utils.js +27 -0
- package/dist/es2022/core/utils/array.utils.js.map +1 -0
- package/dist/es2022/core/utils/binary-data.utils.d.ts +5 -0
- package/dist/es2022/core/utils/binary-data.utils.js +21 -0
- package/dist/es2022/core/utils/binary-data.utils.js.map +1 -0
- package/dist/es2022/core/utils/confirm.utils.d.ts +31 -0
- package/dist/es2022/core/utils/confirm.utils.js +73 -0
- package/dist/es2022/core/utils/confirm.utils.js.map +1 -0
- package/dist/es2022/core/utils/error.utils.d.ts +4 -0
- package/dist/es2022/core/utils/error.utils.js +50 -0
- package/dist/es2022/core/utils/error.utils.js.map +1 -0
- package/dist/es2022/core/utils/external-id.utils.d.ts +5 -0
- package/dist/es2022/core/utils/external-id.utils.js +5 -0
- package/dist/es2022/core/utils/external-id.utils.js.map +1 -0
- package/dist/es2022/core/utils/global.utils.d.ts +14 -0
- package/dist/es2022/core/utils/global.utils.js +45 -0
- package/dist/es2022/core/utils/global.utils.js.map +1 -0
- package/dist/es2022/core/utils/http.utils.d.ts +3 -0
- package/dist/es2022/core/utils/http.utils.js +29 -0
- package/dist/es2022/core/utils/http.utils.js.map +1 -0
- package/dist/es2022/core/utils/management-client-utils.d.ts +19 -0
- package/dist/es2022/core/utils/management-client-utils.js +129 -0
- package/dist/es2022/core/utils/management-client-utils.js.map +1 -0
- package/dist/es2022/core/utils/processing-utils.d.ts +12 -0
- package/dist/es2022/core/utils/processing-utils.js +39 -0
- package/dist/es2022/core/utils/processing-utils.js.map +1 -0
- package/dist/es2022/core/utils/run.utils.d.ts +10 -0
- package/dist/es2022/core/utils/run.utils.js +37 -0
- package/dist/es2022/core/utils/run.utils.js.map +1 -0
- package/dist/es2022/export/context/export-context-fetcher.d.ts +4 -0
- package/dist/es2022/export/context/export-context-fetcher.js +289 -0
- package/dist/es2022/export/context/export-context-fetcher.js.map +1 -0
- package/dist/es2022/export/export-manager.d.ts +5 -0
- package/dist/es2022/export/export-manager.js +167 -0
- package/dist/es2022/export/export-manager.js.map +1 -0
- package/dist/es2022/export/export.models.d.ts +55 -0
- package/dist/es2022/export/export.models.js +2 -0
- package/dist/es2022/export/export.models.js.map +1 -0
- package/dist/es2022/export/index.d.ts +2 -0
- package/dist/es2022/export/index.js +3 -0
- package/dist/es2022/export/index.js.map +1 -0
- package/dist/es2022/export/utils/export.utils.d.ts +2 -0
- package/dist/es2022/export/utils/export.utils.js +5 -0
- package/dist/es2022/export/utils/export.utils.js.map +1 -0
- package/dist/es2022/file/file-manager.d.ts +5 -0
- package/dist/es2022/file/file-manager.js +29 -0
- package/dist/es2022/file/file-manager.js.map +1 -0
- package/dist/es2022/file/index.d.ts +1 -0
- package/dist/es2022/file/index.js +2 -0
- package/dist/es2022/file/index.js.map +1 -0
- package/dist/es2022/import/comparers/asset-comparer.d.ts +12 -0
- package/dist/es2022/import/comparers/asset-comparer.js +65 -0
- package/dist/es2022/import/comparers/asset-comparer.js.map +1 -0
- package/dist/es2022/import/context/import-context-fetcher.d.ts +4 -0
- package/dist/es2022/import/context/import-context-fetcher.js +235 -0
- package/dist/es2022/import/context/import-context-fetcher.js.map +1 -0
- package/dist/es2022/import/import-manager.d.ts +4 -0
- package/dist/es2022/import/import-manager.js +80 -0
- package/dist/es2022/import/import-manager.js.map +1 -0
- package/dist/es2022/import/import.models.d.ts +45 -0
- package/dist/es2022/import/import.models.js +2 -0
- package/dist/es2022/import/import.models.js.map +1 -0
- package/dist/es2022/import/importers/assets-importer.d.ts +10 -0
- package/dist/es2022/import/importers/assets-importer.js +175 -0
- package/dist/es2022/import/importers/assets-importer.js.map +1 -0
- package/dist/es2022/import/importers/content-items-importer.d.ts +10 -0
- package/dist/es2022/import/importers/content-items-importer.js +97 -0
- package/dist/es2022/import/importers/content-items-importer.js.map +1 -0
- package/dist/es2022/import/importers/language-variant-importer.d.ts +11 -0
- package/dist/es2022/import/importers/language-variant-importer.js +215 -0
- package/dist/es2022/import/importers/language-variant-importer.js.map +1 -0
- package/dist/es2022/import/importers/workflow-importer.d.ts +18 -0
- package/dist/es2022/import/importers/workflow-importer.js +122 -0
- package/dist/es2022/import/importers/workflow-importer.js.map +1 -0
- package/dist/es2022/import/index.d.ts +2 -0
- package/dist/es2022/import/index.js +3 -0
- package/dist/es2022/import/index.js.map +1 -0
- package/dist/es2022/import/utils/import.utils.d.ts +2 -0
- package/dist/es2022/import/utils/import.utils.js +5 -0
- package/dist/es2022/import/utils/import.utils.js.map +1 -0
- package/dist/es2022/index.d.ts +8 -0
- package/dist/es2022/index.js +10 -0
- package/dist/es2022/index.js.map +1 -0
- package/dist/es2022/metadata.d.ts +5 -0
- package/dist/es2022/metadata.js +6 -0
- package/dist/es2022/metadata.js.map +1 -0
- package/dist/es2022/node/cli/actions/export-action.d.ts +2 -0
- package/dist/es2022/node/cli/actions/export-action.js +40 -0
- package/dist/es2022/node/cli/actions/export-action.js.map +1 -0
- package/dist/es2022/node/cli/actions/import-action.d.ts +2 -0
- package/dist/es2022/node/cli/actions/import-action.js +29 -0
- package/dist/es2022/node/cli/actions/import-action.js.map +1 -0
- package/dist/es2022/node/cli/actions/migrate-action.d.ts +2 -0
- package/dist/es2022/node/cli/actions/migrate-action.js +47 -0
- package/dist/es2022/node/cli/actions/migrate-action.js.map +1 -0
- package/dist/es2022/node/cli/app.d.ts +2 -0
- package/dist/es2022/node/cli/app.js +27 -0
- package/dist/es2022/node/cli/app.js.map +1 -0
- package/dist/es2022/node/cli/args/args-fetcher.d.ts +2 -0
- package/dist/es2022/node/cli/args/args-fetcher.js +46 -0
- package/dist/es2022/node/cli/args/args-fetcher.js.map +1 -0
- package/dist/es2022/node/cli/args/args-setter.d.ts +2 -0
- package/dist/es2022/node/cli/args/args-setter.js +31 -0
- package/dist/es2022/node/cli/args/args-setter.js.map +1 -0
- package/dist/es2022/node/cli/cli.models.d.ts +24 -0
- package/dist/es2022/node/cli/cli.models.js +2 -0
- package/dist/es2022/node/cli/cli.models.js.map +1 -0
- package/dist/es2022/node/cli/commands.d.ts +1 -0
- package/dist/es2022/node/cli/commands.js +157 -0
- package/dist/es2022/node/cli/commands.js.map +1 -0
- package/dist/es2022/toolkit/elements-builder.d.ts +14 -0
- package/dist/es2022/toolkit/elements-builder.js +69 -0
- package/dist/es2022/toolkit/elements-builder.js.map +1 -0
- package/dist/es2022/toolkit/export.d.ts +3 -0
- package/dist/es2022/toolkit/export.js +21 -0
- package/dist/es2022/toolkit/export.js.map +1 -0
- package/dist/es2022/toolkit/file.d.ts +12 -0
- package/dist/es2022/toolkit/file.js +50 -0
- package/dist/es2022/toolkit/file.js.map +1 -0
- package/dist/es2022/toolkit/import.d.ts +2 -0
- package/dist/es2022/toolkit/import.js +21 -0
- package/dist/es2022/toolkit/import.js.map +1 -0
- package/dist/es2022/toolkit/index.d.ts +5 -0
- package/dist/es2022/toolkit/index.js +6 -0
- package/dist/es2022/toolkit/index.js.map +1 -0
- package/dist/es2022/toolkit/migrate.d.ts +21 -0
- package/dist/es2022/toolkit/migrate.js +39 -0
- package/dist/es2022/toolkit/migrate.js.map +1 -0
- package/dist/es2022/translation/extraction/items-extraction.processor.d.ts +24 -0
- package/dist/es2022/translation/extraction/items-extraction.processor.js +108 -0
- package/dist/es2022/translation/extraction/items-extraction.processor.js.map +1 -0
- package/dist/es2022/translation/helpers/rich-text.processor.d.ts +22 -0
- package/dist/es2022/translation/helpers/rich-text.processor.js +209 -0
- package/dist/es2022/translation/helpers/rich-text.processor.js.map +1 -0
- package/dist/es2022/translation/index.d.ts +4 -0
- package/dist/es2022/translation/index.js +5 -0
- package/dist/es2022/translation/index.js.map +1 -0
- package/dist/es2022/translation/transforms/export-transforms.d.ts +3 -0
- package/dist/es2022/translation/transforms/export-transforms.js +196 -0
- package/dist/es2022/translation/transforms/export-transforms.js.map +1 -0
- package/dist/es2022/translation/transforms/import-transforms.d.ts +7 -0
- package/dist/es2022/translation/transforms/import-transforms.js +183 -0
- package/dist/es2022/translation/transforms/import-transforms.js.map +1 -0
- package/dist/es2022/zip/index.d.ts +4 -0
- package/dist/es2022/zip/index.js +5 -0
- package/dist/es2022/zip/index.js.map +1 -0
- package/dist/es2022/zip/zip-manager.d.ts +6 -0
- package/dist/es2022/zip/zip-manager.js +27 -0
- package/dist/es2022/zip/zip-manager.js.map +1 -0
- package/dist/es2022/zip/zip-packager.d.ts +3 -0
- package/dist/es2022/zip/zip-packager.js +69 -0
- package/dist/es2022/zip/zip-packager.js.map +1 -0
- package/dist/es2022/zip/zip-transformer.d.ts +6 -0
- package/dist/es2022/zip/zip-transformer.js +82 -0
- package/dist/es2022/zip/zip-transformer.js.map +1 -0
- package/dist/es2022/zip/zip.models.d.ts +13 -0
- package/dist/es2022/zip/zip.models.js +2 -0
- package/dist/es2022/zip/zip.models.js.map +1 -0
- package/lib/core/helpers/workflow-helper.ts +104 -0
- package/lib/core/index.ts +17 -0
- package/lib/core/logs/loggers.ts +80 -0
- package/lib/core/models/core.models.ts +134 -0
- package/lib/core/models/log.models.ts +31 -0
- package/lib/core/models/migration.models.ts +165 -0
- package/lib/core/utils/array.utils.ts +49 -0
- package/lib/core/utils/binary-data.utils.ts +29 -0
- package/lib/core/utils/confirm.utils.ts +139 -0
- package/lib/core/utils/error.utils.ts +65 -0
- package/lib/core/utils/external-id.utils.ts +9 -0
- package/lib/core/utils/global.utils.ts +59 -0
- package/lib/core/utils/http.utils.ts +35 -0
- package/lib/core/utils/management-client-utils.ts +182 -0
- package/lib/core/utils/processing-utils.ts +71 -0
- package/lib/core/utils/run.utils.ts +51 -0
- package/lib/export/context/export-context-fetcher.ts +475 -0
- package/lib/export/export-manager.ts +249 -0
- package/lib/export/export.models.ts +87 -0
- package/lib/export/index.ts +2 -0
- package/lib/export/utils/export.utils.ts +10 -0
- package/lib/file/file-manager.ts +37 -0
- package/lib/file/index.ts +1 -0
- package/lib/import/comparers/asset-comparer.ts +113 -0
- package/lib/import/context/import-context-fetcher.ts +367 -0
- package/lib/import/import-manager.ts +103 -0
- package/lib/import/import.models.ts +84 -0
- package/lib/import/importers/assets-importer.ts +239 -0
- package/lib/import/importers/content-items-importer.ts +142 -0
- package/lib/import/importers/language-variant-importer.ts +342 -0
- package/lib/import/importers/workflow-importer.ts +159 -0
- package/lib/import/index.ts +2 -0
- package/lib/import/utils/import.utils.ts +10 -0
- package/lib/index.ts +9 -0
- package/lib/metadata.ts +6 -0
- package/lib/node/cli/actions/export-action.ts +45 -0
- package/lib/node/cli/actions/import-action.ts +34 -0
- package/lib/node/cli/actions/migrate-action.ts +52 -0
- package/lib/node/cli/app.ts +29 -0
- package/lib/node/cli/args/args-fetcher.ts +61 -0
- package/lib/node/cli/args/args-setter.ts +35 -0
- package/lib/node/cli/cli.models.ts +28 -0
- package/lib/node/cli/commands.ts +161 -0
- package/lib/toolkit/elements-builder.ts +84 -0
- package/lib/toolkit/export.ts +21 -0
- package/lib/toolkit/file.ts +70 -0
- package/lib/toolkit/import.ts +21 -0
- package/lib/toolkit/index.ts +5 -0
- package/lib/toolkit/migrate.ts +71 -0
- package/lib/translation/extraction/items-extraction.processor.ts +181 -0
- package/lib/translation/helpers/rich-text.processor.ts +300 -0
- package/lib/translation/index.ts +4 -0
- package/lib/translation/transforms/export-transforms.ts +253 -0
- package/lib/translation/transforms/import-transforms.ts +215 -0
- package/lib/zip/index.ts +4 -0
- package/lib/zip/zip-manager.ts +33 -0
- package/lib/zip/zip-packager.ts +86 -0
- package/lib/zip/zip-transformer.ts +105 -0
- package/lib/zip/zip.models.ts +12 -0
- 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
|
+
}
|