import { isDeepStrictEqual } from "node:util"; import type { FieldDefinition, InvalidOperationError, Type, TypeAddEnumValueAction, TypeAddFieldDefinitionAction, TypeChangeEnumValueLabelAction, TypeChangeFieldDefinitionOrderAction, TypeChangeNameAction, TypeRemoveFieldDefinitionAction, TypeSetDescriptionAction, TypeUpdateAction, } from "@commercetools/platform-sdk"; import { CommercetoolsError } from "#src/exceptions.ts"; import type { Writable } from "#src/types.ts"; import type { RepositoryContext } from "../abstract.ts"; import { AbstractUpdateHandler } from "../abstract.ts"; type TypeUpdateHandlerMethod = ( context: RepositoryContext, resource: Writable, action: T, ) => void; type TypeUpdateActions = Partial<{ [P in TypeUpdateAction as P["action"]]: TypeUpdateHandlerMethod

; }>; export class TypeUpdateHandler extends AbstractUpdateHandler implements TypeUpdateActions { addEnumValue( context: RepositoryContext, resource: Writable, { fieldName, value }: TypeAddEnumValueAction, ) { resource.fieldDefinitions.forEach((field) => { if (field.name === fieldName) { // TODO, should be done better i suppose if (field.type.name === "Enum") { field.type.values.push(value); } else if ( field.type.name === "Set" && field.type.elementType.name === "Enum" ) { field.type.elementType.values.push(value); } else { throw new CommercetoolsError( { code: "InvalidOperation", message: "Type is not a Enum (or Set of Enum)", }, 400, ); } } }); } addFieldDefinition( context: RepositoryContext, resource: Writable, { fieldDefinition }: TypeAddFieldDefinitionAction, ) { resource.fieldDefinitions.push(fieldDefinition); } changeEnumValueLabel( context: RepositoryContext, resource: Writable, { fieldName, value }: TypeChangeEnumValueLabelAction, ) { resource.fieldDefinitions.forEach((field) => { if (field.name === fieldName) { // TODO, should be done better i suppose if (field.type.name === "Enum") { field.type.values.forEach((v) => { if (v.key === value.key) { v.label = value.label; } }); } else if ( field.type.name === "Set" && field.type.elementType.name === "Enum" ) { field.type.elementType.values.forEach((v) => { if (v.key === value.key) { v.label = value.label; } }); } else { throw new CommercetoolsError( { code: "InvalidOperation", message: "Type is not a Enum (or Set of Enum)", }, 400, ); } } }); } changeFieldDefinitionOrder( context: RepositoryContext, resource: Writable, { fieldNames }: TypeChangeFieldDefinitionOrderAction, ) { const fields = new Map( resource.fieldDefinitions.map((item) => [item.name, item]), ); const result: FieldDefinition[] = []; let current = resource.fieldDefinitions; fieldNames.forEach((fieldName) => { const field = fields.get(fieldName); if (field === undefined) { throw new CommercetoolsError( { code: "InvalidOperation", message: "Adding new field definitions is not fully supported yet", }, 400, ); } result.push(field); // Remove from current items current = current.filter((f) => f.name !== fieldName); }); if ( isDeepStrictEqual( fieldNames, resource.fieldDefinitions.map((item) => item.name), ) ) { throw new CommercetoolsError({ code: "InvalidOperation", message: "'fieldDefinitions' has no changes.", action: { action: "changeFieldDefinitionOrder", fieldNames: fieldNames, }, }); } resource.fieldDefinitions = result; // Add fields which were not specified in the order as last items. Not // sure if this follows commercetools resource.fieldDefinitions.push(...current); } changeName( context: RepositoryContext, resource: Writable, { name }: TypeChangeNameAction, ) { resource.name = name; } removeFieldDefinition( context: RepositoryContext, resource: Writable, { fieldName }: TypeRemoveFieldDefinitionAction, ) { resource.fieldDefinitions = resource.fieldDefinitions.filter( (f) => f.name !== fieldName, ); } setDescription( context: RepositoryContext, resource: Writable, { description }: TypeSetDescriptionAction, ) { resource.description = description; } }