Skip to content

Commit

Permalink
Add sync skeleton
Browse files Browse the repository at this point in the history
  • Loading branch information
IvanKiral committed Mar 7, 2024
1 parent 3f8920d commit 97ec345
Show file tree
Hide file tree
Showing 13 changed files with 252 additions and 3 deletions.
44 changes: 44 additions & 0 deletions src/commands/generateSyncModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { LogOptions } from "../log.js";
import { generateSyncModelToFile } from "../modules/sync/generateSyncModel.js";
import { RegisterCommand } from "../types/yargs.js";

export const generateSyncModel: RegisterCommand = yargs =>
yargs.command(
{
command: "generate-sync-model",
describe: "generates content model json file used for sync from Kontent.ai environment",
builder: yargs =>
yargs
.option("environmentId", {
type: "string",
describe: "Id of the target Kontent.ai environment that should be synced",
demandOption: "You need to provide the environmentId of the Kontent.ai to be synced",
alias: "e",
})
.option("apiKey", {
type: "string",
describe: "Management API key of target Kontent.ai project",
demandOption: "You need to provide a Management API key for the given Kontent.ai environment.",
alias: "k",
})
.option("fileName", {
type: "string",
describe: "Name of the json file with content model",
alias: "f",
}),
handler: args => generateModel(args),
},
);

export type SyncParams =
& Readonly<{
environmentId: string;
apiKey: string;
fileName?: string;
}>
& LogOptions;

export const generateModel = (params: SyncParams) => {
//TODO
generateSyncModelToFile(params);
};
45 changes: 45 additions & 0 deletions src/commands/sync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { LogOptions } from "../log.js";
import { RegisterCommand } from "../types/yargs.js";

export const sync: RegisterCommand = yargs =>
yargs.command(
{
command: "sync",
describe: "Synchronize content model by model in file",
builder: yargs =>
yargs
.option("fileName", {
type: "string",
describe: "Name of the json file with content model",
demandOption: "You need to provide the filename of the json file to sync content model",
alias: "f",
})
.option("environmentId", {
type: "string",
describe: "Id of the target Kontent.ai environment that should be synced",
demandOption: "You need to provide the environmentId of the Kontent.ai to be synced",
alias: "e",
})
.option("apiKey", {
type: "string",
describe: "Management API key of target Kontent.ai project",
demandOption: "You need to provide a Management API key for the given Kontent.ai environment.",
alias: "k",
}),
handler: args => syncContentModel(args),
},
);

export type SyncParams =
& Readonly<{
environmentId: string;
fileName: string;
apiKey: string;
}>
& LogOptions;

export const syncContentModel = (params: SyncParams) => {
//TODO
params as never;
};

13 changes: 13 additions & 0 deletions src/modules/sync/diff.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ManagementClient } from "@kontent-ai/management-sdk"

type DiffConfig = DiffOptions

type DiffOptions = {
filname: string
}

export const diff = (client: ManagementClient, config: DiffConfig) => {
//TODO
client as never;
config as never;
}
37 changes: 37 additions & 0 deletions src/modules/sync/generateSyncModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ManagementClient } from "@kontent-ai/management-sdk";

import { ManagementClientBaseOptions } from "../../types/managementClient.js";
import { generateContentTypeModel } from "./modelGenerators/contentTypes.js";
import { generateContentTypeSnippetsModel } from "./modelGenerators/contentTypeSnippets.js";
import { generateTaxonomyGroupsModel } from "./modelGenerators/taxonomyGroups.js";

type GetModelConfig = ManagementClientBaseOptions & GetModelOptions

type GetModelOptions = {
filename?: string
}

export const generateSyncModelToFile = (config: GetModelConfig) => {
/**
* This function should create the file dateTime-environmentId.json (if other name not specified)
* This file contains the content model from the given environmentId (you can use the type fileContentModel).
* The internalIds should be replaced by codenames.
* Unnecesary fields for syncing like lastModified should be removed.
* The tool might add comment about the datetime and tool's version.
*/

//TODO
const client = new ManagementClient({
environmentId: config.environmentId,
apiKey: config.apiKey
})

const contentTypeModel = generateContentTypeModel(client);
const contentTypeSnippetModel = generateContentTypeSnippetsModel(client);
const taxonomyGroupsModel = generateTaxonomyGroupsModel(client);

contentTypeModel as never;
contentTypeSnippetModel as never;
taxonomyGroupsModel as never;

}
10 changes: 10 additions & 0 deletions src/modules/sync/modelGenerators/contentTypeSnippets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ManagementClient } from "@kontent-ai/management-sdk";

import { ContentTypeSnippetsContract } from "../types/fileContentModel.js";

export const generateContentTypeSnippetsModel = (client: ManagementClient): ContentTypeSnippetsContract => {
//TODO
client as never;

return {} as ContentTypeSnippetsContract;
}
10 changes: 10 additions & 0 deletions src/modules/sync/modelGenerators/contentTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ManagementClient } from "@kontent-ai/management-sdk";

import { ContentTypeContract } from "../types/fileContentModel.js";

