UNPKG

@commercetools/sync-actions

Version:

Build API update actions for the commercetools platform.

1,512 lines (1,490 loc) 143 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default")); // src/index.ts var index_exports = {}; __export(index_exports, { createSyncApiExtensions: () => api_extensions_default, createSyncAttributeGroups: () => attribute_groups_default, createSyncBusinessUnits: () => business_units_default, createSyncCartDiscounts: () => cart_discounts_default, createSyncCategories: () => categories_default, createSyncChannels: () => channels_default, createSyncCustomerGroup: () => customer_group_default, createSyncCustomers: () => customers_default, createSyncDiscountCodes: () => discount_codes_default, createSyncInventories: () => inventories_default, createSyncOrders: () => orders_default, createSyncProductDiscounts: () => product_discounts_default, createSyncProductSelections: () => product_selections_default, createSyncProductTailoring: () => product_tailoring_default, createSyncProductTypes: () => product_types_default, createSyncProducts: () => products_default, createSyncProjects: () => projects_default, createSyncRecurringOrders: () => recurring_orders_default, createSyncShippingMethods: () => shipping_methods_default, createSyncStandalonePrices: () => prices_default, createSyncStates: () => states_default, createSyncStores: () => stores_default, createSyncSubscriptions: () => subscriptions_default, createSyncTaxCategories: () => tax_categories_default, createSyncTypes: () => types_default, createSyncZones: () => zones_default }); // src/utils/create-build-actions.ts import isEqual from "lodash.isequal"; import isNil from "lodash.isnil"; function applyOnBeforeDiff(before, now, fn) { return fn && typeof fn === "function" ? fn(before, now) : [before, now]; } var createPriceComparator = (price) => ({ value: { currencyCode: price.value.currencyCode }, channel: price.channel, country: price.country, customerGroup: price.customerGroup, validFrom: price.validFrom, validUntil: price.validUntil }); function arePricesStructurallyEqual(oldPrice, newPrice) { const oldPriceComparison = createPriceComparator(oldPrice); const newPriceComparison = createPriceComparator(newPrice); return isEqual(newPriceComparison, oldPriceComparison); } function extractPriceFromPreviousVariant(newPrice, previousVariant) { if (!previousVariant) return null; const price = previousVariant.prices.find( (oldPrice) => arePricesStructurallyEqual(oldPrice, newPrice) ); return price || null; } function injectMissingPriceIds(nextVariants, previousVariants) { return nextVariants.map((newVariant) => { const { prices, ...restOfVariant } = newVariant; if (!prices) return restOfVariant; const oldVariant = previousVariants.find( (previousVariant) => !isNil(previousVariant.id) && previousVariant.id === newVariant.id || !isNil(previousVariant.key) && previousVariant.key === newVariant.key || !isNil(previousVariant.sku) && previousVariant.sku === newVariant.sku ); return { ...restOfVariant, prices: prices.map((price) => { const newPrice = { ...price }; const oldPrice = extractPriceFromPreviousVariant(price, oldVariant); if (oldPrice) { if (!newPrice.id) newPrice.id = oldPrice.id; if (isNil(newPrice.value.type)) newPrice.value.type = oldPrice.value.type; if (isNil(newPrice.value.fractionDigits)) newPrice.value.fractionDigits = oldPrice.value.fractionDigits; } return newPrice; }) }; }); } function createBuildActions(differ, doMapActions, onBeforeDiff, buildActionsConfig = {}) { return function buildActions(now, before, options = {}) { if (!now || !before) { throw new Error( "Missing either `newObj` or `oldObj` in order to build update actions" ); } const [processedBefore, processedNow] = applyOnBeforeDiff( before, now, onBeforeDiff ); if ("variants" in processedNow && "variants" in processedBefore) { processedNow["variants"] = injectMissingPriceIds( processedNow.variants, processedBefore.variants ); } const diffed = differ(processedBefore, processedNow); if (!buildActionsConfig.withHints && !diffed) return []; return doMapActions(diffed, processedNow, processedBefore, options); }; } // src/utils/create-map-action-group.ts function createMapActionGroup(actionGroups = []) { return function mapActionGroup(type, fn) { if (!Object.keys(actionGroups).length) return fn(); const found = actionGroups.find((c) => c.type === type); if (!found) return []; if (found.group === "ignore" || found.group === "black") return []; if (found.group === "allow" || found.group === "white") return fn(); throw new Error( `Action group '${found.group}' not supported. Use either "allow" or "ignore".` ); }; } // src/utils/diffpatcher.ts import { DiffPatcher } from "jsondiffpatch/dist/jsondiffpatch.cjs"; function objectHash(obj, index) { const objIndex = `$$index:${index}`; return typeof obj === "object" && obj !== null ? obj.id || obj.name || obj.url || objIndex : objIndex; } var diffpatcher = new DiffPatcher({ objectHash, arrays: { // detect items moved inside the array detectMove: true, // value of items moved is not included in deltas includeValueOnMove: false }, textDiff: { /** * jsondiffpatch uses a very fine-grained diffing algorithm for long strings to easily identify * what changed between strings. However, we don't actually care about what changed, just * if the string changed at all. So we set the minimum length to diff to a very large number to avoid * using the very slow algorithm. * See https://github.com/benjamine/jsondiffpatch/blob/master/docs/deltas.md#text-diffs. */ minLength: Number.MAX_SAFE_INTEGER } }); function diff(oldObj, newObj) { return diffpatcher.diff(oldObj, newObj); } function patch(obj, delta) { return diffpatcher.patch(obj, delta); } function getDeltaValue(arr, originalObject) { if (!Array.isArray(arr)) throw new Error("Expected array to extract delta value"); if (arr.length === 1) return arr[0]; if (arr.length === 2) return arr[1]; if (arr.length === 3 && arr[2] === 0) return void 0; if (arr.length === 3 && arr[2] === 2) { if (!originalObject) throw new Error( "Cannot apply patch to long text diff. Missing original object." ); return patch(originalObject, arr); } if (arr.length === 3 && arr[2] === 3) throw new Error( "Detected an array move, it should not happen as `includeValueOnMove` should be set to false" ); throw new Error(`Got unsupported number ${arr[2]} in delta value`); } // src/utils/action-map-custom.ts var Actions = { setCustomType: "setCustomType", setCustomField: "setCustomField" }; var hasSingleCustomFieldChanged = (diff2) => Array.isArray(diff2.custom); var haveMultipleCustomFieldsChanged = (diff2) => Boolean(diff2.custom.fields); var hasCustomTypeChanged = (diff2) => Boolean(diff2.custom.type); var extractCustomType = (diff2, previousObject) => Array.isArray(diff2.custom.type) ? getDeltaValue(diff2.custom.type, previousObject) : diff2.custom.type; var extractTypeId = (type, nextObject) => Array.isArray(type.id) ? getDeltaValue(type.id) : nextObject.custom.type.id; var extractTypeKey = (type, nextObject) => Array.isArray(type.key) ? getDeltaValue(type.key) : nextObject.custom.type.key; var extractTypeFields = (diffedFields, nextFields) => Array.isArray(diffedFields) ? getDeltaValue(diffedFields) : nextFields; var extractFieldValue = (newFields, fieldName) => newFields[fieldName]; function actionsMapCustom(diff2, newObj, oldObj, customProps = { actions: {} }) { const actions = []; const { actions: customPropsActions, ...options } = customProps; const actionGroup = { ...Actions, ...customPropsActions }; if (!diff2.custom) return actions; if (hasSingleCustomFieldChanged(diff2)) { const custom = getDeltaValue(diff2.custom, oldObj); actions.push({ action: actionGroup.setCustomType, ...options, ...custom }); } else if (hasCustomTypeChanged(diff2)) { const type = extractCustomType(diff2, oldObj); if (!type) actions.push({ action: actionGroup.setCustomType, ...options }); else if (type.id) actions.push({ action: actionGroup.setCustomType, ...options, type: { typeId: "type", id: extractTypeId(type, newObj) }, fields: extractTypeFields(diff2.custom.fields, newObj.custom.fields) }); else if (type.key) actions.push({ action: actionGroup.setCustomType, ...options, type: { typeId: "type", key: extractTypeKey(type, newObj) }, fields: extractTypeFields(diff2.custom.fields, newObj.custom.fields) }); } else if (haveMultipleCustomFieldsChanged(diff2)) { const customFieldsActions = Object.keys(diff2.custom.fields).map((name) => ({ action: actionGroup.setCustomField, ...options, name, value: extractFieldValue(newObj.custom.fields, name) })); actions.push(...customFieldsActions); } return actions; } // src/utils/create-build-array-actions.ts var REGEX_NUMBER = new RegExp(/^\d+$/); var REGEX_UNDERSCORE_NUMBER = new RegExp(/^_\d+$/); var ADD_ACTIONS = "create"; var REMOVE_ACTIONS = "remove"; var CHANGE_ACTIONS = "change"; function isCreateAction(obj, key) { return REGEX_NUMBER.test(key) && Array.isArray(obj[key]) && obj[key].length === 1; } function isChangeAction(obj, key) { return REGEX_NUMBER.test(key) && (typeof obj[key] === "object" || typeof obj[key] === "string"); } function isRemoveAction(obj, key) { return REGEX_UNDERSCORE_NUMBER.test(key) && Array.isArray(obj[key]) && obj[key].length === 3 && (typeof obj[key][0] === "object" || typeof obj[key][0] === "string") && obj[key][1] === 0 && obj[key][2] === 0; } function createBuildArrayActions(key, config) { return function buildArrayActions(diff2, oldObj, newObj) { const addActions = []; const removeActions = []; const changeActions = []; if (diff2[key]) { const arrayDelta = diff2[key]; Object.keys(arrayDelta).forEach((index) => { if (config[ADD_ACTIONS] && isCreateAction(arrayDelta, index)) { const actionGenerator = config[ADD_ACTIONS]; const action = actionGenerator( newObj[key][index], parseInt(index, 10) ); if (action) addActions.push(action); } else if (config[CHANGE_ACTIONS] && isChangeAction(arrayDelta, index)) { const actionGenerator = config[CHANGE_ACTIONS]; const action = actionGenerator( oldObj[key][index], newObj[key][index], parseInt(index, 10) ); if (action) changeActions.push(action); } else if (config[REMOVE_ACTIONS] && isRemoveAction(arrayDelta, index)) { const realIndex = index.replace("_", ""); const actionGenerator = config[REMOVE_ACTIONS]; const action = actionGenerator( oldObj[key][realIndex], parseInt(realIndex, 10) ); if (action) removeActions.push(action); } }); } return changeActions.concat(removeActions, addActions); }; } // src/assets/assets-actions.ts function toAssetIdentifier(asset) { const assetIdentifier = asset.id ? { assetId: asset.id } : { assetKey: asset.key }; return assetIdentifier; } function actionsMapAssets(diff2, oldObj, newObj) { const handler = createBuildArrayActions("assets", { [ADD_ACTIONS]: (newAsset) => ({ action: "addAsset", asset: newAsset }), [REMOVE_ACTIONS]: (oldAsset) => ({ action: "removeAsset", ...toAssetIdentifier(oldAsset) }), [CHANGE_ACTIONS]: (oldAsset, newAsset) => ( // here we could use more atomic update actions (e.g. changeAssetName) // but for now we use the simpler approach to first remove and then // re-add the asset - which reduces the code complexity [ { action: "removeAsset", ...toAssetIdentifier(oldAsset) }, { action: "addAsset", asset: newAsset } ] ) }); return handler(diff2, oldObj, newObj); } // src/utils/common-actions.ts import isNil2 from "lodash.isnil"; // src/utils/clone.ts function clone(obj) { return JSON.parse(JSON.stringify(obj)); } function notEmpty(value) { return value !== null && value !== void 0; } // src/utils/common-actions.ts var normalizeValue = (value) => typeof value === "string" ? value.trim() : value; var createIsEmptyValue = (emptyValues) => (value) => emptyValues.some((emptyValue) => emptyValue === normalizeValue(value)); var isOptionalField = (action) => action.startsWith("set"); function buildBaseAttributesActions({ actions, diff: diff2, oldObj, newObj, shouldOmitEmptyString, shouldUnsetOmittedProperties, shouldPreventUnsettingRequiredFields }) { const isEmptyValue2 = createIsEmptyValue( shouldOmitEmptyString ? [void 0, null, ""] : [void 0, null] ); return actions.map((item) => { const key = item.key; const actionKey = item.actionKey || item.key; const delta = diff2[key]; const before = oldObj[key]; const now = newObj[key]; const isNotDefinedBefore = isEmptyValue2(oldObj[key]); const isNotDefinedNow = isEmptyValue2(newObj[key]); const isOmitted = !Object.keys(newObj).includes(key); if (!delta) return void 0; if (isNotDefinedNow && !isOptionalField(item.action) && shouldPreventUnsettingRequiredFields) return void 0; if (isNotDefinedNow && isNotDefinedBefore) return void 0; if (!isNotDefinedNow && isNotDefinedBefore) return { action: item.action, [actionKey]: now }; if (isNotDefinedNow && isOmitted && !shouldUnsetOmittedProperties) return void 0; if (isNotDefinedNow) return { action: item.action }; const patched = patch(clone(before), delta); return { action: item.action, [actionKey]: patched }; }).filter((action) => !isNil2(action)); } function buildReferenceActions({ actions, diff: diff2, // eslint-disable-next-line oldObj, newObj }) { return actions.map((item) => { const action = item.action; const key = item.key; if (diff2[key] && // The `key` value was added or removed (Array.isArray(diff2[key]) || // The `key` value id changed diff2[key].id)) { const newValue = Array.isArray(diff2[key]) ? getDeltaValue(diff2[key]) : newObj[key]; if (!newValue) return { action }; if (!newValue.id) { return { action, [key]: { typeId: newValue.typeId, key: newValue.key } }; } return { action, // We only need to pass a reference to the object. // This prevents accidentally sending the expanded (`obj`) // over the wire. [key]: { typeId: newValue.typeId, id: newValue.id } }; } return void 0; }).filter((action) => action); } // src/categories/category-actions.ts var baseActionsList = [ { action: "changeName", key: "name" }, { action: "changeSlug", key: "slug" }, { action: "setDescription", key: "description" }, { action: "changeOrderHint", key: "orderHint" }, { action: "setExternalId", key: "externalId" }, { action: "setKey", key: "key" } ]; var metaActionsList = [ { action: "setMetaTitle", key: "metaTitle" }, { action: "setMetaKeywords", key: "metaKeywords" }, { action: "setMetaDescription", key: "metaDescription" } ]; var referenceActionsList = [ { action: "changeParent", key: "parent" } ]; function actionsMapBase(diff2, oldObj, newObj, config = {}) { return buildBaseAttributesActions({ actions: baseActionsList, diff: diff2, oldObj, newObj, shouldOmitEmptyString: config.shouldOmitEmptyString, shouldUnsetOmittedProperties: config.shouldUnsetOmittedProperties, shouldPreventUnsettingRequiredFields: config.shouldPreventUnsettingRequiredFields }); } function actionsMapReferences(diff2, oldObj, newObj) { return buildReferenceActions({ actions: referenceActionsList, diff: diff2, oldObj, newObj }); } function actionsMapMeta(diff2, oldObj, newObj) { return buildBaseAttributesActions({ actions: metaActionsList, diff: diff2, oldObj, newObj }); } // src/utils/copy-empty-array-props.ts import isNil3 from "lodash.isnil"; var CUSTOM = "custom"; function copyEmptyArrayProps(oldObj = {}, newObj = {}) { if (!isNil3(oldObj) && !isNil3(newObj)) { const nextObjectWithEmptyArray = Object.entries(oldObj).reduce( (merged, [key, value]) => { if (key === CUSTOM) return merged; if (Array.isArray(value) && newObj[key] && newObj[key].length >= 1) { const hashMapValue = value.reduce((acc, val) => { acc[val.id] = val; return acc; }, {}); for (let i = 0; i < newObj[key].length; i++) { if (!isNil3(newObj[key][i]) && typeof newObj[key][i] === "object" && !isNil3(newObj[key][i].id)) { const foundObject = hashMapValue[newObj[key][i].id]; if (!isNil3(foundObject)) { const [, nestedObject] = copyEmptyArrayProps( foundObject, newObj[key][i] ); if (Object.isFrozen(merged[key])) { merged[key] = merged[key].slice(); } merged[key][i] = nestedObject; } } } return merged; } if (Array.isArray(value)) { merged[key] = isNil3(newObj[key]) ? [] : newObj[key]; return merged; } if (!isNil3(newObj[key]) && typeof value === "object" && // Ignore Date as this will create invalid object since typeof date === 'object' return true // ex: {date: new Date()} will result {date: {}} !(value instanceof Date)) { const [, nestedObject] = copyEmptyArrayProps(value, newObj[key]); merged[key] = nestedObject; return merged; } return merged; }, { ...newObj } ); return [oldObj, nextObjectWithEmptyArray]; } return [oldObj, newObj]; } // src/categories/categories.ts function createCategoryMapActions(mapActionGroup, syncActionConfig) { return function doMapActions(diff2, newObj, oldObj) { const allActions = []; allActions.push( mapActionGroup( "base", () => actionsMapBase(diff2, oldObj, newObj, syncActionConfig) ) ); allActions.push( mapActionGroup( "references", () => actionsMapReferences(diff2, oldObj, newObj) ) ); allActions.push( mapActionGroup( "meta", () => actionsMapMeta(diff2, oldObj, newObj) ) ); allActions.push( mapActionGroup( "custom", () => actionsMapCustom(diff2, newObj, oldObj) ) ); allActions.push( mapActionGroup( "assets", () => actionsMapAssets( diff2, oldObj, newObj ) ) ); return allActions.flat(); }; } var categories_default = (actionGroupList, syncActionConfig) => { const mapActionGroup = createMapActionGroup(actionGroupList); const doMapActions = createCategoryMapActions( mapActionGroup, syncActionConfig ); const buildActions = createBuildActions( diff, doMapActions, copyEmptyArrayProps ); return { buildActions }; }; // src/customers/customer-actions.ts var isEmptyValue = createIsEmptyValue([void 0, null, ""]); var baseActionsList2 = [ { action: "setSalutation", key: "salutation" }, { action: "changeEmail", key: "email" }, { action: "setFirstName", key: "firstName" }, { action: "setLastName", key: "lastName" }, { action: "setMiddleName", key: "middleName" }, { action: "setTitle", key: "title" }, { action: "setCustomerNumber", key: "customerNumber" }, { action: "setExternalId", key: "externalId" }, { action: "setCompanyName", key: "companyName" }, { action: "setDateOfBirth", key: "dateOfBirth" }, { action: "setLocale", key: "locale" }, { action: "setVatId", key: "vatId" }, { action: "setStores", key: "stores" }, { action: "setKey", key: "key" } ]; var setDefaultBaseActionsList = [ { action: "setDefaultBillingAddress", key: "defaultBillingAddressId", actionKey: "addressId" }, { action: "setDefaultShippingAddress", key: "defaultShippingAddressId", actionKey: "addressId" } ]; var referenceActionsList2 = [ { action: "setCustomerGroup", key: "customerGroup" } ]; var authenticationModeActionsList = [ { action: "setAuthenticationMode", key: "authenticationMode", value: "password" } ]; function actionsMapBase2(diff2, oldObj, newObj, config = {}) { return buildBaseAttributesActions({ actions: baseActionsList2, diff: diff2, oldObj, newObj, shouldOmitEmptyString: config.shouldOmitEmptyString, shouldUnsetOmittedProperties: config.shouldUnsetOmittedProperties, shouldPreventUnsettingRequiredFields: config.shouldPreventUnsettingRequiredFields }); } function actionsMapSetDefaultBase(diff2, oldObj, newObj, config = {}) { return buildBaseAttributesActions({ actions: setDefaultBaseActionsList, diff: diff2, oldObj, newObj, shouldOmitEmptyString: config.shouldOmitEmptyString, shouldUnsetOmittedProperties: config.shouldUnsetOmittedProperties, shouldPreventUnsettingRequiredFields: config.shouldPreventUnsettingRequiredFields }); } function actionsMapReferences2(diff2, oldObj, newObj) { return buildReferenceActions({ actions: referenceActionsList2, diff: diff2, oldObj, newObj }); } function actionsMapAddresses(diff2, oldObj, newObj) { const handler = createBuildArrayActions("addresses", { [ADD_ACTIONS]: (newObject) => ({ action: "addAddress", address: newObject }), [REMOVE_ACTIONS]: (objectToRemove) => ({ action: "removeAddress", addressId: objectToRemove.id }), [CHANGE_ACTIONS]: (oldObject, updatedObject) => ({ action: "changeAddress", addressId: oldObject.id, address: updatedObject }) }); return handler(diff2, oldObj, newObj); } function actionsMapAddBillingAddresses(diff2, oldObj, newObj) { const handler = createBuildArrayActions("billingAddressIds", { [ADD_ACTIONS]: (addressId) => ({ action: "addBillingAddressId", addressId }) }); return handler(diff2, oldObj, newObj); } function actionsMapRemoveBillingAddresses(diff2, oldObj, newObj) { const handler = createBuildArrayActions("billingAddressIds", { [REMOVE_ACTIONS]: (addressId) => ({ action: "removeBillingAddressId", addressId }) }); return handler(diff2, oldObj, newObj); } function actionsMapAddShippingAddresses(diff2, oldObj, newObj) { const handler = createBuildArrayActions("shippingAddressIds", { [ADD_ACTIONS]: (addressId) => ({ action: "addShippingAddressId", addressId }) }); return handler(diff2, oldObj, newObj); } function actionsMapRemoveShippingAddresses(diff2, oldObj, newObj) { const handler = createBuildArrayActions("shippingAddressIds", { [REMOVE_ACTIONS]: (addressId) => ({ action: "removeShippingAddressId", addressId }) }); return handler(diff2, oldObj, newObj); } function actionsMapAuthenticationModes(diff2, oldObj, newObj) { return buildAuthenticationModeActions({ actions: authenticationModeActionsList, diff: diff2, oldObj, newObj }); } function buildAuthenticationModeActions({ actions, diff: diff2, oldObj, newObj }) { return actions.map((item) => { const key = item.key; const value = item.value || item.key; const delta = diff2[key]; const before = oldObj[key]; const now = newObj[key]; const isNotDefinedBefore = isEmptyValue(oldObj[key]); const isNotDefinedNow = isEmptyValue(newObj[key]); const authenticationModes = ["Password", "ExternalAuth"]; if (!delta) return void 0; if (isNotDefinedNow && isNotDefinedBefore) return void 0; if (newObj.authenticationMode === "Password" && !newObj.password) throw new Error( "Cannot set to Password authentication mode without password" ); if ("authenticationMode" in newObj && !authenticationModes.includes(newObj.authenticationMode)) throw new Error("Invalid Authentication Mode"); if (!isNotDefinedNow && isNotDefinedBefore) { if (newObj.authenticationMode === "ExternalAuth") return { action: item.action, authMode: now }; return { action: item.action, authMode: now, [value]: newObj.password }; } if (isNotDefinedNow && !{}.hasOwnProperty.call(newObj, key)) return void 0; if (isNotDefinedNow && {}.hasOwnProperty.call(newObj, key)) return void 0; const patched = patch(clone(before), delta); if (newObj.authenticationMode === "ExternalAuth") return { action: item.action, authMode: patched }; return { action: item.action, authMode: patched, [value]: newObj.password }; }).filter(notEmpty); } // src/customers/customers.ts function createCustomerMapActions(mapActionGroup, syncActionConfig) { return function doMapActions(diff2, newObj, oldObj) { const allActions = []; allActions.push( mapActionGroup( "base", () => actionsMapBase2(diff2, oldObj, newObj, syncActionConfig) ) ); allActions.push( mapActionGroup( "references", () => actionsMapReferences2(diff2, oldObj, newObj) ) ); allActions.push( mapActionGroup( "billingAddressIds", () => actionsMapRemoveBillingAddresses(diff2, oldObj, newObj) ) ); allActions.push( mapActionGroup( "shippingAddressIds", () => actionsMapRemoveShippingAddresses( diff2, oldObj, newObj ) ) ); allActions.push( mapActionGroup( "addresses", () => actionsMapAddresses(diff2, oldObj, newObj) ) ); allActions.push( mapActionGroup( "base", () => actionsMapSetDefaultBase( diff2, oldObj, newObj, syncActionConfig ) ) ); allActions.push( mapActionGroup( "billingAddressIds", () => actionsMapAddBillingAddresses(diff2, oldObj, newObj) ) ); allActions.push( mapActionGroup( "shippingAddressIds", () => actionsMapAddShippingAddresses(diff2, oldObj, newObj) ) ); allActions.push( mapActionGroup( "custom", () => actionsMapCustom(diff2, newObj, oldObj) ) ); allActions.push( mapActionGroup( "authenticationModes", () => actionsMapAuthenticationModes(diff2, oldObj, newObj) ) ); return allActions.flat(); }; } var customers_default = (actionGroupList, syncActionConfig = {}) => { const mapActionGroup = createMapActionGroup(actionGroupList); const doMapActions = createCustomerMapActions( mapActionGroup, syncActionConfig ); const buildActions = createBuildActions( diff, doMapActions, copyEmptyArrayProps ); return { buildActions }; }; // src/inventories/inventory-actions.ts var baseActionsList3 = [ { action: "changeQuantity", key: "quantityOnStock", actionKey: "quantity" }, { action: "setRestockableInDays", key: "restockableInDays" }, { action: "setExpectedDelivery", key: "expectedDelivery" } ]; var referenceActionsList3 = [ { action: "setSupplyChannel", key: "supplyChannel" } ]; function actionsMapBase3(diff2, oldObj, newObj, config = {}) { return buildBaseAttributesActions({ actions: baseActionsList3, diff: diff2, oldObj, newObj, shouldOmitEmptyString: config.shouldOmitEmptyString, shouldUnsetOmittedProperties: config.shouldUnsetOmittedProperties, shouldPreventUnsettingRequiredFields: config.shouldPreventUnsettingRequiredFields }); } function actionsMapReferences3(diff2, oldObj, newObj) { return buildReferenceActions({ actions: referenceActionsList3, diff: diff2, oldObj, newObj }); } // src/inventories/inventories.ts function createInventoryMapActions(mapActionGroup, syncActionConfig) { return function doMapActions(diff2, newObj, oldObj) { const allActions = []; allActions.push( mapActionGroup( "base", () => actionsMapBase3( diff2, oldObj, newObj, syncActionConfig ) ) ); allActions.push( mapActionGroup( "references", () => actionsMapReferences3(diff2, oldObj, newObj) ) ); allActions.push( mapActionGroup( "custom", () => actionsMapCustom(diff2, newObj, oldObj) ) ); return allActions.flat(); }; } var inventories_default = (actionGroupList, syncActionConfig) => { const mapActionGroup = createMapActionGroup(actionGroupList); const doMapActions = createInventoryMapActions( mapActionGroup, syncActionConfig ); const buildActions = createBuildActions( diff, doMapActions ); return { buildActions }; }; // src/products/product-actions.ts import forEach2 from "lodash.foreach"; import uniqWith from "lodash.uniqwith"; import intersection from "lodash.intersection"; import without from "lodash.without"; // src/utils/extract-matching-pairs.ts function extractMatchingPairs(hashMap, key, before, now) { let oldObjPos; let newObjPos; let oldObj; let newObj; if (hashMap[key]) { oldObjPos = hashMap[key][0]; newObjPos = hashMap[key][1]; if (before && before[oldObjPos]) oldObj = before[oldObjPos]; if (now && now[newObjPos]) newObj = now[newObjPos]; } return { oldObj, newObj }; } // src/utils/find-matching-pairs.ts import forEach from "lodash.foreach"; var REGEX_NUMBER2 = new RegExp(/^\d+$/); var REGEX_UNDERSCORE_NUMBER2 = new RegExp(/^_\d+$/); function preProcessCollection(collection = [], identifier = "id") { return collection.reduce( (acc, currentValue, currentIndex) => { acc.refByIndex[String(currentIndex)] = currentValue[identifier]; acc.refByIdentifier[currentValue[identifier]] = String(currentIndex); return acc; }, { refByIndex: {}, refByIdentifier: {} } ); } function findMatchingPairs(diff2, before = [], now = [], identifier = "id") { const result = {}; const { refByIdentifier: beforeObjRefByIdentifier, refByIndex: beforeObjRefByIndex } = preProcessCollection(before, identifier); const { refByIdentifier: nowObjRefByIdentifier, refByIndex: nowObjRefByIndex } = preProcessCollection(now, identifier); forEach(diff2, (_item, key) => { if (REGEX_NUMBER2.test(key)) { const matchingIdentifier = nowObjRefByIndex[key]; result[key] = [beforeObjRefByIdentifier[matchingIdentifier], key]; } else if (REGEX_UNDERSCORE_NUMBER2.test(key)) { const index = key.substring(1); const matchingIdentifier = beforeObjRefByIndex[index]; result[key] = [index, nowObjRefByIdentifier[matchingIdentifier]]; } }); return result; } // src/utils/array-actions-utils.ts var REGEX_NUMBER3 = new RegExp(/^\d+$/); var REGEX_UNDERSCORE_NUMBER3 = new RegExp(/^_\d+$/); var getIsAddAction = (key, resource) => REGEX_NUMBER3.test(key) && Array.isArray(resource) && resource.length; var getIsUpdateAction = (key, resource) => REGEX_NUMBER3.test(key) && Object.keys(resource).length; var getIsRemoveAction = (key, resource) => REGEX_UNDERSCORE_NUMBER3.test(key) && Number(resource[2]) === 0; var getIsItemMovedAction = (key, resource) => REGEX_UNDERSCORE_NUMBER3.test(key) && Number(resource[2]) === 3; // src/products/product-actions.ts var baseActionsList4 = [ { action: "changeName", key: "name" }, { action: "changeSlug", key: "slug" }, { action: "setDescription", key: "description" }, { action: "setSearchKeywords", key: "searchKeywords" }, { action: "setKey", key: "key" }, { action: "setPriceMode", key: "priceMode" } ]; var baseAssetActionsList = [ { action: "setAssetKey", key: "key", actionKey: "assetKey" }, { action: "changeAssetName", key: "name" }, { action: "setAssetDescription", key: "description" }, { action: "setAssetTags", key: "tags" }, { action: "setAssetSources", key: "sources" } ]; var metaActionsList2 = [ { action: "setMetaTitle", key: "metaTitle" }, { action: "setMetaDescription", key: "metaDescription" }, { action: "setMetaKeywords", key: "metaKeywords" } ]; var referenceActionsList4 = [ { action: "setTaxCategory", key: "taxCategory" }, { action: "transitionState", key: "state" } ]; function _buildSkuActions(variantDiff, oldVariant) { if ({}.hasOwnProperty.call(variantDiff, "sku")) { const newValue = getDeltaValue(variantDiff.sku); if (!newValue && !oldVariant.sku) return null; return { action: "setSku", variantId: oldVariant.id, sku: newValue || null }; } return null; } function _buildKeyActions(variantDiff, oldVariant) { if ({}.hasOwnProperty.call(variantDiff, "key")) { const newValue = getDeltaValue(variantDiff.key); if (!newValue && !oldVariant.key) return null; return { action: "setProductVariantKey", variantId: oldVariant.id, key: newValue || null }; } return null; } function _buildAttributeValue(diffedValue, oldAttributeValue, newAttributeValue) { let value; if (Array.isArray(diffedValue)) value = getDeltaValue(diffedValue, oldAttributeValue); else if (typeof diffedValue === "string") value = getDeltaValue(diffedValue, oldAttributeValue); else if (diffedValue.centAmount || diffedValue.currencyCode) value = { centAmount: diffedValue.centAmount ? getDeltaValue(diffedValue.centAmount) : newAttributeValue.centAmount, currencyCode: diffedValue.currencyCode ? getDeltaValue(diffedValue.currencyCode) : newAttributeValue.currencyCode }; else if (diffedValue.key) value = getDeltaValue(diffedValue.key); else if (typeof diffedValue === "object") if ({}.hasOwnProperty.call(diffedValue, "_t") && diffedValue._t === "a") { value = newAttributeValue; } else { const updatedValue = Object.keys(diffedValue).reduce( (acc, lang) => { const patchedValue = getDeltaValue( diffedValue[lang], acc[lang] ); return Object.assign(acc, { [lang]: patchedValue }); }, { ...oldAttributeValue } ); value = updatedValue; } return value; } function _buildNewSetAttributeAction(variantId, attr, sameForAllAttributeNames) { const attributeName = attr && attr.name; if (!attributeName) return void 0; let action = { action: "setAttribute", variantId, name: attributeName, value: attr.value }; if (sameForAllAttributeNames.indexOf(attributeName) !== -1) { action = { ...action, action: "setAttributeInAllVariants" }; delete action.variantId; } return action; } function _buildSetAttributeAction(diffedValue, oldVariant, attribute, sameForAllAttributeNames) { if (!attribute || !diffedValue) return void 0; let action = { action: "setAttribute", variantId: oldVariant.id, name: attribute.name, value: null }; const oldAttribute = oldVariant.attributes.find( (a) => a.name === attribute.name ) || {}; if (sameForAllAttributeNames.indexOf(attribute.name) !== -1) { action = { ...action, action: "setAttributeInAllVariants" }; delete action.variantId; } action.value = _buildAttributeValue( diffedValue, oldAttribute.value, attribute.value ); return action; } function _buildNewSetProductAttributeAction(attr) { const attributeName = attr && attr.name; if (!attributeName) return void 0; const action = { action: "setProductAttribute", name: attributeName, value: attr.value }; return action; } function _buildSetProductAttributeAction(diffedValue, oldProductData, newAttribute) { if (!newAttribute || !diffedValue) return void 0; const action = { action: "setProductAttribute", name: newAttribute.name, value: null }; const oldAttribute = oldProductData.attributes.find( (a) => a.name === newAttribute.name ) || {}; action.value = _buildAttributeValue( diffedValue, oldAttribute.value, newAttribute.value ); return action; } function _buildVariantImagesAction(diffedImages, oldVariant = {}, newVariant = {}) { const actions = []; const matchingImagePairs = findMatchingPairs( diffedImages, oldVariant.images, newVariant.images, "url" ); forEach2(diffedImages, (image, key) => { const { oldObj, newObj } = extractMatchingPairs( matchingImagePairs, key, oldVariant.images, newVariant.images ); if (REGEX_NUMBER3.test(key)) { if (Array.isArray(image) && image.length) actions.push({ action: "addExternalImage", variantId: oldVariant.id, image: getDeltaValue(image) }); else if (typeof image === "object") { if ({}.hasOwnProperty.call(image, "url") && image.url.length === 2) { actions.push({ action: "removeImage", variantId: oldVariant.id, imageUrl: oldObj.url }); actions.push({ action: "addExternalImage", variantId: oldVariant.id, image: newObj }); } else if ({}.hasOwnProperty.call(image, "label") && (image.label.length === 1 || image.label.length === 2)) actions.push({ action: "setImageLabel", variantId: oldVariant.id, imageUrl: oldObj.url, label: getDeltaValue(image.label) }); } } else if (REGEX_UNDERSCORE_NUMBER3.test(key)) { if (Array.isArray(image) && image.length === 3) { if (Number(image[2]) === 3) actions.push({ action: "moveImageToPosition", variantId: oldVariant.id, imageUrl: oldObj.url, position: Number(image[1]) }); else if (Number(image[2]) === 0) actions.push({ action: "removeImage", variantId: oldVariant.id, imageUrl: oldObj.url }); } } }); return actions; } function _buildVariantPricesAction(diffedPrices, oldVariant = {}, newVariant = {}, enableDiscounted = false) { const addPriceActions = []; const changePriceActions = []; const removePriceActions = []; const matchingPricePairs = findMatchingPairs( diffedPrices, oldVariant.prices, newVariant.prices ); forEach2(diffedPrices, (price, key) => { const { oldObj, newObj } = extractMatchingPairs( matchingPricePairs, key, oldVariant.prices, newVariant.prices ); if (getIsAddAction(key, price)) { const patchedPrice = price.map((p) => { const shallowClone = { ...p }; if (enableDiscounted !== true) delete shallowClone.discounted; return shallowClone; }); addPriceActions.push({ action: "addPrice", variantId: oldVariant.id, price: getDeltaValue(patchedPrice) }); return; } if (getIsUpdateAction(key, price)) { const filteredPrice = clone(price); if (enableDiscounted !== true) delete filteredPrice["discounted"]; if (Object.keys(filteredPrice).length) { const newPrice = { ...newObj }; if (enableDiscounted !== true) delete newPrice["discounted"]; changePriceActions.push({ action: "changePrice", priceId: oldObj.id, price: newPrice }); } return; } if (getIsRemoveAction(key, price)) { removePriceActions.push({ action: "removePrice", priceId: oldObj.id }); } }); return [addPriceActions, changePriceActions, removePriceActions]; } function _buildProductAttributesActions(diffedAttributes, oldProductData, newProductData) { const actions = []; if (!diffedAttributes) return actions; forEach2(diffedAttributes, (value, key) => { if (REGEX_NUMBER3.test(key)) { if (Array.isArray(value)) { const setAction = _buildNewSetProductAttributeAction( getDeltaValue(value) ); if (setAction) actions.push(setAction); } else if (newProductData.attributes) { const setAction = _buildSetProductAttributeAction( value["value"], oldProductData, newProductData.attributes[key] ); if (setAction) actions.push(setAction); } } else if (REGEX_UNDERSCORE_NUMBER3.test(key)) { if (Array.isArray(value)) { if (value.length === 3 && value[2] === 3) return; let deltaValue = getDeltaValue(value); if (!deltaValue) if (value[0] && value[0].name) deltaValue = { name: value[0].name }; else deltaValue = void 0; const setAction = _buildNewSetProductAttributeAction( deltaValue ); if (setAction) actions.push(setAction); } else { const index = key.substring(1); if (newProductData.attributes) { const setAction = _buildSetProductAttributeAction( value["value"], oldProductData, newProductData.attributes[index] ); if (setAction) actions.push(setAction); } } } }); return actions; } function _buildVariantAttributesActions(attributes, oldVariant, newVariant, sameForAllAttributeNames) { const actions = []; if (!attributes) return actions; forEach2(attributes, (value, key) => { if (REGEX_NUMBER3.test(key)) { if (Array.isArray(value)) { const { id } = oldVariant; const deltaValue = getDeltaValue(value); const setAction = _buildNewSetAttributeAction( id, deltaValue, sameForAllAttributeNames ); if (setAction) actions.push(setAction); } else if (newVariant.attributes) { const setAction = _buildSetAttributeAction( value.value, oldVariant, newVariant.attributes[key], sameForAllAttributeNames ); if (setAction) actions.push(setAction); } } else if (REGEX_UNDERSCORE_NUMBER3.test(key)) if (Array.isArray(value)) { if (value.length === 3 && value[2] === 3) return; const { id } = oldVariant; let deltaValue = getDeltaValue(value); if (!deltaValue) if (value[0] && value[0].name) deltaValue = { name: value[0].name }; else deltaValue = void 0; const setAction = _buildNewSetAttributeAction( id, deltaValue, sameForAllAttributeNames ); if (setAction) actions.push(setAction); } else { const index = key.substring(1); if (newVariant.attributes) { const setAction = _buildSetAttributeAction( value.value, oldVariant, newVariant.attributes[index], sameForAllAttributeNames ); if (setAction) actions.push(setAction); } } }); return actions; } function toAssetIdentifier2(asset) { const assetIdentifier = asset.id ? { assetId: asset.id } : { assetKey: asset.key }; return assetIdentifier; } function toVariantIdentifier(variant) { const { id, sku } = variant; return id ? { variantId: id } : { sku }; } function _buildVariantChangeAssetOrderAction(diffAssets, oldVariant, newVariant) { const isAssetOrderChanged = Object.entries(diffAssets).find( (entry) => getIsItemMovedAction(entry[0], entry[1]) ); if (!isAssetOrderChanged) { return []; } const assetIdsBefore = oldVariant.assets.map((_) => _.id); const assetIdsCurrent = newVariant.assets.map((_) => _.id).filter((_) => _ !== void 0); const assetIdsToKeep = intersection(assetIdsCurrent, assetIdsBefore); const assetIdsToRemove = without(assetIdsBefore, ...assetIdsToKeep); const changeAssetOrderAction = { action: "changeAssetOrder", assetOrder: assetIdsToKeep.concat(assetIdsToRemove), ...toVariantIdentifier(oldVariant) }; return [changeAssetOrderAction]; } function _buildVariantAssetsActions(diffAssets, oldVariant, newVariant) { const assetActions = []; const matchingAssetPairs = findMatchingPairs( diffAssets, oldVariant.assets, newVariant.assets ); forEach2(diffAssets, (asset, key) => { const { oldObj: oldAsset, newObj: newAsset } = extractMatchingPairs( matchingAssetPairs, key, oldVariant.assets, newVariant.assets ); if (getIsAddAction(key, asset)) { assetActions.push({ action: "addAsset", asset: getDeltaValue(asset), ...toVariantIdentifier(newVariant), position: Number(key) }); return; } if (getIsUpdateAction(key, asset)) { const basicActions = buildBaseAttributesActions({ actions: baseAssetActionsList, diff: asset, oldObj: oldAsset, newObj: newAsset }).map((action) => { if (action.action === "setAssetKey") { return { ...action, ...toVariantIdentifier(oldVariant), assetId: oldAsset.id }; } return { ...action, ...toVariantIdentifier(oldVariant), ...toAssetIdentifier2(oldAsset) }; }); assetActions.push(...basicActions); if (asset.custom) { const customActions = actionsMapCustom(asset, newAsset, oldAsset, { actions: { setCustomType: "setAssetCustomType", setCustomField: "setAssetCustomField" }, ...toVariantIdentifier(oldVariant), ...toAssetIdentifier2(oldAsset) }); assetActions.push(...customActions); } return; } if (getIsRemoveAction(key, asset)) { assetActions.push({ action: "removeAsset", ...toAssetIdentifier2(oldAsset), ...toVariantIdentifier(oldVariant) }); } }); const changedAssetOrderAction = _buildVariantChangeAssetOrderAction( diffAssets, oldVariant, newVariant ); return [...changedAssetOrderAction, ...assetActions]; } function actionsMapBase4(diff2, oldObj, newObj, config = {}) { return buildBaseAttributesActions({ actions: baseActionsList4, diff: diff2, oldObj, newObj, shouldOmitEmptyString: config.shouldOmitEmptyString, shouldUnsetOmittedProperties: config.shouldUnsetOmittedProperties }); } function actionsMapMeta2(diff2, oldObj, newObj, config = {}) { return buildBaseAttributesActions({ actions: metaActionsList2, diff: diff2, oldObj, newObj, shouldOmitEmptyString: config.shouldOmitEmptyString, shouldUnsetOmittedProperties: config.shouldUnsetOmittedProperties }); } function actionsMapAddVariants(diff2, oldObj, newObj) { const handler = createBuildArrayActions("variants", { [ADD_ACTIONS]: (newObject) => ({ ...newObject, action: "addVariant" }) }); return handler(diff2, oldObj, newObj); } function actionsMapRemoveVariants(diff2, oldObj, newObj) { const handler = createBuildArrayActions("variants", { [REMOVE_ACTIONS]: ({ id }) => ({ action: "removeVariant", id }) }); return handler(diff2, oldObj, newObj); } function actionsMapReferences4(diff2, oldObj, newObj) { return buildReferenceActions({ actions: referenceActionsList4, diff: diff2, oldObj, newObj }); } function actionsMapCategories(diff2) { const actions = []; if (!diff2.categories) return actions; const addToCategoryActions = []; const removeFromCategoryActions = []; forEach2(diff2.categories, (category) => { if (Array.isArray(category)) { const action = { category: category[0] }; if (category.length === 3) { if (category[2] !== 3) { action["action"] = "removeFromCategory"; removeFromCategoryActions.push(action); } } else if (category.length === 1) { action["action"] = "addToCategory"; addToCategoryActions.push(action); } } }); return removeFromCategoryActions.concat(addToCategoryActions); } function actionsMapCategoryOrderHints(diff2, _oldObj) { if (!diff2.categoryOrderHints) return []; if (Array.isArray(diff2.categoryOrderHints)) return []; return Object.keys(diff2.categoryOrderHints).map((categoryId) => { const hintChange = diff2.categoryOrderHints[categoryId]; const action = { action: "setCategoryOrderHint", categoryId }; const updatedAction = clone(action); if (hintChange.length === 1) updatedAction.orderHint = hintChange[0]; else if (hintChange.length === 2 &&