@kontent-ai/migration-toolkit 3.0.0 → 3.1.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 (74) hide show
  1. package/dist/core/logs/loggers.js.map +1 -1
  2. package/dist/core/models/core.models.d.ts +28 -28
  3. package/dist/core/models/error.models.js +2 -2
  4. package/dist/core/models/error.models.js.map +1 -1
  5. package/dist/core/models/log.models.d.ts +6 -6
  6. package/dist/core/models/migration.schema.d.ts +5 -5
  7. package/dist/core/utils/array.utils.d.ts +1 -2
  8. package/dist/core/utils/array.utils.js.map +1 -1
  9. package/dist/core/utils/confirm.utils.d.ts +9 -2
  10. package/dist/core/utils/confirm.utils.js +42 -4
  11. package/dist/core/utils/confirm.utils.js.map +1 -1
  12. package/dist/core/utils/error.utils.js +6 -0
  13. package/dist/core/utils/error.utils.js.map +1 -1
  14. package/dist/core/utils/external-id.utils.d.ts +2 -2
  15. package/dist/core/utils/global.utils.d.ts +1 -1
  16. package/dist/core/utils/global.utils.js.map +1 -1
  17. package/dist/core/utils/http.utils.d.ts +1 -2
  18. package/dist/core/utils/http.utils.js.map +1 -1
  19. package/dist/core/utils/management-client-utils.d.ts +3 -3
  20. package/dist/core/utils/management-client-utils.js +1 -1
  21. package/dist/core/utils/management-client-utils.js.map +1 -1
  22. package/dist/core/utils/processing-utils.js +2 -2
  23. package/dist/core/utils/processing-utils.js.map +1 -1
  24. package/dist/export/export.models.d.ts +18 -18
  25. package/dist/import/comparers/asset-comparer.js +5 -2
  26. package/dist/import/comparers/asset-comparer.js.map +1 -1
  27. package/dist/import/context/import-context-fetcher.js.map +1 -1
  28. package/dist/import/import.models.d.ts +14 -14
  29. package/dist/import/importers/workflow-importer.d.ts +1 -1
  30. package/dist/import/importers/workflow-importer.js.map +1 -1
  31. package/dist/index.d.ts +1 -0
  32. package/dist/index.js +1 -1
  33. package/dist/index.js.map +1 -1
  34. package/dist/metadata.js +2 -2
  35. package/dist/node/cli/actions/export-action.js +13 -14
  36. package/dist/node/cli/actions/export-action.js.map +1 -1
  37. package/dist/node/cli/actions/import-action.js +13 -4
  38. package/dist/node/cli/actions/import-action.js.map +1 -1
  39. package/dist/node/cli/actions/migrate-action.js +1 -1
  40. package/dist/node/cli/actions/migrate-action.js.map +1 -1
  41. package/dist/node/cli/cli.models.d.ts +4 -4
  42. package/dist/toolkit/file.d.ts +4 -4
  43. package/dist/toolkit/migrate.d.ts +6 -6
  44. package/dist/translation/extraction/items-extraction.processor.d.ts +8 -8
  45. package/dist/translation/transforms/import-transforms.js.map +1 -1
  46. package/lib/core/logs/loggers.ts +1 -2
  47. package/lib/core/models/core.models.ts +28 -28
  48. package/lib/core/models/error.models.ts +2 -2
  49. package/lib/core/models/log.models.ts +6 -6
  50. package/lib/core/models/migration.schema.ts +2 -2
  51. package/lib/core/utils/array.utils.ts +0 -2
  52. package/lib/core/utils/confirm.utils.ts +70 -5
  53. package/lib/core/utils/error.utils.ts +6 -0
  54. package/lib/core/utils/external-id.utils.ts +2 -2
  55. package/lib/core/utils/global.utils.ts +1 -2
  56. package/lib/core/utils/http.utils.ts +1 -2
  57. package/lib/core/utils/management-client-utils.ts +13 -13
  58. package/lib/core/utils/processing-utils.ts +3 -3
  59. package/lib/export/export.models.ts +18 -18
  60. package/lib/import/comparers/asset-comparer.ts +6 -2
  61. package/lib/import/context/import-context-fetcher.ts +3 -4
  62. package/lib/import/import.models.ts +14 -14
  63. package/lib/import/importers/workflow-importer.ts +1 -2
  64. package/lib/index.ts +2 -1
  65. package/lib/metadata.ts +2 -2
  66. package/lib/node/cli/actions/export-action.ts +14 -14
  67. package/lib/node/cli/actions/import-action.ts +15 -6
  68. package/lib/node/cli/actions/migrate-action.ts +1 -1
  69. package/lib/node/cli/cli.models.ts +4 -4
  70. package/lib/toolkit/file.ts +4 -4
  71. package/lib/toolkit/migrate.ts +6 -6
  72. package/lib/translation/extraction/items-extraction.processor.ts +8 -8
  73. package/lib/translation/transforms/import-transforms.ts +1 -2
  74. package/package.json +29 -36