export const generateContentTypeModel = (client: ManagementClient): ContentTypeContract => {
//TODO
client as never;

return {} as ContentTypeContract;
}
10 changes: 10 additions & 0 deletions src/modules/sync/modelGenerators/taxonomyGroups.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ManagementClient } from "@kontent-ai/management-sdk";

import { TaxonomyContract } from "../types/fileContentModel.js";

export const generateTaxonomyGroupsModel = (client: ManagementClient): TaxonomyContract => {
//TODO
client as never;

return {} as TaxonomyContract
}
9 changes: 9 additions & 0 deletions src/modules/sync/sync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ManagementClient } from "@kontent-ai/management-sdk";

import { DiffModel } from "./types/diffModel.js";

export const sync = (client: ManagementClient, diff: DiffModel) => {
//TODO
diff as never;
client as never;
}
26 changes: 26 additions & 0 deletions src/modules/sync/types/diffModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ContentTypeModels, ContentTypeSnippetModels, TaxonomyModels } from "@kontent-ai/management-sdk";

import { RequiredCodename } from "../../../utils/types.js";

type Codename = string;

type DiffObject<A, U> = Readonly<{
added: ReadonlyArray<A>;
updated: ReadonlyMap<Codename, ReadonlyArray<U>>;
deleted: ReadonlyArray<Codename>;
}>;

export type DiffModel = {
taxonomyGroups: DiffObject<
RequiredCodename<TaxonomyModels.IAddTaxonomyRequestModel>,
TaxonomyModels.IModifyTaxonomyData
>;
contentTypeSnippets: DiffObject<
RequiredCodename<ContentTypeSnippetModels.IAddContentTypeSnippetData>,
ContentTypeSnippetModels.IModifyContentTypeSnippetData
>;
contentTypes: DiffObject<
RequiredCodename<ContentTypeModels.IAddContentTypeData>,
ContentTypeModels.IModifyContentTypeData
>;
};
28 changes: 28 additions & 0 deletions src/modules/sync/types/fileContentModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
ContentTypeContracts,
ContentTypeSnippetContracts,
ElementContracts,
TaxonomyContracts,
} from "@kontent-ai/management-sdk";

import { CodenameReference, FixReferences } from "../../../utils/types.js";

export type TaxonomyContract = Omit<TaxonomyContracts.ITaxonomyContract, "id" | "last_modified" | "codename" | "terms"> & {
codename: string;
terms: TaxonomyContract[];
};

export type ContentTypeSnippetsContract =
& Omit<ContentTypeSnippetContracts.IContentTypeSnippetContract, "id" | "codename" | "last_modified" | "elements">
& { codename: string; elements: FixReferences<ElementContracts.IContentItemElementContract, CodenameReference>[] };

export type ContentTypeContract =
& Omit<ContentTypeContracts.IContentTypeContract, "id" | "codename" | "last_modified" | "elements">
& { codename: string; elements: FixReferences<ElementContracts.IContentItemElementContract, CodenameReference>[] };

export type FileContentModel = {
taxonomyGroups: ReadonlyArray<TaxonomyContract>;
contentTypeSnippets: ReadonlyArray<ContentTypeSnippetsContract>;
contentTypes: ReadonlyArray<ContentTypeContract>;
};

11 changes: 11 additions & 0 deletions src/modules/sync/utils/patchOperations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//TODO: This file is justa suggestion. Feel free to come up with your idea :)

export const handleName = (name: string) => ({
op : 'replace',
path: '/name',
value: name
})

export const contentTypePropertyHandlers = {
name: handleName
}
4 changes: 4 additions & 0 deletions src/types/managementClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type ManagementClientBaseOptions = {
environmentId: string,
apiKey: string
}
8 changes: 5 additions & 3 deletions src/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,22 @@ export type MapValues<Map extends ReadonlyMap<unknown, unknown>> = Map extends R
: never;

export type IdReference = Readonly<{ id: string }>;
export type CodenameReference = Readonly<{ codename: string }>;

/**
* Use this to replace inaccurate references for better ones in SDK types returned from MAPI.
*
* @example FixReferences<LanguageVariantContracts.ILanguageVariantModel>
*/
export type FixReferences<T> = T extends object ? {
export type FixReferences<T, R extends IdReference | CodenameReference = IdReference> = T extends object ? {
[K in keyof T]: T[K] extends SharedContracts.IReferenceObjectContract
? SharedContracts.IReferenceObjectContract extends T[K] ? IdReference : FixReferences<T[K]>
: FixReferences<T[K]>;
? SharedContracts.IReferenceObjectContract extends T[K] ? R : FixReferences<T[K], R>
: FixReferences<T[K], R>;
}
: T;

export type RequiredId<T extends { [key in "id"]?: string }> = Replace<T, "id", string>;
export type RequiredCodename<T extends { [key in "codename"]?: string }> = Replace<T, "codename", string>;

export type Replace<T, Key extends keyof T, NewValue, IsOptional extends boolean = false> =
& Omit<T, Key>
Expand Down

0 comments on commit 97ec345

Please sign in to comment.