@kontent-ai/migration-toolkit 1.0.0 → 1.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 (56) hide show
  1. package/README.md +3 -7
  2. package/dist/es2022/core/index.d.ts +1 -0
  3. package/dist/es2022/core/index.js +1 -0
  4. package/dist/es2022/core/index.js.map +1 -1
  5. package/dist/es2022/core/models/migration.models.d.ts +35 -133
  6. package/dist/es2022/core/models/migration.schema.d.ts +1300 -0
  7. package/dist/es2022/core/models/migration.schema.js +114 -0
  8. package/dist/es2022/core/models/migration.schema.js.map +1 -0
  9. package/dist/es2022/core/utils/confirm.utils.js +3 -3
  10. package/dist/es2022/core/utils/confirm.utils.js.map +1 -1
  11. package/dist/es2022/core/utils/error.utils.js +8 -2
  12. package/dist/es2022/core/utils/error.utils.js.map +1 -1
  13. package/dist/es2022/core/utils/global.utils.d.ts +4 -1
  14. package/dist/es2022/core/utils/global.utils.js +1 -3
  15. package/dist/es2022/core/utils/global.utils.js.map +1 -1
  16. package/dist/es2022/export/context/export-context-fetcher.js +10 -6
  17. package/dist/es2022/export/context/export-context-fetcher.js.map +1 -1
  18. package/dist/es2022/export/export-manager.js +3 -3
  19. package/dist/es2022/export/export-manager.js.map +1 -1
  20. package/dist/es2022/import/import-manager.js.map +1 -1
  21. package/dist/es2022/metadata.js +2 -2
  22. package/dist/es2022/node/cli/actions/export-action.js +2 -2
  23. package/dist/es2022/node/cli/actions/export-action.js.map +1 -1
  24. package/dist/es2022/node/cli/actions/import-action.js +2 -2
  25. package/dist/es2022/node/cli/actions/import-action.js.map +1 -1
  26. package/dist/es2022/node/cli/app.js +3 -0
  27. package/dist/es2022/node/cli/app.js.map +1 -1
  28. package/dist/es2022/node/cli/args/args-setter.js +3 -0
  29. package/dist/es2022/node/cli/args/args-setter.js.map +1 -1
  30. package/dist/es2022/node/cli/cli.models.d.ts +1 -0
  31. package/dist/es2022/toolkit/file.js +3 -3
  32. package/dist/es2022/toolkit/file.js.map +1 -1
  33. package/dist/es2022/translation/transforms/export-transforms.js.map +1 -1
  34. package/dist/es2022/zip/zip-transformer.js +9 -6
  35. package/dist/es2022/zip/zip-transformer.js.map +1 -1
  36. package/dist/es2022/zip/zip.models.d.ts +1 -1
  37. package/lib/core/index.ts +1 -0
  38. package/lib/core/models/migration.models.ts +56 -159
  39. package/lib/core/models/migration.schema.ts +180 -0
  40. package/lib/core/utils/confirm.utils.ts +4 -4
  41. package/lib/core/utils/error.utils.ts +9 -6
  42. package/lib/core/utils/global.utils.ts +3 -3
  43. package/lib/export/context/export-context-fetcher.ts +9 -6
  44. package/lib/export/export-manager.ts +16 -20
  45. package/lib/import/import-manager.ts +2 -6
  46. package/lib/metadata.ts +2 -2
  47. package/lib/node/cli/actions/export-action.ts +2 -2
  48. package/lib/node/cli/actions/import-action.ts +2 -2
  49. package/lib/node/cli/app.ts +4 -0
  50. package/lib/node/cli/args/args-setter.ts +3 -0
  51. package/lib/node/cli/cli.models.ts +1 -0
  52. package/lib/toolkit/file.ts +3 -9
  53. package/lib/translation/transforms/export-transforms.ts +1 -4
  54. package/lib/zip/zip-transformer.ts +25 -11
  55. package/lib/zip/zip.models.ts +1 -1
  56. package/package.json +10 -10
@@ -16,7 +16,10 @@ import {
16
16
  isNotUndefined,
17
17
  MigrationElementValue,
18
18
  getMigrationManagementClient,
19
- findRequired
19
+ findRequired,
20
+ Writeable,
21
+ MigrationItemsSchema,
22
+ MigrationAssetsSchema
20
23
  } from '../core/index.js';
