strapi-plugin-bulk-updater 1.4.9 → 1.4.10

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.
@@ -4987,6 +4987,23 @@ async function findExistingDocument(strapi, uid, targetDocId, docLocale) {
4987
4987
  }
4988
4988
  return null;
4989
4989
  }
4990
+ function deepMergeComponent(existingVal, newVal) {
4991
+ if (!existingVal || typeof existingVal !== "object" || Array.isArray(existingVal)) {
4992
+ return newVal;
4993
+ }
4994
+ if (!newVal || typeof newVal !== "object" || Array.isArray(newVal)) {
4995
+ return newVal;
4996
+ }
4997
+ const merged = { ...existingVal };
4998
+ for (const k of Object.keys(newVal)) {
4999
+ if (newVal[k] && typeof newVal[k] === "object" && !Array.isArray(newVal[k])) {
5000
+ merged[k] = deepMergeComponent(existingVal[k], newVal[k]);
5001
+ } else if (newVal[k] !== void 0) {
5002
+ merged[k] = newVal[k];
5003
+ }
5004
+ }
5005
+ return merged;
5006
+ }
4990
5007
  async function processCsvRows(strapi, ct, uid, rows, startRowNumber, options) {
4991
5008
  const attrs = ct.attributes || {};
4992
5009
  const { mode = "auto", publish = true, publishStrategy = "safe", user } = options;
@@ -5021,32 +5038,86 @@ async function processCsvRows(strapi, ct, uid, rows, startRowNumber, options) {
5021
5038
  const normalizedKey = key.toLowerCase().replace(/[\s_-]/g, "");
5022
5039
  if (SYSTEM_FIELD_KEYS.has(normalizedKey)) continue;
5023
5040
  if (key.includes(".")) {
5024
- const [parent, child] = key.split(".");
5025
- const parentDef = attrs[parent];
5026
- if (parentDef?.type === "component" && !parentDef.repeatable && parentDef.component) {
5027
- const comp = strapi.components[parentDef.component];
5028
- const childDef = comp?.attributes?.[child];
5029
- if (childDef) {
5030
- if (!payload[parent]) payload[parent] = {};
5031
- let val = rawVal;
5041
+ const parts = key.split(".");
5042
+ let currentAttrs = attrs;
5043
+ let currentTarget = payload;
5044
+ for (let pIdx = 0; pIdx < parts.length; pIdx++) {
5045
+ const part = parts[pIdx];
5046
+ const isLeaf = pIdx === parts.length - 1;
5047
+ if (isLeaf) {
5048
+ let leafDef = currentAttrs[part];
5049
+ if (!leafDef) {
5050
+ const match = Object.keys(currentAttrs).find(
5051
+ (k) => k.toLowerCase() === part.toLowerCase() || k.toLowerCase() === part.toLowerCase().replace(/\s+/g, "")
5052
+ );
5053
+ if (match) leafDef = currentAttrs[match];
5054
+ }
5055
+ if (!leafDef) {
5056
+ break;
5057
+ }
5032
5058
  if (rawVal === "" || rawVal === null || rawVal === void 0) {
5033
- val = null;
5034
- } else if (childDef.type === "integer" || childDef.type === "biginteger") {
5059
+ if (leafDef.type !== "dynamiczone" && !(leafDef.type === "component" && leafDef.repeatable) && leafDef.type !== "relation") {
5060
+ currentTarget[part] = null;
5061
+ }
5062
+ } else if (leafDef.type === "integer" || leafDef.type === "biginteger") {
5035
5063
  const parsedInt = parseInt(rawVal, 10);
5036
- val = isNaN(parsedInt) ? null : parsedInt;
5037
- } else if (childDef.type === "float" || childDef.type === "decimal") {
5064
+ currentTarget[part] = isNaN(parsedInt) ? null : parsedInt;
5065
+ } else if (leafDef.type === "float" || leafDef.type === "decimal") {
5038
5066
  const parsedFloat = parseFloat(rawVal);
5039
- val = isNaN(parsedFloat) ? null : parsedFloat;
5040
- } else if (childDef.type === "boolean") {
5041
- val = rawVal.toLowerCase() === "true" || rawVal === "1";
5042
- } else if (childDef.type === "json") {
5067
+ currentTarget[part] = isNaN(parsedFloat) ? null : parsedFloat;
5068
+ } else if (leafDef.type === "boolean") {
5069
+ currentTarget[part] = rawVal.toLowerCase() === "true" || rawVal === "1";
5070
+ } else if (leafDef.type === "json") {
5071
+ try {
5072
+ currentTarget[part] = JSON.parse(rawVal);
5073
+ } catch {
5074
+ currentTarget[part] = rawVal;
5075
+ }
5076
+ } else if (leafDef.type === "component" && leafDef.repeatable) {
5077
+ try {
5078
+ const parsed = JSON.parse(rawVal);
5079
+ if (Array.isArray(parsed)) {
5080
+ currentTarget[part] = parsed;
5081
+ }
5082
+ } catch {
5083
+ }
5084
+ } else if (leafDef.type === "relation") {
5043
5085
  try {
5044
- val = JSON.parse(rawVal);
5086
+ const parsed = JSON.parse(rawVal);
5087
+ if (Array.isArray(parsed) || typeof parsed === "object" && parsed !== null) {
5088
+ currentTarget[part] = parsed;
5089
+ } else if (isValidDocId(rawVal)) {
5090
+ currentTarget[part] = rawVal;
5091
+ }
5045
5092
  } catch {
5046
- val = rawVal;
5093
+ if (isValidDocId(rawVal)) {
5094
+ currentTarget[part] = rawVal;
5095
+ }
5047
5096
  }
5097
+ } else {
5098
+ currentTarget[part] = rawVal;
5099
+ }
5100
+ } else {
5101
+ let compDef = currentAttrs[part];
5102
+ if (!compDef) {
5103
+ const match = Object.keys(currentAttrs).find(
5104
+ (k) => k.toLowerCase() === part.toLowerCase() || k.toLowerCase() === part.toLowerCase().replace(/\s+/g, "")
5105
+ );
5106
+ if (match) compDef = currentAttrs[match];
5107
+ }
5108
+ if (compDef?.type === "component" && !compDef.repeatable && compDef.component) {
5109
+ const comp = strapi.components[compDef.component];
5110
+ if (!comp?.attributes) {
5111
+ break;
5112
+ }
5113
+ if (!currentTarget[part] || typeof currentTarget[part] !== "object" || Array.isArray(currentTarget[part])) {
5114
+ currentTarget[part] = {};
5115
+ }
5116
+ currentTarget = currentTarget[part];
5117
+ currentAttrs = comp.attributes;
5118
+ } else {
5119
+ break;
5048
5120
  }
5049
- payload[parent][child] = val;
5050
5121
  }
5051
5122
  }
5052
5123
  continue;
@@ -5181,7 +5252,7 @@ async function processCsvRows(strapi, ct, uid, rows, startRowNumber, options) {
5181
5252
  const mergedPayload = { ...payload };
5182
5253
  for (const key of Object.keys(payload)) {
5183
5254
  if (attrs[key]?.type === "component" && typeof payload[key] === "object" && payload[key] !== null) {
5184
- mergedPayload[key] = { ...existing[key] || {}, ...payload[key] };
5255
+ mergedPayload[key] = deepMergeComponent(existing[key], payload[key]);
5185
5256
  }
5186
5257
  }
5187
5258
  if (Object.keys(mergedPayload).length === 0) {
@@ -5251,7 +5322,7 @@ async function processCsvRows(strapi, ct, uid, rows, startRowNumber, options) {
5251
5322
  const mergedPayload = { ...payload };
5252
5323
  for (const key of Object.keys(payload)) {
5253
5324
  if (attrs[key]?.type === "component" && typeof payload[key] === "object" && payload[key] !== null) {
5254
- mergedPayload[key] = { ...existing[key] || {}, ...payload[key] };
5325
+ mergedPayload[key] = deepMergeComponent(existing[key], payload[key]);
5255
5326
  }
5256
5327
  }
5257
5328
  const updateArgs = {
@@ -5348,7 +5419,7 @@ async function processCsvRows(strapi, ct, uid, rows, startRowNumber, options) {
5348
5419
  const mergedPayload = { ...payload };
5349
5420
  for (const key of Object.keys(payload)) {
5350
5421
  if (attrs[key]?.type === "component" && typeof payload[key] === "object" && payload[key] !== null) {
5351
- mergedPayload[key] = { ...existing[key] || {}, ...payload[key] };
5422
+ mergedPayload[key] = deepMergeComponent(existing[key], payload[key]);
5352
5423
  }
5353
5424
  }
5354
5425
  const updateArgs = {