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