@kontent-ai/migration-toolkit 1.4.0 → 1.5.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 (83) hide show
  1. package/README.md +1 -4
  2. package/dist/es2022/core/helpers/workflow-helper.d.ts +1 -0
  3. package/dist/es2022/core/helpers/workflow-helper.js +6 -4
  4. package/dist/es2022/core/helpers/workflow-helper.js.map +1 -1
  5. package/dist/es2022/core/logs/loggers.js +13 -22
  6. package/dist/es2022/core/logs/loggers.js.map +1 -1
  7. package/dist/es2022/core/models/core.models.d.ts +16 -6
  8. package/dist/es2022/core/models/migration.schema.d.ts +247 -0
  9. package/dist/es2022/core/models/migration.schema.js +12 -2
  10. package/dist/es2022/core/models/migration.schema.js.map +1 -1
  11. package/dist/es2022/core/utils/array.utils.js.map +1 -1
  12. package/dist/es2022/core/utils/binary-data.utils.js +2 -6
  13. package/dist/es2022/core/utils/binary-data.utils.js.map +1 -1
  14. package/dist/es2022/core/utils/confirm.utils.js +10 -14
  15. package/dist/es2022/core/utils/confirm.utils.js.map +1 -1
  16. package/dist/es2022/core/utils/error.utils.js +35 -27
  17. package/dist/es2022/core/utils/error.utils.js.map +1 -1
  18. package/dist/es2022/core/utils/http.utils.js +7 -11
  19. package/dist/es2022/core/utils/http.utils.js.map +1 -1
  20. package/dist/es2022/core/utils/management-client-utils.d.ts +2 -1
  21. package/dist/es2022/core/utils/management-client-utils.js +11 -1
  22. package/dist/es2022/core/utils/management-client-utils.js.map +1 -1
  23. package/dist/es2022/core/utils/run.utils.js +12 -10
  24. package/dist/es2022/core/utils/run.utils.js.map +1 -1
  25. package/dist/es2022/export/context/export-context-fetcher.js +2 -1
  26. package/dist/es2022/export/context/export-context-fetcher.js.map +1 -1
  27. package/dist/es2022/export/export-manager.js +8 -0
  28. package/dist/es2022/export/export-manager.js.map +1 -1
  29. package/dist/es2022/export/export.models.d.ts +2 -1
  30. package/dist/es2022/import/comparers/asset-comparer.d.ts +2 -1
  31. package/dist/es2022/import/comparers/asset-comparer.js +9 -17
  32. package/dist/es2022/import/comparers/asset-comparer.js.map +1 -1
  33. package/dist/es2022/import/context/import-context-fetcher.js +120 -40
  34. package/dist/es2022/import/context/import-context-fetcher.js.map +1 -1
  35. package/dist/es2022/import/import.models.d.ts +2 -1
  36. package/dist/es2022/import/importers/assets-importer.js +25 -7
  37. package/dist/es2022/import/importers/assets-importer.js.map +1 -1
  38. package/dist/es2022/import/importers/language-variant-importer.js +95 -87
  39. package/dist/es2022/import/importers/language-variant-importer.js.map +1 -1
  40. package/dist/es2022/import/importers/workflow-importer.d.ts +41 -4
  41. package/dist/es2022/import/importers/workflow-importer.js +158 -17
  42. package/dist/es2022/import/importers/workflow-importer.js.map +1 -1
  43. package/dist/es2022/metadata.js +2 -2
  44. package/dist/es2022/node/cli/app.js +8 -12
  45. package/dist/es2022/node/cli/app.js.map +1 -1
  46. package/dist/es2022/node/cli/args/args-fetcher.js +9 -10
  47. package/dist/es2022/node/cli/args/args-fetcher.js.map +1 -1
  48. package/dist/es2022/toolkit/migrate.d.ts +1 -3
  49. package/dist/es2022/toolkit/migrate.js.map +1 -1
  50. package/dist/es2022/translation/extraction/items-extraction.processor.js +17 -17
  51. package/dist/es2022/translation/extraction/items-extraction.processor.js.map +1 -1
  52. package/dist/es2022/zip/zip-packager.js +13 -18
  53. package/dist/es2022/zip/zip-packager.js.map +1 -1
  54. package/dist/es2022/zip/zip-transformer.js +3 -1
  55. package/dist/es2022/zip/zip-transformer.js.map +1 -1
  56. package/lib/core/helpers/workflow-helper.ts +8 -8
  57. package/lib/core/logs/loggers.ts +14 -22
  58. package/lib/core/models/core.models.ts +23 -4
  59. package/lib/core/models/migration.schema.ts +13 -2
  60. package/lib/core/utils/array.utils.ts +2 -10
  61. package/lib/core/utils/binary-data.utils.ts +2 -7
  62. package/lib/core/utils/confirm.utils.ts +18 -24
  63. package/lib/core/utils/error.utils.ts +50 -30
  64. package/lib/core/utils/http.utils.ts +14 -15
  65. package/lib/core/utils/management-client-utils.ts +188 -176
  66. package/lib/core/utils/run.utils.ts +27 -18
  67. package/lib/export/context/export-context-fetcher.ts +2 -1
  68. package/lib/export/export-manager.ts +14 -3
  69. package/lib/export/export.models.ts +3 -1
  70. package/lib/import/comparers/asset-comparer.ts +16 -24
  71. package/lib/import/context/import-context-fetcher.ts +179 -85
  72. package/lib/import/import.models.ts +2 -0
  73. package/lib/import/importers/assets-importer.ts +41 -25
  74. package/lib/import/importers/language-variant-importer.ts +119 -111
  75. package/lib/import/importers/workflow-importer.ts +228 -20
  76. package/lib/metadata.ts +2 -2
  77. package/lib/node/cli/app.ts +11 -12
  78. package/lib/node/cli/args/args-fetcher.ts +12 -14
  79. package/lib/toolkit/migrate.ts +1 -3
  80. package/lib/translation/extraction/items-extraction.processor.ts +93 -93
  81. package/lib/zip/zip-packager.ts +26 -28
  82. package/lib/zip/zip-transformer.ts +3 -1
  83. package/package.json +13 -12