21
24
  import { exportTransforms } from '../translation/index.js';
22
25
  import { exportContextFetcherAsync } from './context/export-context-fetcher.js';
@@ -61,11 +64,7 @@ export function exportManager(config: ExportConfig) {
61
64
  const componentType = context.environmentData.contentTypes.find((m) => m.contentTypeId === component.type.id);
62
65
 
63
66
  if (!componentType) {
64
- throw Error(
65
- `Could not find content type with id '${chalk.red(component.type.id)}' for component '${chalk.red(
66
- component.id
67
- )}'`
68
- );
67
+ throw Error(`Could not find content type with id '${chalk.red(component.type.id)}' for component '${chalk.red(component.id)}'`);
69
68
  }
70
69
 
71
70
  const migrationItem: MigrationComponent = {
@@ -96,7 +95,7 @@ export function exportManager(config: ExportConfig) {
96
95
  }
97
96
  return 0;
98
97
  })
99
- .reduce<MigrationElements>((model, typeElement) => {
98
+ .reduce<Writeable<MigrationElements>>((model, typeElement) => {
100
99
  const itemElement = findRequired(
101
100
  elements,
102
101
  (m) => m.element.id === typeElement.id,
@@ -128,9 +127,7 @@ export function exportManager(config: ExportConfig) {
128
127
  context: data.context,
129
128
  typeElement: data.typeElement,
130
129
  exportElement: {
131
- components: data.exportElement.components.map((component) =>
132
- mapToMigrationComponent(data.context, component)
133
- ),
130
+ components: data.exportElement.components.map((component) => mapToMigrationComponent(data.context, component)),
134
131
  value: data.exportElement.value,
135
132
  urlSlugMode: data.exportElement.mode
136
133
  }
@@ -155,9 +152,7 @@ export function exportManager(config: ExportConfig) {
155
152
 
156
153
  const exportAssetsAsync = async (context: ExportContext): Promise<readonly Readonly<MigrationAsset>[]> => {
157
154
  const assets = Array.from(context.referencedData.assetIds)
158
- .map<Readonly<AssetModels.Asset> | undefined>(
159
- (assetId) => context.getAssetStateInSourceEnvironment(assetId).asset
160
- )
155
+ .map<Readonly<AssetModels.Asset> | undefined>((assetId) => context.getAssetStateInSourceEnvironment(assetId).asset)
161
156
  .filter(isNotUndefined);
162
157
 
163
158
  return await getMigrationAssetsWithBinaryDataAsync(assets, context);
@@ -184,8 +179,9 @@ export function exportManager(config: ExportConfig) {
184
179
  },
185
180
  items: assets,
186
181
  processAsync: async (asset, logSpinner) => {
187
- const assetCollection: Readonly<CollectionModels.Collection> | undefined =
188
- context.environmentData.collections.find((m) => m.id === asset.collection?.reference?.id);
182
+ const assetCollection: Readonly<CollectionModels.Collection> | undefined = context.environmentData.collections.find(
183
+ (m) => m.id === asset.collection?.reference?.id
184
+ );
189
185
 
190
186
  logSpinner({
191
187
  type: 'download',
@@ -204,9 +200,9 @@ export function exportManager(config: ExportConfig) {
204
200
  const language = findRequired(
205
201
  context.environmentData.languages,
206
202
  (language) => language.id === description.language.id,
207
- `Could not find language with id '${chalk.red(
208
- description.language.id
209
- )}' requested by asset '${chalk.red(asset.codename)}'`
203
+ `Could not find language with id '${chalk.red(description.language.id)}' requested by asset '${chalk.red(
204
+ asset.codename
205
+ )}'`
210
206
  );
211
207
 
212
208
  return {
@@ -234,8 +230,8 @@ export function exportManager(config: ExportConfig) {
234
230
  ).getExportContextAsync();
235
231
 
236
232
  const migrationData: MigrationData = {
237
- items: getMigrationItems(exportContext),
238
- assets: await exportAssetsAsync(exportContext)
233
+ items: MigrationItemsSchema.parse(getMigrationItems(exportContext)),
234
+ assets: MigrationAssetsSchema.parse(await exportAssetsAsync(exportContext))
239
235
  };
240
236
 
241
237
  logger.log({
@@ -11,9 +11,7 @@ export function importManager(config: ImportConfig) {
11
11
  const logger: Logger = config.logger ?? getDefaultLogger();
12
12
  const targetEnvironmentClient: ManagementClient = getMigrationManagementClient(config);
13
13
 
14
- const importAssetsAsync = async (
15
- importContext: ImportContext
16
- ): Promise<Pick<ImportResult, 'editedAssets' | 'uploadedAssets'>> => {
14
+ const importAssetsAsync = async (importContext: ImportContext): Promise<Pick<ImportResult, 'editedAssets' | 'uploadedAssets'>> => {
17
15
  if (!importContext.categorizedImportData.assets.length) {
18
16
  logger.log({
19
17
  type: 'info',
@@ -31,9 +29,7 @@ export function importManager(config: ImportConfig) {
31
29
  logger: logger
32
30
  }).importAsync();
33
31
  };
34
- const importContentItemsAsync = async (
35
- importContext: ImportContext
36
- ): Promise<readonly Readonly<ContentItemModels.ContentItem>[]> => {
32
+ const importContentItemsAsync = async (importContext: ImportContext): Promise<readonly Readonly<ContentItemModels.ContentItem>[]> => {
37
33
  if (!importContext.categorizedImportData.contentItems.length) {
38
34
  logger.log({
39
35
  type: 'info',
package/lib/metadata.ts CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  export const libMetadata = {
3
3
  name: '@kontent-ai/migration-toolkit',
4
- timestamp: 'Wed, 10 Jul 2024 10:38:24 GMT',
5
- version: '1.0.0'
4
+ timestamp: 'Tue, 16 Jul 2024 13:30:22 GMT',
5
+ version: '1.1.0'
6
6
  };
@@ -1,4 +1,4 @@
1
- import { confirmExportAsync, getDefaultZipFilename, getDefaultLogger } from '../../../core/index.js';
1
+ import { confirmExportAsync, defaultZipFilename, getDefaultLogger } from '../../../core/index.js';
2
2
  import { exportAsync, storeAsync } from '../../../toolkit/index.js';
3
3
  import { CliArgumentsFetcher } from '../cli.models.js';
4
4
 
@@ -10,7 +10,7 @@ export async function exportActionAsync(cliFetcher: CliArgumentsFetcher): Promis
10
10
  const items = cliFetcher.getRequiredArgumentValue('items').split(',');
11
11
  const baseUrl = cliFetcher.getOptionalArgumentValue('baseUrl');
12
12
  const force = cliFetcher.getBooleanArgumentValue('force', false);
13
- const filename = cliFetcher.getOptionalArgumentValue('filename') ?? getDefaultZipFilename();
13
+ const filename = cliFetcher.getOptionalArgumentValue('filename') ?? defaultZipFilename;
14
14
 
15
15
  await confirmExportAsync({
16
16
  force: force,
@@ -1,4 +1,4 @@
1
- import { confirmImportAsync, getDefaultZipFilename, getDefaultLogger } from '../../../core/index.js';
1
+ import { confirmImportAsync, defaultZipFilename, getDefaultLogger } from '../../../core/index.js';
2
2
  import { extractAsync, importAsync } from '../../../toolkit/index.js';
3
3
  import { CliArgumentsFetcher } from '../cli.models.js';
4
4
 
@@ -8,7 +8,7 @@ export async function importActionAsync(argsFetcher: CliArgumentsFetcher): Promi
8
8
  const apiKey = argsFetcher.getRequiredArgumentValue('targetApiKey');
9
9
  const baseUrl = argsFetcher.getOptionalArgumentValue('baseUrl');
10
10
  const force = argsFetcher.getBooleanArgumentValue('force', false);
11
- const filename = argsFetcher.getOptionalArgumentValue('filename') ?? getDefaultZipFilename();
11
+ const filename = argsFetcher.getOptionalArgumentValue('filename') ?? defaultZipFilename;
12
12
 
13
13
  await confirmImportAsync({
14
14
  force: force,
@@ -6,6 +6,10 @@ import { exportActionAsync } from './actions/export-action.js';
6
6
  import { importActionAsync } from './actions/import-action.js';
7
7
  import { migrateActionAsync } from './actions/migrate-action.js';
8
8
  import { argumentsFetcherAsync } from './args/args-fetcher.js';
9
+ import { cliArgs } from './commands.js';
10
+
11
+ // This enabled --help with all commands, options & samples
12
+ cliArgs.registerCommands();
9
13
 
10
14
  const run = async () => {
11
15
  const argsFetcher = await argumentsFetcherAsync();
@@ -30,6 +30,9 @@ export function argumentsSetter(): CliArgumentsSetter {
30
30
  });
31
31
 
32
32
  return this;
33
+ },
34
+ registerCommands(): void {
35
+ argv.parseSync();
33
36
  }
34
37
  };
35
38
  }
@@ -18,6 +18,7 @@ export interface CommandOption {
18
18
  export type CliArgumentsSetter = {
19
19
  withCommand(command: Command): CliArgumentsSetter;
20
20
  withOption(option: CommandOption): CliArgumentsSetter;
21
+ registerCommands(): void;
21
22
  };
22
23
 
23
24
  export type CliArgumentsFetcher = {
@@ -1,11 +1,5 @@
1
1
  import { fileManager } from '../file/index.js';
2
- import {
3
- Logger,
4
- executeWithTrackingAsync,
5
- getDefaultZipFilename,
6
- getDefaultLogger,
7
- MigrationData
8
- } from '../core/index.js';
2
+ import { Logger, executeWithTrackingAsync, defaultZipFilename, getDefaultLogger, MigrationData } from '../core/index.js';
9
3
  import { zipManager } from '../zip/index.js';
10
4
  import { libMetadata } from '../metadata.js';
11
5
 
@@ -22,7 +16,7 @@ export interface ExtractConfig {
22
16
 
23
17
  export async function storeAsync(config: StoreConfig): Promise<void> {
24
18
  const logger = config.logger ?? getDefaultLogger();
25
- const filename: string = getDefaultZipFilename();
19
+ const filename = config.filename ?? defaultZipFilename;
26
20
 
27
21
  await executeWithTrackingAsync<void>({
28
22
  event: {
@@ -49,7 +43,7 @@ export async function storeAsync(config: StoreConfig): Promise<void> {
49
43
 
50
44
  export async function extractAsync(config: ExtractConfig): Promise<MigrationData> {
51
45
  const logger = config.logger ?? getDefaultLogger();
52
- const filename: string = getDefaultZipFilename();
46
+ const filename = config.filename ?? defaultZipFilename;
53
47
 
54
48
  return await executeWithTrackingAsync({
55
49
  event: {
@@ -175,10 +175,7 @@ export const exportTransforms: Readonly<Record<MigrationElementType, ExportTrans
175
175
  }
176
176
  };
177
177
 
178
- function findTaxonomy(
179
- termId: string,
180
- taxonomy: Readonly<TaxonomyModels.Taxonomy>
181
- ): Readonly<TaxonomyModels.Taxonomy> | undefined {
178
+ function findTaxonomy(termId: string, taxonomy: Readonly<TaxonomyModels.Taxonomy>): Readonly<TaxonomyModels.Taxonomy> | undefined {
182
179
  if (taxonomy.id === termId) {
183
180
  return taxonomy;
184
181
  }
@@ -1,10 +1,19 @@
1
- import { FileBinaryData, ZipPackager } from './zip.models.js';
2
- import { Logger, MigrationAsset, MigrationData, MigrationItem, getDefaultLogger, mapAsync } from '../core/index.js';
3
1
  import chalk from 'chalk';
4
-
5
- type ZipAssetRecord = Omit<MigrationAsset, 'binaryData'> & {
6
- _zipFilename: string;
7
- };
2
+ import { z } from 'zod';
3
+ import { FileBinaryData, ZipPackager } from './zip.models.js';
4
+ import {
5
+ Logger,
6
+ MigrationAsset,
7
+ MigrationData,
8
+ MigrationItem,
9
+ MigrationItemsSchema,
10
+ ZipMigrationAssetSchema,
11
+ ZipMigrationAssetsSchema,
12
+ getDefaultLogger,
13
+ mapAsync
14
+ } from '../core/index.js';
15
+
16
+ type ZipAssetRecord = z.infer<typeof ZipMigrationAssetSchema>;
8
17
 
9
18
  export function zipTransformer(zip: ZipPackager, logger?: Logger) {
10
19
  const loggerToUse: Logger = logger ?? getDefaultLogger();
@@ -51,18 +60,23 @@ export function zipTransformer(zip: ZipPackager, logger?: Logger) {
51
60
  };
52
61
 
53
62
  const parseItems = async () => {
54
- const fileContent = await zip.getFileContentAsync(filename);
55
- return fileContent ? (JSON.parse(fileContent) as MigrationItem[]) : [];
63
+ const content = await zip.getFileContentAsync(filename);
64
+
65
+ if (!content) {
66
+ return [];
67
+ }
68
+
69
+ return MigrationItemsSchema.parse(JSON.parse(content));
56
70
  };
57
71
 
58
72
  const parseAssets = async () => {
59
- const text = await zip.getFileContentAsync(assetsFilename);
73
+ const content = await zip.getFileContentAsync(assetsFilename);
60
74
 
61
- if (!text) {
75
+ if (!content) {
62
76
  return [];
63
77
  }
64
78
 
65
- const assetRecords = JSON.parse(text) as ZipAssetRecord[];
79
+ const assetRecords = ZipMigrationAssetsSchema.parse(JSON.parse(content));
66
80
 
67
81
  return await mapAsync(assetRecords, async (assetRecord) => {
68
82
  const binaryFile = await zip.getBinaryDataAsync(`${assetRecord._zipFilename}`);
@@ -4,7 +4,7 @@ export type FileBinaryData = Buffer | Blob;
4
4
  export type ZipCompressionLevel = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
5
5
 
6
6
  export type ZipPackager = {
7
- addFile(filePath: string, data: string | Blob | Buffer): void;
7
+ addFile(filePath: string, data: string | FileBinaryData): void;
8
8
  addFolder(name: string): ZipPackager;
9
9
  generateZipAsync(config: { logger?: Logger; compressionLevel?: ZipCompressionLevel }): Promise<FileBinaryData>;
10
10
  getBinaryDataAsync(filePath: string): Promise<FileBinaryData | undefined>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontent-ai/migration-toolkit",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
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,
@@ -59,30 +59,30 @@
59
59
  "chalk": "5.3.0",
60
60
  "dotenv": "16.4.5",
61
61
  "jszip": "3.10.1",
62
- "mime": "4.0.3",
62
+ "mime": "4.0.4",
63
63
  "ora": "8.0.1",
64
64
  "prompts": "2.4.2",
65
65
  "yargs": "17.7.2",
66
- "p-limit": "5.0.0",
67
- "deep-equal": "2.2.3"
66
+ "p-limit": "6.1.0",
67
+ "deep-equal": "2.2.3",
68
+ "zod": "3.23.8"
68
69
  },
69
70
  "devDependencies": {
70
- "@eslint/js": "9.6.0",
71
+ "@eslint/js": "9.7.0",
71
72
  "@types/deep-equal": "1.0.4",
72
73
  "@types/browser-or-node": "1.3.2",
73
74
  "@types/bytes": "3.1.4",
74
75
  "@types/eslint__js": "8.42.3",
75
- "@types/jszip": "3.4.1",
76
- "@types/node": "20.14.9",
76
+ "@types/node": "20.14.10",
77
77
  "@types/prompts": "2.4.9",
78
78
  "@types/yargs": "17.0.32",
79
- "@typescript-eslint/eslint-plugin": "7.15.0",
80
- "@typescript-eslint/parser": "7.15.0",
79
+ "@typescript-eslint/eslint-plugin": "7.16.0",
80
+ "@typescript-eslint/parser": "7.16.0",
81
81
  "eslint": "8.57.0",
82
82
  "standard-version": "9.5.0",
83
83
  "tslib": "2.6.3",
84
84
  "tsx": "4.16.2",
85
85
  "typescript": "5.5.3",
86
- "typescript-eslint": "7.15.0"
86
+ "typescript-eslint": "7.16.0"
87
87
  }
88
88
  }