@@ -52,28 +52,28 @@ export type LanguageVariantWorkflowState =
52
52
  }
53
53
  | undefined;
54
54
 
55
- export interface ItemInfo {
55
+ export type ItemInfo = {
56
56
  readonly title: string;
57
57
  readonly itemType: MapiType | MigrationItemType;
58
- }
58
+ };
59
59
 
60
- export interface ErrorData {
60
+ export type ErrorData = {
61
61
  readonly message: string;
62
- readonly requestData?: string;
63
- readonly requestUrl?: string;
62
+ readonly requestData: string | undefined;
63
+ readonly requestUrl: string | undefined;
64
64
  readonly isUnknownError: boolean;
65
65
  readonly error: unknown;
66
- }
66
+ };
67
67
 
68
- export interface ReferencedDataInMigrationItems {
68
+ export type ReferencedDataInMigrationItems = {
69
69
  readonly itemCodenames: ReadonlySet<string>;
70
70
  readonly assetCodenames: ReadonlySet<string>;
71
- }
71
+ };
72
72
 
73
- export interface ReferencedDataInLanguageVariants {
73
+ export type ReferencedDataInLanguageVariants = {
74
74
  readonly itemIds: ReadonlySet<string>;
75
75
  readonly assetIds: ReadonlySet<string>;
76
- }
76
+ };
77
77
 