@@ -1,8 +1,9 @@
1
1
  import yargs from 'yargs';
2
2
  import { hideBin } from 'yargs/helpers';
3
3
  import chalk from 'chalk';
4
- import { CliAction, exitProgram } from '../../../core/index.js';
4
+ import { CliAction, exitProgram, LiteralUnion } from '../../../core/index.js';
5
5
  import { CliArgumentsFetcher } from '../cli.models.js';
6
+ import { match } from 'ts-pattern';
6
7
 
7
8
  type ArgvResult = {
8
9
  [x: string]: unknown;
@@ -20,19 +21,16 @@ export async function argumentsFetcherAsync(): Promise<CliArgumentsFetcher> {
20
21
 
21
22
  return {
22
23
  getCliAction(): CliAction {
23
- const command = resolvedArgv._?.[0]?.toString()?.toLowerCase();
24
-
25
- if (command === <CliAction>'export') {
26
- return 'export';
27
- }
28
- if (command === <CliAction>'import') {
29
- return 'import';
30
- }
31
- if (command === <CliAction>'migrate') {
32
- return 'migrate';
33
- }
34
-
35
- throw Error(`Unsupported command '${chalk.yellow(command)}'`);
24
+ const command = resolvedArgv._?.[0]?.toString()?.toLowerCase() as LiteralUnion<CliAction>;
25
+
26
+ return match(command)
27
+ .returnType<CliAction>()
28
+ .with('export', () => 'export')
29
+ .with('import', () => 'import')
30
+ .with('migrate', () => 'migrate')
31
+ .otherwise(() => {
32
+ throw Error(`Unsupported command '${chalk.yellow(command)}'`);
33
+ });
36
34
  },
37
35
  getOptionalArgumentValue(argName: string): string | undefined {
38
36
  return resolvedArgv[argName]?.toString();
@@ -17,14 +17,12 @@ export interface MigrationSource extends ManagementClientConfig {
17
17
  readonly items: readonly SourceExportItem[];
18
18
  }
19
19
 
20
- export interface MigrationTarget extends ManagementClientConfig {}
21
-
22
20
  export interface MigrationConfig {
23
21
  readonly retryStrategy?: IRetryStrategyOptions;
24
22
  readonly externalIdGenerator?: ExternalIdGenerator;
25
23
  readonly logger?: Logger;
26
24
  readonly sourceEnvironment: MigrationSource;
27
- readonly targetEnvironment: MigrationTarget;
25
+ readonly targetEnvironment: ManagementClientConfig;
28
26
  }
29
27
 
30
28
  export interface MigrationResult {
@@ -9,6 +9,7 @@ import {
9
9
  import { GetFlattenedElementByCodenames } from '../../import/index.js';
10
10
  import { ElementModels } from '@kontent-ai/management-sdk';
11
11
  import { GetFlattenedElementByIds } from 'lib/export/export.models.js';
12
+ import { match, P } from 'ts-pattern';
12
13
 
13
14
  export interface ExtractItemById {
14
15
  readonly elements: Readonly<ElementModels.ContentItemElement>[];
@@ -40,45 +41,49 @@ export function itemsExtractionProcessor() {
40
41
  return item.elements.reduce<ReferencedDataInLanguageVariantsLocal>((childExtractedIds, itemElement) => {
41
42
  const typeElement = getElement(item.contentTypeId, itemElement.element.id ?? '');
42
43
 
43
- if (typeElement.type === 'rich_text') {
44
- const rteValue = itemElement.value?.toString();
45
-
46
- // extract referenced items
47
- richTextProcessor()
48
- .processDataIds(rteValue ?? '')
49
- .ids.forEach((id) => extractedIds.itemIds.add(id));
50
-
51
- richTextProcessor()
52
- .processLinkItemIds(rteValue ?? '')
53
- .ids.forEach((id) => extractedIds.itemIds.add(id));
54
-
55
- // extract referenced assets
56
- richTextProcessor()
57
- .processAssetIds(rteValue ?? '')
58
- .ids.forEach((id) => extractedIds.assetIds.add(id));
59
-
60
- // recursively extract data from components as well because they may reference additional assets & content items
61
- const extractedComponents = extractReferencedDataFromExtractItems(
62
- itemElement.components.map((component) => {
63
- return {
64
- contentTypeId: component.type.id ?? '',
65
- elements: component.elements
66
- };
67
- }),
68
- getElement
69
- );
70
-
71
- extractedComponents.itemIds.forEach((id) => extractedIds.itemIds.add(id));
72
- extractedComponents.assetIds.forEach((id) => extractedIds.assetIds.add(id));
73
- } else if (typeElement.type === 'modular_content' || typeElement.type === 'subpages') {
74
- if (itemElement.value && Array.isArray(itemElement.value)) {
75
- itemElement.value.forEach((value) => (value.id ? extractedIds.itemIds.add(value.id) : {}));
76
- }
77
- } else if (typeElement.type === 'asset') {
78
- if (itemElement.value && Array.isArray(itemElement.value)) {
79
- itemElement.value.forEach((value) => (value.id ? extractedIds.assetIds.add(value.id) : {}));
80
- }
81
- }
44
+ match(typeElement.type)
45
+ .with('rich_text', () => {
46
+ const rteValue = itemElement.value?.toString();
47
+
48
+ // extract referenced items
49
+ richTextProcessor()
50
+ .processDataIds(rteValue ?? '')
51
+ .ids.forEach((id) => extractedIds.itemIds.add(id));
52
+
53
+ richTextProcessor()
54
+ .processLinkItemIds(rteValue ?? '')
55
+ .ids.forEach((id) => extractedIds.itemIds.add(id));
56
+
57
+ // extract referenced assets
58
+ richTextProcessor()
59
+ .processAssetIds(rteValue ?? '')
60
+ .ids.forEach((id) => extractedIds.assetIds.add(id));
61
+
62
+ // recursively extract data from components as well because they may reference additional assets & content items
63
+ const extractedComponents = extractReferencedDataFromExtractItems(
64
+ itemElement.components.map((component) => {
65
+ return {
66
+ contentTypeId: component.type.id ?? '',
67
+ elements: component.elements
68
+ };
69
+ }),
70
+ getElement
71
+ );
72
+
73
+ extractedComponents.itemIds.forEach((id) => extractedIds.itemIds.add(id));
74
+ extractedComponents.assetIds.forEach((id) => extractedIds.assetIds.add(id));
75
+ })
76
+ .with(P.union('modular_content', 'subpages'), () => {
77
+ if (itemElement.value && Array.isArray(itemElement.value)) {
78
+ itemElement.value.forEach((value) => (value.id ? extractedIds.itemIds.add(value.id) : {}));
79
+ }
80
+ })
81
+ .with('asset', () => {
82
+ if (itemElement.value && Array.isArray(itemElement.value)) {
83
+ itemElement.value.forEach((value) => (value.id ? extractedIds.assetIds.add(value.id) : {}));
84
+ }
85
+ })
86
+ .otherwise(() => {});
82
87
 
83
88
  return childExtractedIds;
84
89
  }, extractedIds);
@@ -102,60 +107,55 @@ export function itemsExtractionProcessor() {
102
107
  (childExtractedCodenames, [elementCodename, element]) => {
103
108
  const flattenedElement = getElement(item.contentTypeCodename, elementCodename, element.type);
104
109
 
105
- if (flattenedElement.type === 'rich_text') {
106
- const richTextElementValue = element as MigrationElementModels.RichTextElement;
107
-
108
- if (!richTextElementValue.value) {
109
- return childExtractedCodenames;
110
- }
111
-
112
- const richTextHtml = richTextElementValue.value?.value ?? '';
113
-
114
- // items
115
- richTextProcessor()
116
- .processItemCodenames(richTextHtml)
117
- .codenames.forEach((codename) => childExtractedCodenames.itemCodenames.add(codename));
118
-
119
- richTextProcessor()
120
- .processLinkItemCodenames(richTextHtml)
121
- .codenames.forEach((codename) => childExtractedCodenames.itemCodenames.add(codename));
122
-
123
- // assets
124
- richTextProcessor()
125
- .processAssetCodenames(richTextHtml)
126
- .codenames.forEach((codename) => childExtractedCodenames.assetCodenames.add(codename));
127
-
128
- // recursively extract data from components as well because they may reference additional assets & content items
129
- const extractedComponents = extractReferencedItemsFromMigrationItems(
130
- richTextElementValue.value.components.map((component) => {
131
- const extractionItem: ExtractItemByCodename = {
132
- contentTypeCodename: component.system.type.codename,
133
- elements: component.elements
134
- };
135
-
136
- return extractionItem;
137
- }),
138
- getElement
139
- );
140
-
141
- extractedComponents.itemCodenames.forEach((codename) =>
142
- childExtractedCodenames.itemCodenames.add(codename)
143
- );
144
- extractedComponents.assetCodenames.forEach((codename) =>
145
- childExtractedCodenames.assetCodenames.add(codename)
146
- );
147
- } else if (
148
- flattenedElement.type === 'modular_content' ||
149
- flattenedElement.type === 'subpages'
150
- ) {
151
- parseAsMigrationReferencesArray(element.value)
152
- .map((m) => m.codename)
153
- .forEach((codename) => childExtractedCodenames.itemCodenames.add(codename));
154
- } else if (flattenedElement.type === 'asset') {
155
- parseAsMigrationReferencesArray(element.value)
156
- .map((m) => m.codename)
157
- .forEach((codename) => childExtractedCodenames.assetCodenames.add(codename));
158
- }
110
+ match(flattenedElement.type)
111
+ .with('rich_text', () => {
112
+ const richTextElementValue = element as MigrationElementModels.RichTextElement;
113
+ const richTextHtml = richTextElementValue.value?.value ?? '';
114
+
115
+ // items
116
+ richTextProcessor()
117
+ .processItemCodenames(richTextHtml)
118
+ .codenames.forEach((codename) => childExtractedCodenames.itemCodenames.add(codename));
119
+
120
+ richTextProcessor()
121
+ .processLinkItemCodenames(richTextHtml)
122
+ .codenames.forEach((codename) => childExtractedCodenames.itemCodenames.add(codename));
123
+
124
+ // assets
125
+ richTextProcessor()
126
+ .processAssetCodenames(richTextHtml)
127
+ .codenames.forEach((codename) => childExtractedCodenames.assetCodenames.add(codename));
128
+
129
+ // recursively extract data from components as well because they may reference additional assets & content items
130
+ const extractedComponents = extractReferencedItemsFromMigrationItems(
131
+ (richTextElementValue.value?.components ?? []).map((component) => {
132
+ const extractionItem: ExtractItemByCodename = {
133
+ contentTypeCodename: component.system.type.codename,
134
+ elements: component.elements
135
+ };
136
+
137
+ return extractionItem;
138
+ }),
139
+ getElement
140
+ );
141
+
142
+ extractedComponents.itemCodenames.forEach((codename) =>
143
+ childExtractedCodenames.itemCodenames.add(codename)
144
+ );
145
+ extractedComponents.assetCodenames.forEach((codename) =>
146
+ childExtractedCodenames.assetCodenames.add(codename)
147
+ );
148
+ })
149
+ .with(P.union('modular_content', 'subpages'), () => {
150
+ parseAsMigrationReferencesArray(element.value)
151
+ .map((m) => m.codename)
152
+ .forEach((codename) => childExtractedCodenames.itemCodenames.add(codename));
153
+ })
154
+ .with('asset', () => {
155
+ parseAsMigrationReferencesArray(element.value)
156
+ .map((m) => m.codename)
157
+ .forEach((codename) => childExtractedCodenames.assetCodenames.add(codename));
158
+ });
159
159
 
160
160
  return childExtractedCodenames;
161
161
  },
@@ -2,33 +2,34 @@ import JSZip from 'jszip';
2
2
  import chalk from 'chalk';
3
3
  import { Logger, formatBytes, getCurrentEnvironment, exitProgram, getDefaultLogger } from '../core/index.js';
4
4
  import { FileBinaryData, ZipCompressionLevel, ZipPackager } from './zip.models.js';
5
+ import { match } from 'ts-pattern';
6
+
7
+ type ZipOutputType = 'nodebuffer' | 'blob';
5
8
 
6
9
  export function zipPackager(jsZip: JSZip): ZipPackager {
7
10
  const getZipOutputType = (): 'nodebuffer' | 'blob' => {
8
- const currentEnv = getCurrentEnvironment();
9
-
10
- if (currentEnv === 'browser') {
11
- return 'blob';
12
- }
13
- if (currentEnv === 'node') {
14
- return 'nodebuffer';
15
- }
16
-
17
- exitProgram({
18
- message: `Unsupported context`
19
- });
11
+ return match(getCurrentEnvironment())
12
+ .returnType<ZipOutputType>()
13
+ .with('browser', () => 'blob')
14
+ .with('node', () => 'nodebuffer')
15
+ .exhaustive();
20
16
  };
21
17
 
22
18
  const getZipSizeInBytes = (zipData: FileBinaryData): number => {
23
- if (zipData instanceof Blob) {
24
- return zipData.size;
25
- } else if (zipData instanceof Buffer) {
26
- return zipData.byteLength;
27
- }
28
-
29
- exitProgram({
30
- message: `Unrecognized zip data type '${typeof zipData}'`
31
- });
19
+ return match(zipData)
20
+ .when(
21
+ (data) => data instanceof Blob,
22
+ (data) => data.size
23
+ )
24
+ .when(
25
+ (data) => data instanceof Buffer,
26
+ (data) => data.byteLength
27
+ )
28
+ .otherwise(() => {
29
+ exitProgram({
30
+ message: `Unrecognized zip data type '${typeof zipData}'`
31
+ });
32
+ });
32
33
  };
33
34
 
34
35
  return {
@@ -44,19 +45,16 @@ export function zipPackager(jsZip: JSZip): ZipPackager {
44
45
 
45
46
  return zipPackager(folder);
46
47
  },
47
- async generateZipAsync(config: {
48
- logger?: Logger;
49
- compressionLevel?: ZipCompressionLevel;
50
- }): Promise<FileBinaryData> {
48
+ async generateZipAsync(config: { logger?: Logger; compressionLevel?: ZipCompressionLevel }): Promise<FileBinaryData> {
51
49
  const logger = config.logger ?? getDefaultLogger();
52
50
  const zipOutputType = getZipOutputType();
53
51
  const compressionLevel: ZipCompressionLevel = config.compressionLevel ?? 9;
54
52
 
55
53
  logger.log({
56
54
  type: 'info',
57
- message: `Creating zip file using '${chalk.yellow(
58
- zipOutputType
59
- )}' with compression level '${chalk.yellow(compressionLevel.toString())}'`
55
+ message: `Creating zip file using '${chalk.yellow(zipOutputType)}' with compression level '${chalk.yellow(
56
+ compressionLevel.toString()
57
+ )}'`
60
58
  });
61
59
 
62
60
  const result = await jsZip.generateAsync({
@@ -48,7 +48,8 @@ export function zipTransformer(zip: ZipPackager, logger?: Logger) {
48
48
  title: asset.title,
49
49
  codename: asset.codename,
50
50
  collection: asset.collection,
51
- descriptions: asset.descriptions
51
+ descriptions: asset.descriptions,
52
+ folder: asset.folder
52
53
  });
53
54
 
54
55
  if (asset.binaryData) {
@@ -91,6 +92,7 @@ export function zipTransformer(zip: ZipPackager, logger?: Logger) {
91
92
  collection: assetRecord.collection,
92
93
  title: assetRecord.title,
93
94
  descriptions: assetRecord.descriptions,
95
+ folder: assetRecord.folder,
94
96
  binaryData: binaryFile
95
97
  };
96
98
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontent-ai/migration-toolkit",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
4
4
  "description": "This program can be used to import content related data into Kontent.ai from various formats. Additionally, it can also be used to export Kontent.ai data using Delivery API.",
5
5
  "preferGlobal": true,
6
6
  "private": false,
@@ -52,8 +52,8 @@
52
52
  ],
53
53
  "license": "MIT",
54
54
  "dependencies": {
55
- "@kontent-ai-consulting/tools-analytics": "0.0.6",
56
- "@kontent-ai/management-sdk": "7.0.0",
55
+ "@kontent-ai-consulting/tools-analytics": "0.0.7",
56
+ "@kontent-ai/management-sdk": "7.2.0",
57
57
  "browser-or-node": "3.0.0",
58
58
  "bytes": "3.1.2",
59
59
  "chalk": "5.3.0",
@@ -65,24 +65,25 @@
65
65
  "yargs": "17.7.2",
66
66
  "p-limit": "6.1.0",
67
67
  "deep-equal": "2.2.3",
68
- "zod": "3.23.8"
68
+ "zod": "3.23.8",
69
+ "ts-pattern": "5.3.1"
69
70
  },
70
71
  "devDependencies": {
71
- "@eslint/js": "9.8.0",
72
+ "@eslint/js": "9.9.0",
72
73
  "@types/deep-equal": "1.0.4",
73
74
  "@types/browser-or-node": "1.3.2",
74
75
  "@types/bytes": "3.1.4",
75
76
  "@types/eslint__js": "8.42.3",
76
- "@types/node": "22.0.0",
77
+ "@types/node": "22.3.0",
77
78
  "@types/prompts": "2.4.9",
78
- "@types/yargs": "17.0.32",
79
- "@typescript-eslint/eslint-plugin": "7.17.0",
80
- "@typescript-eslint/parser": "7.17.0",
81
- "eslint": "8.57.0",
79
+ "@types/yargs": "17.0.33",
80
+ "@typescript-eslint/eslint-plugin": "8.1.0",
81
+ "@typescript-eslint/parser": "8.1.0",
82
+ "eslint": "9.9.0",
82
83
  "standard-version": "9.5.0",
83
84
  "tslib": "2.6.3",
84
- "tsx": "4.16.2",
85
+ "tsx": "4.17.0",
85
86
  "typescript": "5.5.4",
86
- "typescript-eslint": "7.17.0"
87
+ "typescript-eslint": "8.1.0"
87
88
  }
88
89
  }