78
78
  type DataStateInSourceEnvironmentById<T extends Readonly<ContentItemModels.ContentItem> | Readonly<AssetModels.Asset>> = {
79
79
  readonly id: string;
@@ -96,61 +96,61 @@ export type ItemStateInSourceEnvironmentById = DataStateInSourceEnvironmentById<
96
96
 
97
97
  export type AssetStateInSourceEnvironmentById = DataStateInSourceEnvironmentById<Readonly<AssetModels.Asset>>;
98
98
 
99
- export interface ItemStateInTargetEnvironmentByCodename {
99
+ export type ItemStateInTargetEnvironmentByCodename = {
100
100
  readonly state: TargetItemState;
101
101
  readonly itemCodename: string;
102
102
  readonly item: Readonly<ContentItemModels.ContentItem> | undefined;
103
103
  readonly externalIdToUse: string;
104
- }
104
+ };
105
105
 
106
- export interface LanguageVariantStateData {
106
+ export type LanguageVariantStateData = {
107
107
  readonly languageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined;
108
108
  readonly workflow: Readonly<WorkflowModels.Workflow> | undefined;
109
109
  readonly workflowState: LanguageVariantWorkflowState;
110
- }
110
+ };
111
111
 
112
- export interface LanguageVariantStateInTargetEnvironmentByCodename {
112
+ export type LanguageVariantStateInTargetEnvironmentByCodename = {
113
113
  readonly state: TargetItemState;
114
114
  readonly itemCodename: string;
115
115
  readonly languageCodename: string;
116
116
  readonly publishedLanguageVariant: LanguageVariantStateData | undefined;
117
117
  readonly draftLanguageVariant: LanguageVariantStateData | undefined;
118
- }
118
+ };
119
119
 
120
- export interface AssetStateInTargetEnvironmentByCodename {
120
+ export type AssetStateInTargetEnvironmentByCodename = {
121
121
  readonly state: TargetItemState;
122
122
  readonly assetCodename: string;
123
123
  readonly asset: Readonly<AssetModels.Asset> | undefined;
124
124
  readonly externalIdToUse: string;
125
- }
125
+ };
126
126
 
127
- export interface PackageMetadata {
127
+ export type PackageMetadata = {
128
128
  readonly created: Date;
129
129
  readonly environmentId: string;
130
130
  readonly dataOverview: PackageDataOverview;
131
- }
131
+ };
132
132
 
133
- export interface PackageDataOverview {
133
+ export type PackageDataOverview = {
134
134
  readonly contentItemsCount: number;
135
135
  readonly assetsCount: number;
136
- }
136
+ };
137
137
 
138
- export interface FlattenedContentTypeElement {
138
+ export type FlattenedContentTypeElement = {
139
139
  readonly codename: string;
140
140
  readonly name: string | undefined;
141
141
  readonly id: string;
142
142
  readonly type: MigrationElementType;
143
143
  readonly element: Readonly<ContentTypeElements.ContentTypeElementModel>;
144
- }
144
+ };
145
145
 
146
- export interface FlattenedContentType {
146
+ export type FlattenedContentType = {
147
147
  readonly contentTypeCodename: string;
148
148
  readonly name: string;
149
149
  readonly contentTypeId: string;
150
150
  readonly elements: readonly FlattenedContentTypeElement[];
151
- }
151
+ };
152
152
 
153
- export interface OriginalManagementError {
153
+ export type OriginalManagementError = {
154
154
  readonly response?: {
155
155
  readonly status?: number;
156
156
  readonly config?: {
@@ -161,7 +161,7 @@ export interface OriginalManagementError {
161
161
  readonly error_code?: number;
162
162
  };
163
163
  };
164
- }
164
+ };
165
165
 
166
166
  export type ItemProcessingResult<InputItem, OutputItem> =
167
167
  | {
@@ -112,7 +112,7 @@ export class InvalidValueError extends MigrationToolkitError {
112
112
  ` ${chalk.gray("└─")} ID: ${chalk.dim(contentType.contentTypeId)}`,
113
113
  "",
114
114
  `${chalk.cyan("🔧 Element:")}`,
115
- ` ${chalk.gray("├─")} Name: ${chalk.yellow.bold(element.name)}`,
115
+ ` ${chalk.gray("├─")} Name: ${chalk.yellow.bold(element.name ?? "n/a")}`,
116
116
  ` ${chalk.gray("├─")} Codename: ${chalk.yellow.bold(element.codename)}`,
117
117
  ` ${chalk.gray("├─")} Type: ${chalk.green.bold(element.type)}`,
118
118
  ` ${chalk.gray("└─")} ID: ${chalk.dim(element.id)}`,
@@ -124,7 +124,7 @@ export class InvalidValueError extends MigrationToolkitError {
124
124
  "",
125
125
  `${chalk.cyan("📦 Item version:")}`,
126
126
  ` ${chalk.gray("├─")} Workflow step codename: ${chalk.yellow.bold(exportItemVersion.workflowStepCodename)}`,
127
- ` ${chalk.gray("└─")} Language variant: ${chalk.yellow.bold(exportItemVersion.languageVariant.language.codename)}`,
127
+ ` ${chalk.gray("└─")} Language variant: ${chalk.yellow.bold(exportItemVersion.languageVariant.language.codename ?? "n/a")}`,
128
128
  "",
129
129
  chalk.cyan("Invalid Value:"),
130
130
  chalk.dim(getValueToDisplay()),
@@ -16,19 +16,19 @@ export type DebugType =
16
16
  | MapiType
17
17
  | MapiAction;
18
18
 
19
- export interface LogMessage {
19
+ export type LogMessage = {
20
20
  readonly type?: DebugType;
21
21
  readonly message: string;
22
- }
22
+ };
23
23
 
24
- export interface LogSpinnerMessage extends LogMessage {
24
+ export type LogSpinnerMessage = LogMessage & {
25
25
  readonly prefix?: string;
26
- }
26
+ };
27
27
 
28
28
  export type LogData = (data: LogMessage) => void;
29
29
  export type LogSpinnerData = (data: LogSpinnerMessage) => void;
30
30
 
31
- export interface Logger {
31
+ export type Logger = {
32
32
  readonly logWithSpinnerAsync: <T>(func: (logData: LogSpinnerData) => Promise<T>) => Promise<T>;
33
33
  readonly log: LogData;
34
- }
34
+ };
@@ -1,9 +1,9 @@
1
1
  import { Buffer as BufferProxy } from "buffer";
2
2
  import { z } from "zod";
3
3
 
4
- interface Elements {
4
+ type Elements = {
5
5
  readonly [key: string]: Element;
6
- }
6
+ };
7
7
 
8
8
  type UrlSlugMode = "autogenerated" | "custom";
9
9
  type Reference = { readonly codename: string };
@@ -12,8 +12,6 @@ export function parseAsMigrationReferencesArray(value: MigrationElementValue): r
12
12
  throw new MigrationToolkitError("invalidValue", `Value is not an array`);
13
13
  }
14
14
 
15
- export function findRequired<T>(array: readonly T[], predicate: (item: T, index: number) => boolean, errorMessage: string): T;
16
- export function findRequired<T>(array: readonly T[], predicate: (item: T, index: number) => boolean, errorMessage: () => never): T;
17
15
  export function findRequired<T>(
18
16
  array: readonly T[],
19
17
  predicate: (item: T, index: number) => boolean,
@@ -5,6 +5,13 @@ import { MigrationToolkitError } from "../models/error.models.js";
5
5
  import type { Logger } from "../models/log.models.js";
6
6
  import { getMigrationManagementClient, managementClientUtils } from "./management-client-utils.js";
7
7
 
8
+ const maxItemsShownInPreview = 20;
9
+
10
+ export type ItemPreview = {
11
+ readonly itemCodename: string;
12
+ readonly languageCodename: string;
13
+ };
14
+
8
15
  export async function confirmExportAsync(data: {
9
16
  readonly force: boolean;
10
17
  readonly environmentId: string;
@@ -12,7 +19,7 @@ export async function confirmExportAsync(data: {
12
19
  readonly logger: Logger;
13
20
  readonly skipMissingReferences: boolean;
14
21
  readonly dataToExport: {
15
- readonly itemsCount: number;
22
+ readonly exportItems: readonly ItemPreview[];
16
23
  };
17
24
  }): Promise<void> {
18
25
  const environment = await managementClientUtils(
@@ -25,7 +32,8 @@ export async function confirmExportAsync(data: {
25
32
 
26
33
  const text = getConfirmText({
27
34
  action: "export",
28
- itemsCount: data.dataToExport.itemsCount,
35
+ itemsCount: data.dataToExport.exportItems.length,
36
+ exportItems: data.dataToExport.exportItems,
29
37
  sourceEnvironment: environment,
30
38
  skipMissingReferences: data.skipMissingReferences,
31
39
  });
@@ -51,7 +59,7 @@ export async function confirmMigrateAsync(data: {
51
59
  readonly skipMissingReferences: boolean;
52
60
  readonly logger: Logger;
53
61
  readonly dataToMigrate: {
54
- readonly itemsCount: number;
62
+ readonly migrateItems: readonly ItemPreview[];
55
63
  };
56
64
  }): Promise<void> {
57
65
  const sourceEnvironment = await managementClientUtils(
@@ -71,7 +79,8 @@ export async function confirmMigrateAsync(data: {
71
79
 
72
80
  const text = getConfirmText({
73
81
  action: "migrate",
74
- itemsCount: data.dataToMigrate.itemsCount,
82
+ itemsCount: data.dataToMigrate.migrateItems.length,
83
+ migrateItems: data.dataToMigrate.migrateItems,
75
84
  sourceEnvironment,
76
85
  targetEnvironment,
77
86
  skipMissingReferences: data.skipMissingReferences,
@@ -90,6 +99,9 @@ export async function confirmImportAsync(data: {
90
99
  readonly environmentId: string;
91
100
  readonly apiKey: string;
92
101
  readonly logger: Logger;
102
+ readonly dataToImport: {
103
+ readonly importItems: readonly ItemPreview[];
104
+ };
93
105
  }): Promise<void> {
94
106
  const environment = await managementClientUtils(
95
107
  getMigrationManagementClient({
@@ -102,7 +114,8 @@ export async function confirmImportAsync(data: {
102
114
  const text = getConfirmText({
103
115
  action: "import",
104
116
  targetEnvironment: environment,
105
- itemsCount: undefined,
117
+ itemsCount: data.dataToImport.importItems.length,
118
+ importItems: data.dataToImport.importItems,
106
119
  });
107
120
 
108
121
  await confirmAsync({
@@ -145,6 +158,9 @@ async function confirmAsync(data: {
145
158
  function getConfirmText({
146
159
  action,
147
160
  itemsCount,
161
+ exportItems,
162
+ importItems,
163
+ migrateItems,
148
164
  sourceEnvironment,
149
165
  targetEnvironment,
150
166
  skipMissingReferences,
@@ -152,9 +168,29 @@ function getConfirmText({
152
168
  readonly action: "export" | "import" | "migrate";
153
169
  readonly skipMissingReferences?: boolean;
154
170
  readonly itemsCount?: number;
171
+ readonly exportItems?: readonly ItemPreview[];
172
+ readonly importItems?: readonly ItemPreview[];
173
+ readonly migrateItems?: readonly ItemPreview[];
155
174
  readonly sourceEnvironment?: EnvironmentModels.EnvironmentInformationModel;
156
175
  readonly targetEnvironment?: EnvironmentModels.EnvironmentInformationModel;
157
176
  }): string {
177
+ const previewItems: readonly ItemPreview[] = match(action)
178
+ .returnType<readonly ItemPreview[]>()
179
+ .with("export", () => exportItems ?? [])
180
+ .with("import", () => importItems ?? [])
181
+ .with("migrate", () => migrateItems ?? [])
182
+ .exhaustive()
183
+ .slice(0, maxItemsShownInPreview);
184
+ const remainingPreviewItemsCount: number = Math.max(
185
+ match(action)
186
+ .returnType<number>()
187
+ .with("export", () => exportItems?.length ?? 0)
188
+ .with("import", () => importItems?.length ?? 0)
189
+ .with("migrate", () => migrateItems?.length ?? 0)
190
+ .exhaustive() - previewItems.length,
191
+ 0,
192
+ );
193
+
158
194
  const lines: readonly string[] = [
159
195
  `\n${"=".repeat(70)}`,
160
196
  ...match(action)
@@ -191,6 +227,35 @@ function getConfirmText({
191
227
  "",
192
228
  ])
193
229
  .otherwise(() => []),
230
+ ...match(action)
231
+ .returnType<readonly string[]>()
232
+ .with(P.union("export", "import", "migrate"), (action) => [
233
+ ...match(previewItems.length)
234
+ .returnType<readonly string[]>()
235
+ .with(
236
+ P.when((count) => count > 0),
237
+ () => [
238
+ `${chalk.cyan(
239
+ match(action)
240
+ .with("export", () => "🧾 Export item codenames preview:")
241
+ .with("import", () => "🧾 Import item codenames preview:")
242
+ .with("migrate", () => "🧾 Migrate item codenames preview:")
243
+ .exhaustive(),
244
+ )}`,
245
+ ...previewItems.map((item) => ` ${chalk.gray("├─")} ${item.itemCodename} (${item.languageCodename})`),
246
+ ...match(remainingPreviewItemsCount)
247
+ .returnType<readonly string[]>()
248
+ .with(
249
+ P.when((count) => count > 0),
250
+ (count) => [` ${chalk.gray("└─")} and ${chalk.yellow.bold(count)} more`],
251
+ )
252
+ .otherwise(() => []),
253
+ "",
254
+ ],
255
+ )
256
+ .otherwise(() => []),
257
+ ])
258
+ .otherwise(() => []),
194
259
  ...match(action)
195
260
  .returnType<readonly string[]>()
196
261
  .with(P.union("export", "migrate"), () => [
@@ -32,6 +32,8 @@ export function extractErrorData(error: unknown): ErrorData {
32
32
  isUnknownError: false,
33
33
  error: error,
34
34
  message: `Found '${chalk.red(error.issues.length)}' parsing errors: \n${parsingErrorsMsg}`,
35
+ requestData: undefined,
36
+ requestUrl: undefined,
35
37
  };
36
38
  },
37
39
  )
@@ -42,6 +44,8 @@ export function extractErrorData(error: unknown): ErrorData {
42
44
  isUnknownError: false,
43
45
  error: error,
44
46
  message: error.message,
47
+ requestData: undefined,
48
+ requestUrl: undefined,
45
49
  };
46
50
  },
47
51
  )
@@ -50,6 +54,8 @@ export function extractErrorData(error: unknown): ErrorData {
50
54
  isUnknownError: true,
51
55
  error: error,
52
56
  message: `Unknown error`,
57
+ requestData: undefined,
58
+ requestUrl: undefined,
53
59
  };
54
60
  });
55
61
  }
@@ -1,7 +1,7 @@
1
- export interface ExternalIdGenerator {
1
+ export type ExternalIdGenerator = {
2
2
  readonly assetExternalId: (codename: string) => string;
3
3
  readonly contentItemExternalId: (codename: string) => string;
4
- }
4
+ };
5
5
 
6
6
  export const defaultExternalIdGenerator: ExternalIdGenerator = {
7
7
  assetExternalId: (codename) => `asset_${codename}`,
@@ -1,5 +1,4 @@
1
- import type { ITrackingEventData } from "@kontent-ai-consulting/tools-analytics";
2
- import { getTrackingService } from "@kontent-ai-consulting/tools-analytics";
1
+ import { getTrackingService, type ITrackingEventData } from "@kontent-ai-consulting/tools-analytics";
3
2
  import { isBrowser, isNode, isWebWorker } from "browser-or-node";
4
3
  import { format } from "bytes";
5
4
  import { getDefaultLogger } from "../logs/loggers.js";
@@ -1,5 +1,4 @@
1
- import type { IRetryStrategyOptions } from "@kontent-ai/core-sdk";
2
- import { HttpService } from "@kontent-ai/core-sdk";
1
+ import { HttpService, type IRetryStrategyOptions } from "@kontent-ai/core-sdk";
3
2
  import { match } from "ts-pattern";
4
3
  import type { OriginalManagementError } from "../models/core.models.js";
5
4
 
@@ -1,16 +1,16 @@
1
1
  import type { IRetryStrategyOptions } from "@kontent-ai/core-sdk";
2
- import type {
3
- AssetFolderModels,
4
- CollectionModels,
5
- ContentTypeModels,
6
- ContentTypeSnippetModels,
7
- EnvironmentModels,
8
- LanguageModels,
9
- ManagementClient,
10
- TaxonomyModels,
11
- WorkflowModels,
2
+ import {
3
+ type AssetFolderModels,
4
+ type CollectionModels,
5
+ type ContentTypeModels,
6
+ type ContentTypeSnippetModels,
7
+ createManagementClient,
8
+ type EnvironmentModels,
9
+ type LanguageModels,
10
+ type ManagementClient,
11
+ type TaxonomyModels,
12
+ type WorkflowModels,
12
13
  } from "@kontent-ai/management-sdk";
13
- import { createManagementClient } from "@kontent-ai/management-sdk";
14
14
  import chalk from "chalk";
15
15
  import { coreConfig } from "../config.js";
16
16
  import type { FlattenedContentType, FlattenedContentTypeElement } from "../models/core.models.js";
@@ -20,12 +20,12 @@ import { isNotUndefined } from "./global.utils.js";
20
20
  import { defaultHttpService, defaultRetryStrategy } from "./http.utils.js";
21
21
  import { runMapiRequestAsync } from "./run.utils.js";
22
22
 
23
- export interface ManagementClientConfig {
23
+ export type ManagementClientConfig = {
24
24
  readonly environmentId: string;
25
25
  readonly apiKey: string;
26
26
  readonly retryStrategy?: Readonly<IRetryStrategyOptions>;
27
27
  readonly baseUrl?: string;
28
- }
28
+ };
29
29
 
30
30
  export function getMigrationManagementClient(config: ManagementClientConfig): Readonly<ManagementClient> {
31
31
  return createManagementClient({
@@ -32,9 +32,9 @@ export async function processItemsAsync<InputItem, OutputItem>(data: {
32
32
  const limit = pLimit(data.parallelLimit);
33
33
  let processedItemsCount: number = 1;
34
34
 
35
- const requests: readonly Promise<ItemProcessingResult<InputItem, OutputItem>>[] = data.items.map((item) =>
36
- limit(() => {
37
- return data
35
+ const requests: readonly Promise<ItemProcessingResult<InputItem, OutputItem>>[] = data.items.map(async (item) =>
36
+ limit(async () => {
37
+ return await data
38
38
  .processAsync(item, logSpinner)
39
39
  .then<OutputItem | "404">((output) => {
40
40
  const itemInfo = data.itemInfo(item);
@@ -20,23 +20,23 @@ import type { Logger } from "../core/models/log.models.js";
20
20
  import type { MigrationComponent, MigrationElementTransformData, MigrationUrlSlugMode } from "../core/models/migration.models.js";
21
21
  import type { ManagementClientConfig } from "../core/utils/management-client-utils.js";
22
22
 
23
- export interface ExportContextEnvironmentData {
23
+ export type ExportContextEnvironmentData = {
24
24
  readonly languages: readonly Readonly<LanguageModels.LanguageModel>[];
25
25
  readonly contentTypes: readonly Readonly<FlattenedContentType>[];
26
26
  readonly collections: readonly Readonly<CollectionModels.Collection>[];
27
27
  readonly assetFolders: readonly Readonly<AssetFolderModels.AssetFolder>[];
28
28
  readonly workflows: readonly Readonly<WorkflowModels.Workflow>[];
29
29
  readonly taxonomies: readonly Readonly<TaxonomyModels.Taxonomy>[];
30
- }
30
+ };
31
31
 
32
32
  export type ExportElementValue = string | number | SharedModels.ReferenceObject[] | undefined;
33
33
 
34
- export interface ExportElement {
34
+ export type ExportElement = {
35
35
  readonly value: ExportElementValue;
36
36
  readonly components: readonly MigrationComponent[];
37
37
  readonly urlSlugMode: MigrationUrlSlugMode | undefined;
38
38
  readonly displayTimezone: string | undefined;
39
- }
39
+ };
40
40
 
41
41
  export type ExportTransformFunc = (data: {
42
42
  readonly typeElement: FlattenedContentTypeElement;
@@ -44,7 +44,7 @@ export type ExportTransformFunc = (data: {
44
44
  readonly context: ExportContext;
45
45
  }) => MigrationElementTransformData;
46
46
 
47
- export interface ExportContext {
47
+ export type ExportContext = {
48
48
  readonly environmentData: ExportContextEnvironmentData;
49
49
  readonly referencedData: ReferencedDataInLanguageVariants;
50
50
  readonly getItemStateInSourceEnvironment: (id: string) => ItemStateInSourceEnvironmentById;
@@ -52,23 +52,23 @@ export interface ExportContext {
52
52
  readonly exportItems: readonly ExportItem[];
53
53
  readonly getElement: GetFlattenedElementByIds;
54
54
  readonly exportContextOptions: ExportContextOptions;
55
- }
55
+ };
56
56
 
57
- export interface SourceExportItem {
57
+ export type SourceExportItem = {
58
58
  readonly itemCodename: string;
59
59
  readonly languageCodename: string;
60
- }
60
+ };
61
61
 
62
- export interface ExportContextOptions {
62
+ export type ExportContextOptions = {
63
63
  /**
64
64
  * When enabled, the export process will skip missing items and assets instead of throwing errors.
65
65
  * Missing references will be filtered out from the exported data.
66
66
  * Default: false
67
67
  */
68
68
  readonly skipMissingReferences?: boolean;
69
- }
69
+ };
70
70
 
71
- export interface ExportConfig extends ManagementClientConfig {
71
+ export type ExportConfig = ManagementClientConfig & {
72
72
  readonly exportItems: readonly SourceExportItem[];
73
73
  readonly logger?: Logger;
74
74
  /**
@@ -77,23 +77,23 @@ export interface ExportConfig extends ManagementClientConfig {
77
77
  * Default: false
78
78
  */
79
79
  readonly skipMissingReferences?: boolean;
80
- }
80
+ };
81
81
 
82
- export interface DefaultExportContextConfig {
82
+ export type DefaultExportContextConfig = {
83
83
  readonly logger: Logger;
84
84
  readonly exportItems: readonly SourceExportItem[];
85
85
  readonly managementClient: Readonly<ManagementClient>;
86
86
  readonly skipMissingReferences: boolean;
87
- }
87
+ };
88
88
 
89
89
  export type GetFlattenedElementByIds = (contentTypeId: string, elementId: string) => FlattenedContentTypeElement;
90
90
 
91
- export interface ExportItemVersion {
91
+ export type ExportItemVersion = {
92
92
  readonly workflowStepCodename: string;
93
93
  readonly languageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant>;
94
- }
94
+ };
95
95
 
96
- export interface ExportItem {
96
+ export type ExportItem = {
97
97
  readonly requestItem: SourceExportItem;
98
98
  readonly versions: readonly ExportItemVersion[];
99
99
  readonly contentItem: Readonly<ContentItemModels.ContentItem>;
@@ -102,4 +102,4 @@ export interface ExportItem {
102
102
  readonly language: Readonly<LanguageModels.LanguageModel>;
103
103
  readonly workflow: Readonly<WorkflowModels.Workflow>;
104
104
  readonly contentType: Readonly<FlattenedContentType>;
105
- }
105
+ };
@@ -71,6 +71,10 @@ function areDescriptionsIdentical(data: {
71
71
  readonly targetAsset: Readonly<AssetModels.Asset>;
72
72
  readonly languages: readonly Readonly<LanguageModels.LanguageModel>[];
73
73
  }): boolean {
74
+ const languageComparer = (a: MigrationAssetDescription, b: MigrationAssetDescription) => {
75
+ return a.language.codename.localeCompare(b.language.codename);
76
+ };
77
+
74
78
  const sourceMigrationDescriptions = (data.migrationAsset.descriptions ?? [])
75
79
  .map<MigrationAssetDescription>((description) => {
76
80
  return {
@@ -80,8 +84,8 @@ function areDescriptionsIdentical(data: {
80
84
  },
81
85
  };
82
86
  })
83
- .toSorted();
84
- const targetMigrationDescriptions = mapToMigrationDescriptions(data).toSorted();
87
+ .toSorted(languageComparer);
88
+ const targetMigrationDescriptions = mapToMigrationDescriptions(data).toSorted(languageComparer);
85
89
 
86
90
  return deepEqual(sourceMigrationDescriptions, targetMigrationDescriptions);
87
91
  }
@@ -1,8 +1,7 @@
1
1
  import type { AssetModels, ContentItemModels, LanguageVariantModels } from "@kontent-ai/management-sdk";
2
2
  import chalk from "chalk";
3
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
+ import { type WorkflowStep, workflowHelper as workflowHelperInit } from "../../core/helpers/workflow-helper.js";
6
5
  import type {
7
6
  AssetStateInTargetEnvironmentByCodename,
8
7
  ItemStateInTargetEnvironmentByCodename,
@@ -23,11 +22,11 @@ import { runMapiRequestAsync } from "../../core/utils/run.utils.js";
23
22
  import { type ExtractItemByCodename, itemsExtractionProcessor } from "../../translation/extraction/items-extraction.processor.js";
24
23
  import type { GetFlattenedElementByCodenames, ImportContext, ImportContextConfig, ImportContextEnvironmentData } from "../import.models.js";
25
24
 
26
- interface LanguageVariantWrapper {
25
+ type LanguageVariantWrapper = {
27
26
  readonly draftLanguageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined;
28
27
  readonly publishedLanguageVariant: Readonly<LanguageVariantModels.ContentItemLanguageVariant> | undefined;
29
28
  readonly migrationItem: MigrationItem;
30
- }
29
+ };
31
30
 
32
31
  export async function importContextFetcherAsync(config: ImportContextConfig) {
33
32
  const getEnvironmentDataAsync = async (): Promise<ImportContextEnvironmentData> => {