lingo.dev 0.74.12 → 0.74.14

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.
package/build/cli.mjs CHANGED
@@ -580,7 +580,7 @@ import { bucketTypeSchema, localeCodeSchema, resolveOverridenLocale as resolveOv
580
580
  import { ReplexicaEngine } from "@lingo.dev/_sdk";
581
581
  import { Command as Command6 } from "interactive-commander";
582
582
  import Z4 from "zod";
583
- import _17 from "lodash";
583
+ import _18 from "lodash";
584
584
  import Ora5 from "ora";
585
585
 
586
586
  // src/cli/loaders/_utils.ts
@@ -682,26 +682,87 @@ function createJsonLoader() {
682
682
 
683
683
  // src/cli/loaders/flat.ts
684
684
  import { flatten, unflatten } from "flat";
685
+ import _5 from "lodash";
686
+ var OBJECT_NUMERIC_KEY_PREFIX = "__lingodotdev__obj__";
685
687
  function createFlatLoader() {
688
+ let denormalizedKeysMap = {};
686
689
  return createLoader({
687
690
  pull: async (locale, input) => {
688
- return flatten(input || {}, {
691
+ const denormalized = denormalizeObjectKeys(input || {});
692
+ const flattened = flatten(denormalized, {
689
693
  delimiter: "/",
690
694
  transformKey(key) {
691
695
  return encodeURIComponent(String(key));
692
696
  }
693
697
  });
698
+ denormalizedKeysMap = { ...denormalizedKeysMap, ...buildDenormalizedKeysMap(flattened) };
699
+ const normalized = normalizeObjectKeys(flattened);
700
+ return normalized;
694
701
  },
695
702
  push: async (locale, data) => {
696
- return unflatten(data || {}, {
703
+ const denormalized = mapDenormalizedKeys(data, denormalizedKeysMap);
704
+ const unflattened = unflatten(denormalized || {}, {
697
705
  delimiter: "/",
698
706
  transformKey(key) {
699
707
  return decodeURIComponent(String(key));
700
708
  }
701
709
  });
710
+ const normalized = normalizeObjectKeys(unflattened);
711
+ return normalized;
702
712
  }
703
713
  });
704
714
  }
715
+ function buildDenormalizedKeysMap(obj) {
716
+ if (!obj) return {};
717
+ return Object.keys(obj).reduce(
718
+ (acc, key) => {
719
+ if (key) {
720
+ const normalizedKey = `${key}`.replace(OBJECT_NUMERIC_KEY_PREFIX, "");
721
+ acc[normalizedKey] = key;
722
+ }
723
+ return acc;
724
+ },
725
+ {}
726
+ );
727
+ }
728
+ function mapDenormalizedKeys(obj, denormalizedKeysMap) {
729
+ return Object.keys(obj).reduce(
730
+ (acc, key) => {
731
+ const denormalizedKey = denormalizedKeysMap[key];
732
+ acc[denormalizedKey] = obj[key];
733
+ return acc;
734
+ },
735
+ {}
736
+ );
737
+ }
738
+ function denormalizeObjectKeys(obj) {
739
+ if (_5.isObject(obj) && !_5.isArray(obj)) {
740
+ return _5.transform(
741
+ obj,
742
+ (result, value, key) => {
743
+ const newKey = !isNaN(Number(key)) ? `${OBJECT_NUMERIC_KEY_PREFIX}${key}` : key;
744
+ result[newKey] = _5.isObject(value) ? denormalizeObjectKeys(value) : value;
745
+ },
746
+ {}
747
+ );
748
+ } else {
749
+ return obj;
750
+ }
751
+ }
752
+ function normalizeObjectKeys(obj) {
753
+ if (_5.isObject(obj) && !_5.isArray(obj)) {
754
+ return _5.transform(
755
+ obj,
756
+ (result, value, key) => {
757
+ const newKey = `${key}`.replace(OBJECT_NUMERIC_KEY_PREFIX, "");
758
+ result[newKey] = _5.isObject(value) ? normalizeObjectKeys(value) : value;
759
+ },
760
+ {}
761
+ );
762
+ } else {
763
+ return obj;
764
+ }
765
+ }
705
766
 
706
767
  // src/cli/loaders/text-file.ts
707
768
  import fs5 from "fs/promises";
@@ -713,7 +774,7 @@ function createTextFileLoader(pathPattern) {
713
774
  const trimmedResult = result.trim();
714
775
  return trimmedResult;
715
776
  },
716
- async push(locale, data, _19, originalLocale) {
777
+ async push(locale, data, _20, originalLocale) {
717
778
  const draftPath = pathPattern.replace("[locale]", locale);
718
779
  const finalPath = path6.resolve(draftPath);
719
780
  const dirPath = path6.dirname(finalPath);
@@ -782,15 +843,15 @@ function createRootKeyLoader(replaceAll = false) {
782
843
  }
783
844
 
784
845
  // src/cli/loaders/flutter.ts
785
- import _5 from "lodash";
846
+ import _6 from "lodash";
786
847
  function createFlutterLoader() {
787
848
  return createLoader({
788
849
  async pull(locale, input) {
789
- const result = _5.pickBy(input, (value, key) => !key.startsWith("@"));
850
+ const result = _6.pickBy(input, (value, key) => !key.startsWith("@"));
790
851
  return result;
791
852
  },
792
853
  async push(locale, data, originalInput) {
793
- const result = _5.merge({}, originalInput, { "@@locale": locale }, data);
854
+ const result = _6.merge({}, originalInput, { "@@locale": locale }, data);
794
855
  return result;
795
856
  }
796
857
  });
@@ -892,25 +953,29 @@ function createAndroidLoader() {
892
953
  // src/cli/loaders/csv.ts
893
954
  import { parse } from "csv-parse/sync";
894
955
  import { stringify } from "csv-stringify/sync";
895
- import _6 from "lodash";
956
+ import _7 from "lodash";
896
957
  function createCsvLoader() {
897
958
  return createLoader({
898
959
  async pull(locale, _input) {
899
960
  const input = parse(_input, {
900
- columns: true
961
+ columns: true,
962
+ skip_empty_lines: true
901
963
  });
902
964
  const result = {};
903
- _6.forEach(input, (row) => {
965
+ _7.forEach(input, (row) => {
904
966
  const key = row.id;
905
- if (key && row[locale]) {
967
+ if (key && row[locale] && row[locale].trim() !== "") {
906
968
  result[key] = row[locale];
907
969
  }
908
970
  });
909
971
  return result;
910
972
  },
911
973
  async push(locale, data, originalInput) {
912
- const input = parse(originalInput || "", { columns: true });
913
- const columns = Object.keys(input[0] || { id: "" });
974
+ const input = parse(originalInput || "", {
975
+ columns: true,
976
+ skip_empty_lines: true
977
+ });
978
+ const columns = input.length > 0 ? Object.keys(input[0]) : ["id", locale];
914
979
  const updatedRows = input.map((row) => ({
915
980
  ...row,
916
981
  [locale]: data[row.id] || row[locale] || ""
@@ -918,13 +983,18 @@ function createCsvLoader() {
918
983
  const existingKeys = new Set(input.map((row) => row.id));
919
984
  Object.entries(data).forEach(([key, value]) => {
920
985
  if (!existingKeys.has(key)) {
921
- updatedRows.push({
986
+ const newRow = {
922
987
  id: key,
923
- ...Object.fromEntries(columns.map((column) => [column, column === locale ? value : ""]))
924
- });
988
+ ...Object.fromEntries(columns.map((column) => [column, ""]))
989
+ };
990
+ newRow[locale] = value;
991
+ updatedRows.push(newRow);
925
992
  }
926
993
  });
927
- return stringify(updatedRows, { header: true });
994
+ return stringify(updatedRows, {
995
+ header: true,
996
+ columns
997
+ });
928
998
  }
929
999
  });
930
1000
  }
@@ -1118,7 +1188,7 @@ function createPropertiesLoader() {
1118
1188
  return result;
1119
1189
  },
1120
1190
  async push(locale, payload) {
1121
- const result = Object.entries(payload).filter(([_19, value]) => value != null).map(([key, value]) => `${key}=${value}`).join("\n");
1191
+ const result = Object.entries(payload).filter(([_20, value]) => value != null).map(([key, value]) => `${key}=${value}`).join("\n");
1122
1192
  return result;
1123
1193
  }
1124
1194
  });
@@ -1204,7 +1274,7 @@ function createXcodeStringsdictLoader() {
1204
1274
  }
1205
1275
 
1206
1276
  // src/cli/loaders/xcode-xcstrings.ts
1207
- import _7 from "lodash";
1277
+ import _8 from "lodash";
1208
1278
  function createXcodeXcstringsLoader() {
1209
1279
  return createLoader({
1210
1280
  async pull(locale, input) {
@@ -1268,7 +1338,7 @@ function createXcodeXcstringsLoader() {
1268
1338
  };
1269
1339
  }
1270
1340
  }
1271
- const result = _7.merge({}, originalInput, langDataToMerge);
1341
+ const result = _8.merge({}, originalInput, langDataToMerge);
1272
1342
  return result;
1273
1343
  }
1274
1344
  });
@@ -1310,17 +1380,17 @@ async function loadPrettierConfig() {
1310
1380
  }
1311
1381
 
1312
1382
  // src/cli/loaders/unlocalizable.ts
1313
- import _8 from "lodash";
1383
+ import _9 from "lodash";
1314
1384
  import _isUrl from "is-url";
1315
1385
  import { isValid, parseISO } from "date-fns";
1316
1386
  function createUnlocalizableLoader() {
1317
1387
  const rules = {
1318
- isEmpty: (v) => _8.isEmpty(v),
1319
- isNumber: (v) => !_8.isNaN(_8.toNumber(v)),
1320
- isBoolean: (v) => _8.isBoolean(v),
1321
- isIsoDate: (v) => _8.isString(v) && _isIsoDate(v),
1322
- isSystemId: (v) => _8.isString(v) && _isSystemId(v),
1323
- isUrl: (v) => _8.isString(v) && _isUrl(v)
1388
+ isEmpty: (v) => _9.isEmpty(v),
1389
+ isNumber: (v) => !_9.isNaN(_9.toNumber(v)),
1390
+ isBoolean: (v) => _9.isBoolean(v),
1391
+ isIsoDate: (v) => _9.isString(v) && _isIsoDate(v),
1392
+ isSystemId: (v) => _9.isString(v) && _isSystemId(v),
1393
+ isUrl: (v) => _9.isString(v) && _isUrl(v)
1324
1394
  };
1325
1395
  return createLoader({
1326
1396
  async pull(locale, input) {
@@ -1331,12 +1401,12 @@ function createUnlocalizableLoader() {
1331
1401
  }
1332
1402
  }
1333
1403
  return false;
1334
- }).map(([key, _19]) => key);
1335
- const result = _8.omitBy(input, (_19, key) => passthroughKeys.includes(key));
1404
+ }).map(([key, _20]) => key);
1405
+ const result = _9.omitBy(input, (_20, key) => passthroughKeys.includes(key));
1336
1406
  return result;
1337
1407
  },
1338
1408
  async push(locale, data, originalInput) {
1339
- const result = _8.merge({}, originalInput, data);
1409
+ const result = _9.merge({}, originalInput, data);
1340
1410
  return result;
1341
1411
  }
1342
1412
  });
@@ -1349,7 +1419,7 @@ function _isIsoDate(v) {
1349
1419
  }
1350
1420
 
1351
1421
  // src/cli/loaders/po/index.ts
1352
- import _9 from "lodash";
1422
+ import _10 from "lodash";
1353
1423
  import gettextParser from "gettext-parser";
1354
1424
  function createPoLoader(params = { multiline: false }) {
1355
1425
  return composeLoaders(createPoDataLoader(params), createPoContentLoader());
@@ -1362,7 +1432,7 @@ function createPoDataLoader(params) {
1362
1432
  const sections = input.split("\n\n").filter(Boolean);
1363
1433
  for (const section of sections) {
1364
1434
  const sectionPo = gettextParser.po.parse(section);
1365
- const contextKey = _9.keys(sectionPo.translations)[0];
1435
+ const contextKey = _10.keys(sectionPo.translations)[0];
1366
1436
  const entries = sectionPo.translations[contextKey];
1367
1437
  Object.entries(entries).forEach(([msgid, entry]) => {
1368
1438
  if (msgid && entry.msgid) {
@@ -1380,12 +1450,12 @@ function createPoDataLoader(params) {
1380
1450
  const sections = originalInput?.split("\n\n").filter(Boolean) || [];
1381
1451
  const result = sections.map((section) => {
1382
1452
  const sectionPo = gettextParser.po.parse(section);
1383
- const contextKey = _9.keys(sectionPo.translations)[0];
1453
+ const contextKey = _10.keys(sectionPo.translations)[0];
1384
1454
  const entries = sectionPo.translations[contextKey];
1385
1455
  const msgid = Object.keys(entries).find((key) => entries[key].msgid);
1386
1456
  if (!msgid) return section;
1387
1457
  if (data[msgid]) {
1388
- const updatedPo = _9.merge({}, sectionPo, {
1458
+ const updatedPo = _10.merge({}, sectionPo, {
1389
1459
  translations: {
1390
1460
  [contextKey]: {
1391
1461
  [msgid]: {
@@ -1405,7 +1475,7 @@ function createPoDataLoader(params) {
1405
1475
  function createPoContentLoader() {
1406
1476
  return createLoader({
1407
1477
  async pull(locale, input) {
1408
- const result = _9.chain(input).entries().filter(([, entry]) => !!entry.msgid).map(([, entry]) => [
1478
+ const result = _10.chain(input).entries().filter(([, entry]) => !!entry.msgid).map(([, entry]) => [
1409
1479
  entry.msgid,
1410
1480
  {
1411
1481
  singular: entry.msgstr[0] || entry.msgid,
@@ -1415,7 +1485,7 @@ function createPoContentLoader() {
1415
1485
  return result;
1416
1486
  },
1417
1487
  async push(locale, data, originalInput) {
1418
- const result = _9.chain(originalInput).entries().map(([, entry]) => [
1488
+ const result = _10.chain(originalInput).entries().map(([, entry]) => [
1419
1489
  entry.msgid,
1420
1490
  {
1421
1491
  ...entry,
@@ -1538,34 +1608,34 @@ var datoSettingsSchema = Z2.object({
1538
1608
  });
1539
1609
 
1540
1610
  // src/cli/loaders/dato/filter.ts
1541
- import _10 from "lodash";
1611
+ import _11 from "lodash";
1542
1612
  function createDatoFilterLoader() {
1543
1613
  return createLoader({
1544
1614
  async pull(locale, input) {
1545
1615
  const result = {};
1546
- for (const [modelId, modelInfo] of _10.entries(input)) {
1616
+ for (const [modelId, modelInfo] of _11.entries(input)) {
1547
1617
  result[modelId] = {};
1548
1618
  for (const record of modelInfo.records) {
1549
- result[modelId][record.id] = _10.chain(modelInfo.fields).mapKeys((field) => field.api_key).mapValues((field) => _10.get(record, [field.api_key, locale])).value();
1619
+ result[modelId][record.id] = _11.chain(modelInfo.fields).mapKeys((field) => field.api_key).mapValues((field) => _11.get(record, [field.api_key, locale])).value();
1550
1620
  }
1551
1621
  }
1552
1622
  return result;
1553
1623
  },
1554
1624
  async push(locale, data, originalInput, originalLocale) {
1555
- const result = _10.cloneDeep(originalInput || {});
1556
- for (const [modelId, modelInfo] of _10.entries(result)) {
1625
+ const result = _11.cloneDeep(originalInput || {});
1626
+ for (const [modelId, modelInfo] of _11.entries(result)) {
1557
1627
  for (const record of modelInfo.records) {
1558
- for (const [fieldId, fieldValue] of _10.entries(record)) {
1628
+ for (const [fieldId, fieldValue] of _11.entries(record)) {
1559
1629
  const fieldInfo = modelInfo.fields.find((field) => field.api_key === fieldId);
1560
1630
  if (fieldInfo) {
1561
- const sourceFieldValue = _10.get(fieldValue, [originalLocale]);
1562
- const targetFieldValue = _10.get(data, [modelId, record.id, fieldId]);
1631
+ const sourceFieldValue = _11.get(fieldValue, [originalLocale]);
1632
+ const targetFieldValue = _11.get(data, [modelId, record.id, fieldId]);
1563
1633
  if (targetFieldValue) {
1564
- _10.set(record, [fieldId, locale], targetFieldValue);
1634
+ _11.set(record, [fieldId, locale], targetFieldValue);
1565
1635
  } else {
1566
- _10.set(record, [fieldId, locale], sourceFieldValue);
1636
+ _11.set(record, [fieldId, locale], sourceFieldValue);
1567
1637
  }
1568
- _10.chain(fieldValue).keys().reject((loc) => loc === locale || loc === originalLocale).filter((loc) => _10.isEmpty(_10.get(fieldValue, [loc]))).forEach((loc) => _10.set(record, [fieldId, loc], sourceFieldValue)).value();
1638
+ _11.chain(fieldValue).keys().reject((loc) => loc === locale || loc === originalLocale).filter((loc) => _11.isEmpty(_11.get(fieldValue, [loc]))).forEach((loc) => _11.set(record, [fieldId, loc], sourceFieldValue)).value();
1569
1639
  }
1570
1640
  }
1571
1641
  }
@@ -1576,10 +1646,10 @@ function createDatoFilterLoader() {
1576
1646
  }
1577
1647
 
1578
1648
  // src/cli/loaders/dato/api.ts
1579
- import _12 from "lodash";
1649
+ import _13 from "lodash";
1580
1650
 
1581
1651
  // src/cli/loaders/dato/_utils.ts
1582
- import _11 from "lodash";
1652
+ import _12 from "lodash";
1583
1653
  import { buildClient } from "@datocms/cma-client-node";
1584
1654
  function createDatoClient(params) {
1585
1655
  if (!params.apiKey) {
@@ -1754,7 +1824,7 @@ function createDatoApiLoader(config, onConfigUpdate) {
1754
1824
  const result = {
1755
1825
  models: {}
1756
1826
  };
1757
- const updatedConfig = _12.cloneDeep(config);
1827
+ const updatedConfig = _13.cloneDeep(config);
1758
1828
  console.log(`Initializing DatoCMS loader...`);
1759
1829
  const project = await dato.findProject();
1760
1830
  const modelChoices = await getModelChoices(dato, config);
@@ -1772,7 +1842,7 @@ function createDatoApiLoader(config, onConfigUpdate) {
1772
1842
  delete updatedConfig.models[modelId];
1773
1843
  }
1774
1844
  }
1775
- for (const modelId of _12.keys(updatedConfig.models)) {
1845
+ for (const modelId of _13.keys(updatedConfig.models)) {
1776
1846
  const { modelName, fields } = await getModelFields(dato, modelId);
1777
1847
  if (fields.length > 0) {
1778
1848
  result.models[modelId] = { fields: [], records: [] };
@@ -1783,7 +1853,7 @@ function createDatoApiLoader(config, onConfigUpdate) {
1783
1853
  const isLocalized = await updateFieldLocalization(dato, fieldInfo, selectedFields.includes(fieldInfo.id));
1784
1854
  if (isLocalized) {
1785
1855
  result.models[modelId].fields.push(fieldInfo);
1786
- updatedConfig.models[modelId].fields = _12.uniq([
1856
+ updatedConfig.models[modelId].fields = _13.uniq([
1787
1857
  ...updatedConfig.models[modelId].fields || [],
1788
1858
  fieldInfo.api_key
1789
1859
  ]);
@@ -1802,7 +1872,7 @@ function createDatoApiLoader(config, onConfigUpdate) {
1802
1872
  },
1803
1873
  async pull(locale, input, initCtx) {
1804
1874
  const result = {};
1805
- for (const modelId of _12.keys(initCtx?.models || {})) {
1875
+ for (const modelId of _13.keys(initCtx?.models || {})) {
1806
1876
  let records = initCtx?.models[modelId].records || [];
1807
1877
  const recordIds = records.map((record) => record.id);
1808
1878
  records = await dato.findRecords(recordIds);
@@ -1817,7 +1887,7 @@ function createDatoApiLoader(config, onConfigUpdate) {
1817
1887
  return result;
1818
1888
  },
1819
1889
  async push(locale, data, originalInput) {
1820
- for (const modelId of _12.keys(data)) {
1890
+ for (const modelId of _13.keys(data)) {
1821
1891
  for (let i = 0; i < data[modelId].records.length; i++) {
1822
1892
  const record = data[modelId].records[i];
1823
1893
  console.log(`Updating record ${i + 1}/${data[modelId].records.length} for model ${modelId}...`);
@@ -1831,7 +1901,7 @@ async function getModelFields(dato, modelId) {
1831
1901
  const modelInfo = await dato.findModel(modelId);
1832
1902
  return {
1833
1903
  modelName: modelInfo.name,
1834
- fields: _12.filter(modelInfo.fields, (field) => field.type === "field")
1904
+ fields: _13.filter(modelInfo.fields, (field) => field.type === "field")
1835
1905
  };
1836
1906
  }
1837
1907
  async function getFieldDetails(dato, fields) {
@@ -1909,17 +1979,17 @@ async function promptModelSelection(choices) {
1909
1979
  }
1910
1980
 
1911
1981
  // src/cli/loaders/dato/extract.ts
1912
- import _13 from "lodash";
1982
+ import _14 from "lodash";
1913
1983
  function createDatoExtractLoader() {
1914
1984
  return createLoader({
1915
1985
  async pull(locale, input) {
1916
1986
  const result = {};
1917
- for (const [modelId, modelInfo] of _13.entries(input)) {
1918
- for (const [recordId, record] of _13.entries(modelInfo)) {
1919
- for (const [fieldName, fieldValue] of _13.entries(record)) {
1987
+ for (const [modelId, modelInfo] of _14.entries(input)) {
1988
+ for (const [recordId, record] of _14.entries(modelInfo)) {
1989
+ for (const [fieldName, fieldValue] of _14.entries(record)) {
1920
1990
  const parsedValue = createParsedDatoValue(fieldValue);
1921
1991
  if (parsedValue) {
1922
- _13.set(result, [modelId, `_${recordId}`, fieldName], parsedValue);
1992
+ _14.set(result, [modelId, `_${recordId}`, fieldName], parsedValue);
1923
1993
  }
1924
1994
  }
1925
1995
  }
@@ -1927,14 +1997,14 @@ function createDatoExtractLoader() {
1927
1997
  return result;
1928
1998
  },
1929
1999
  async push(locale, data, originalInput) {
1930
- const result = _13.cloneDeep(originalInput || {});
1931
- for (const [modelId, modelInfo] of _13.entries(data)) {
1932
- for (const [virtualRecordId, record] of _13.entries(modelInfo)) {
1933
- for (const [fieldName, fieldValue] of _13.entries(record)) {
2000
+ const result = _14.cloneDeep(originalInput || {});
2001
+ for (const [modelId, modelInfo] of _14.entries(data)) {
2002
+ for (const [virtualRecordId, record] of _14.entries(modelInfo)) {
2003
+ for (const [fieldName, fieldValue] of _14.entries(record)) {
1934
2004
  const [, recordId] = virtualRecordId.split("_");
1935
- const originalFieldValue = _13.get(originalInput, [modelId, recordId, fieldName]);
2005
+ const originalFieldValue = _14.get(originalInput, [modelId, recordId, fieldName]);
1936
2006
  const rawValue = createRawDatoValue(fieldValue, originalFieldValue, true);
1937
- _13.set(result, [modelId, recordId, fieldName], rawValue || originalFieldValue);
2007
+ _14.set(result, [modelId, recordId, fieldName], rawValue || originalFieldValue);
1938
2008
  }
1939
2009
  }
1940
2010
  }
@@ -1943,25 +2013,25 @@ function createDatoExtractLoader() {
1943
2013
  });
1944
2014
  }
1945
2015
  function detectDatoFieldType(rawDatoValue) {
1946
- if (_13.has(rawDatoValue, "document") && _13.get(rawDatoValue, "schema") === "dast") {
2016
+ if (_14.has(rawDatoValue, "document") && _14.get(rawDatoValue, "schema") === "dast") {
1947
2017
  return "structured_text";
1948
- } else if (_13.has(rawDatoValue, "no_index") || _13.has(rawDatoValue, "twitter_card")) {
2018
+ } else if (_14.has(rawDatoValue, "no_index") || _14.has(rawDatoValue, "twitter_card")) {
1949
2019
  return "seo";
1950
- } else if (_13.get(rawDatoValue, "type") === "item") {
2020
+ } else if (_14.get(rawDatoValue, "type") === "item") {
1951
2021
  return "single_block";
1952
- } else if (_13.isArray(rawDatoValue) && _13.every(rawDatoValue, (item) => _13.get(item, "type") === "item")) {
2022
+ } else if (_14.isArray(rawDatoValue) && _14.every(rawDatoValue, (item) => _14.get(item, "type") === "item")) {
1953
2023
  return "rich_text";
1954
2024
  } else if (_isFile(rawDatoValue)) {
1955
2025
  return "file";
1956
- } else if (_13.isArray(rawDatoValue) && _13.every(rawDatoValue, (item) => _isFile(item))) {
2026
+ } else if (_14.isArray(rawDatoValue) && _14.every(rawDatoValue, (item) => _isFile(item))) {
1957
2027
  return "gallery";
1958
2028
  } else if (_isJson(rawDatoValue)) {
1959
2029
  return "json";
1960
- } else if (_13.isString(rawDatoValue)) {
2030
+ } else if (_14.isString(rawDatoValue)) {
1961
2031
  return "string";
1962
2032
  } else if (_isVideo(rawDatoValue)) {
1963
2033
  return "video";
1964
- } else if (_13.isArray(rawDatoValue) && _13.every(rawDatoValue, (item) => _13.isString(item))) {
2034
+ } else if (_14.isArray(rawDatoValue) && _14.every(rawDatoValue, (item) => _14.isString(item))) {
1965
2035
  return "ref_list";
1966
2036
  } else {
1967
2037
  return null;
@@ -2023,9 +2093,9 @@ function serializeStructuredText(rawStructuredText) {
2023
2093
  if ("document" in node) {
2024
2094
  return serializeStructuredTextNode(node.document, [...path9, "document"], acc);
2025
2095
  }
2026
- if (!_13.isNil(node.value)) {
2096
+ if (!_14.isNil(node.value)) {
2027
2097
  acc[[...path9, "value"].join(".")] = node.value;
2028
- } else if (_13.get(node, "type") === "block") {
2098
+ } else if (_14.get(node, "type") === "block") {
2029
2099
  acc[[...path9, "item"].join(".")] = serializeBlock(node.item);
2030
2100
  }
2031
2101
  if (node.children) {
@@ -2037,44 +2107,44 @@ function serializeStructuredText(rawStructuredText) {
2037
2107
  }
2038
2108
  }
2039
2109
  function serializeSeo(rawSeo) {
2040
- return _13.chain(rawSeo).pick(["title", "description"]).value();
2110
+ return _14.chain(rawSeo).pick(["title", "description"]).value();
2041
2111
  }
2042
2112
  function serializeBlock(rawBlock) {
2043
- if (_13.get(rawBlock, "type") === "item" && _13.has(rawBlock, "id")) {
2113
+ if (_14.get(rawBlock, "type") === "item" && _14.has(rawBlock, "id")) {
2044
2114
  return serializeBlock(rawBlock.attributes);
2045
2115
  }
2046
2116
  const result = {};
2047
- for (const [attributeName, attributeValue] of _13.entries(rawBlock)) {
2117
+ for (const [attributeName, attributeValue] of _14.entries(rawBlock)) {
2048
2118
  result[attributeName] = createParsedDatoValue(attributeValue);
2049
2119
  }
2050
2120
  return result;
2051
2121
  }
2052
2122
  function serializeBlockList(rawBlockList) {
2053
- return _13.chain(rawBlockList).map((block) => serializeBlock(block)).value();
2123
+ return _14.chain(rawBlockList).map((block) => serializeBlock(block)).value();
2054
2124
  }
2055
2125
  function serializeVideo(rawVideo) {
2056
- return _13.chain(rawVideo).pick(["title"]).value();
2126
+ return _14.chain(rawVideo).pick(["title"]).value();
2057
2127
  }
2058
2128
  function serializeFile(rawFile) {
2059
- return _13.chain(rawFile).pick(["alt", "title"]).value();
2129
+ return _14.chain(rawFile).pick(["alt", "title"]).value();
2060
2130
  }
2061
2131
  function serializeGallery(rawGallery) {
2062
- return _13.chain(rawGallery).map((item) => serializeFile(item)).value();
2132
+ return _14.chain(rawGallery).map((item) => serializeFile(item)).value();
2063
2133
  }
2064
2134
  function deserializeFile(parsedFile, originalRawFile) {
2065
- return _13.chain(parsedFile).defaults(originalRawFile).value();
2135
+ return _14.chain(parsedFile).defaults(originalRawFile).value();
2066
2136
  }
2067
2137
  function deserializeGallery(parsedGallery, originalRawGallery) {
2068
- return _13.chain(parsedGallery).map((item, i) => deserializeFile(item, originalRawGallery[i])).value();
2138
+ return _14.chain(parsedGallery).map((item, i) => deserializeFile(item, originalRawGallery[i])).value();
2069
2139
  }
2070
2140
  function deserializeVideo(parsedVideo, originalRawVideo) {
2071
- return _13.chain(parsedVideo).defaults(originalRawVideo).value();
2141
+ return _14.chain(parsedVideo).defaults(originalRawVideo).value();
2072
2142
  }
2073
2143
  function deserializeBlock(payload, rawNode, isClean = false) {
2074
- const result = _13.cloneDeep(rawNode);
2075
- for (const [attributeName, attributeValue] of _13.entries(rawNode.attributes)) {
2144
+ const result = _14.cloneDeep(rawNode);
2145
+ for (const [attributeName, attributeValue] of _14.entries(rawNode.attributes)) {
2076
2146
  const rawValue = createRawDatoValue(payload[attributeName], attributeValue, isClean);
2077
- _13.set(result, ["attributes", attributeName], rawValue);
2147
+ _14.set(result, ["attributes", attributeName], rawValue);
2078
2148
  }
2079
2149
  if (isClean) {
2080
2150
  delete result["id"];
@@ -2082,33 +2152,33 @@ function deserializeBlock(payload, rawNode, isClean = false) {
2082
2152
  return result;
2083
2153
  }
2084
2154
  function deserializeSeo(parsedSeo, originalRawSeo) {
2085
- return _13.chain(parsedSeo).pick(["title", "description"]).defaults(originalRawSeo).value();
2155
+ return _14.chain(parsedSeo).pick(["title", "description"]).defaults(originalRawSeo).value();
2086
2156
  }
2087
2157
  function deserializeBlockList(parsedBlockList, originalRawBlockList, isClean = false) {
2088
- return _13.chain(parsedBlockList).map((block, i) => deserializeBlock(block, originalRawBlockList[i], isClean)).value();
2158
+ return _14.chain(parsedBlockList).map((block, i) => deserializeBlock(block, originalRawBlockList[i], isClean)).value();
2089
2159
  }
2090
2160
  function deserializeStructuredText(parsedStructuredText, originalRawStructuredText) {
2091
- const result = _13.cloneDeep(originalRawStructuredText);
2092
- for (const [path9, value] of _13.entries(parsedStructuredText)) {
2093
- const realPath = _13.chain(path9.split(".")).flatMap((s) => !_13.isNaN(_13.toNumber(s)) ? ["children", s] : s).value();
2094
- const deserializedValue = createRawDatoValue(value, _13.get(originalRawStructuredText, realPath), true);
2095
- _13.set(result, realPath, deserializedValue);
2161
+ const result = _14.cloneDeep(originalRawStructuredText);
2162
+ for (const [path9, value] of _14.entries(parsedStructuredText)) {
2163
+ const realPath = _14.chain(path9.split(".")).flatMap((s) => !_14.isNaN(_14.toNumber(s)) ? ["children", s] : s).value();
2164
+ const deserializedValue = createRawDatoValue(value, _14.get(originalRawStructuredText, realPath), true);
2165
+ _14.set(result, realPath, deserializedValue);
2096
2166
  }
2097
2167
  return result;
2098
2168
  }
2099
2169
  function _isJson(rawDatoValue) {
2100
2170
  try {
2101
- return _13.isString(rawDatoValue) && rawDatoValue.startsWith("{") && rawDatoValue.endsWith("}") && !!JSON.parse(rawDatoValue);
2171
+ return _14.isString(rawDatoValue) && rawDatoValue.startsWith("{") && rawDatoValue.endsWith("}") && !!JSON.parse(rawDatoValue);
2102
2172
  } catch (e) {
2103
2173
  return false;
2104
2174
  }
2105
2175
  }
2106
2176
  function _isFile(rawDatoValue) {
2107
- return _13.isObject(rawDatoValue) && ["alt", "title", "custom_data", "focal_point", "upload_id"].every((key) => _13.has(rawDatoValue, key));
2177
+ return _14.isObject(rawDatoValue) && ["alt", "title", "custom_data", "focal_point", "upload_id"].every((key) => _14.has(rawDatoValue, key));
2108
2178
  }
2109
2179
  function _isVideo(rawDatoValue) {
2110
- return _13.isObject(rawDatoValue) && ["url", "title", "width", "height", "provider", "provider_uid", "thumbnail_url"].every(
2111
- (key) => _13.has(rawDatoValue, key)
2180
+ return _14.isObject(rawDatoValue) && ["url", "title", "width", "height", "provider", "provider_uid", "thumbnail_url"].every(
2181
+ (key) => _14.has(rawDatoValue, key)
2112
2182
  );
2113
2183
  }
2114
2184
 
@@ -2169,7 +2239,7 @@ function createVttLoader() {
2169
2239
  }
2170
2240
 
2171
2241
  // src/cli/loaders/variable/index.ts
2172
- import _14 from "lodash";
2242
+ import _15 from "lodash";
2173
2243
  function createVariableLoader(params) {
2174
2244
  return composeLoaders(variableExtractLoader(params), variableContentLoader());
2175
2245
  }
@@ -2212,11 +2282,11 @@ function variableExtractLoader(params) {
2212
2282
  function variableContentLoader() {
2213
2283
  return createLoader({
2214
2284
  pull: async (locale, input) => {
2215
- const result = _14.mapValues(input, (payload) => payload.value);
2285
+ const result = _15.mapValues(input, (payload) => payload.value);
2216
2286
  return result;
2217
2287
  },
2218
2288
  push: async (locale, data, originalInput) => {
2219
- const result = _14.cloneDeep(originalInput || {});
2289
+ const result = _15.cloneDeep(originalInput || {});
2220
2290
  for (const [key, originalValueObj] of Object.entries(result)) {
2221
2291
  result[key] = {
2222
2292
  ...originalValueObj,
@@ -2239,20 +2309,20 @@ function getFormatSpecifierPattern(type) {
2239
2309
  }
2240
2310
 
2241
2311
  // src/cli/loaders/sync.ts
2242
- import _15 from "lodash";
2312
+ import _16 from "lodash";
2243
2313
  function createSyncLoader() {
2244
2314
  return createLoader({
2245
2315
  async pull(locale, input, originalInput) {
2246
2316
  if (!originalInput) {
2247
2317
  return input;
2248
2318
  }
2249
- return _15.chain(originalInput).mapValues((value, key) => input[key]).value();
2319
+ return _16.chain(originalInput).mapValues((value, key) => input[key]).value();
2250
2320
  },
2251
2321
  async push(locale, data, originalInput) {
2252
2322
  if (!originalInput) {
2253
2323
  return data;
2254
2324
  }
2255
- return _15.chain(originalInput || {}).mapValues((value, key) => data[key]).value();
2325
+ return _16.chain(originalInput || {}).mapValues((value, key) => data[key]).value();
2256
2326
  }
2257
2327
  });
2258
2328
  }
@@ -2479,7 +2549,7 @@ import path7 from "path";
2479
2549
  import Z3 from "zod";
2480
2550
  import YAML3 from "yaml";
2481
2551
  import { MD5 } from "object-hash";
2482
- import _16 from "lodash";
2552
+ import _17 from "lodash";
2483
2553
  function createLockfileHelper() {
2484
2554
  return {
2485
2555
  isLockfileExists: () => {
@@ -2489,23 +2559,23 @@ function createLockfileHelper() {
2489
2559
  registerSourceData: (pathPattern, sourceData) => {
2490
2560
  const lockfile = _loadLockfile();
2491
2561
  const sectionKey = MD5(pathPattern);
2492
- const sectionChecksums = _16.mapValues(sourceData, (value) => MD5(value));
2562
+ const sectionChecksums = _17.mapValues(sourceData, (value) => MD5(value));
2493
2563
  lockfile.checksums[sectionKey] = sectionChecksums;
2494
2564
  _saveLockfile(lockfile);
2495
2565
  },
2496
2566
  registerPartialSourceData: (pathPattern, partialSourceData) => {
2497
2567
  const lockfile = _loadLockfile();
2498
2568
  const sectionKey = MD5(pathPattern);
2499
- const sectionChecksums = _16.mapValues(partialSourceData, (value) => MD5(value));
2500
- lockfile.checksums[sectionKey] = _16.merge({}, lockfile.checksums[sectionKey] ?? {}, sectionChecksums);
2569
+ const sectionChecksums = _17.mapValues(partialSourceData, (value) => MD5(value));
2570
+ lockfile.checksums[sectionKey] = _17.merge({}, lockfile.checksums[sectionKey] ?? {}, sectionChecksums);
2501
2571
  _saveLockfile(lockfile);
2502
2572
  },
2503
2573
  extractUpdatedData: (pathPattern, sourceData) => {
2504
2574
  const lockfile = _loadLockfile();
2505
2575
  const sectionKey = MD5(pathPattern);
2506
- const currentChecksums = _16.mapValues(sourceData, (value) => MD5(value));
2576
+ const currentChecksums = _17.mapValues(sourceData, (value) => MD5(value));
2507
2577
  const savedChecksums = lockfile.checksums[sectionKey] || {};
2508
- const updatedData = _16.pickBy(sourceData, (value, key) => savedChecksums[key] !== currentChecksums[key]);
2578
+ const updatedData = _17.pickBy(sourceData, (value, key) => savedChecksums[key] !== currentChecksums[key]);
2509
2579
  return updatedData;
2510
2580
  }
2511
2581
  };
@@ -2753,7 +2823,7 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
2753
2823
  targetData
2754
2824
  });
2755
2825
  if (flags.key) {
2756
- processableData = _17.pickBy(processableData, (_19, key) => key === flags.key);
2826
+ processableData = _18.pickBy(processableData, (_20, key) => key === flags.key);
2757
2827
  }
2758
2828
  if (flags.verbose) {
2759
2829
  bucketOra.info(JSON.stringify(processableData, null, 2));
@@ -2789,7 +2859,7 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
2789
2859
  if (flags.verbose) {
2790
2860
  bucketOra.info(JSON.stringify(processedTargetData, null, 2));
2791
2861
  }
2792
- let finalTargetData = _17.merge({}, sourceData, targetData, processedTargetData);
2862
+ let finalTargetData = _18.merge({}, sourceData, targetData, processedTargetData);
2793
2863
  if (flags.interactive) {
2794
2864
  bucketOra.stop();
2795
2865
  const reviewedData = await reviewChanges({
@@ -2803,7 +2873,7 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
2803
2873
  finalTargetData = reviewedData;
2804
2874
  bucketOra.start(`Applying changes to ${bucketConfig} (${targetLocale})`);
2805
2875
  }
2806
- const finalDiffSize = _17.chain(finalTargetData).omitBy((value, key) => value === targetData[key]).size().value();
2876
+ const finalDiffSize = _18.chain(finalTargetData).omitBy((value, key) => value === targetData[key]).size().value();
2807
2877
  if (finalDiffSize > 0 || flags.force) {
2808
2878
  await bucketLoader.push(targetLocale, finalTargetData);
2809
2879
  bucketOra.succeed(`[${sourceLocale} -> ${targetLocale}] Localization completed`);
@@ -2848,9 +2918,9 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
2848
2918
  }
2849
2919
  });
2850
2920
  function calculateDataDelta(args) {
2851
- const newKeys = _17.difference(Object.keys(args.sourceData), Object.keys(args.targetData));
2921
+ const newKeys = _18.difference(Object.keys(args.sourceData), Object.keys(args.targetData));
2852
2922
  const updatedKeys = Object.keys(args.updatedSourceData);
2853
- const result = _17.chain(args.sourceData).pickBy((value, key) => newKeys.includes(key) || updatedKeys.includes(key)).value();
2923
+ const result = _18.chain(args.sourceData).pickBy((value, key) => newKeys.includes(key) || updatedKeys.includes(key)).value();
2854
2924
  return result;
2855
2925
  }
2856
2926
  async function retryWithExponentialBackoff(operation, maxAttempts, baseDelay = 1e3) {
@@ -2991,7 +3061,7 @@ Reviewing changes for ${chalk.blue(args.pathPattern)} (${chalk.yellow(args.targe
2991
3061
  return args.currentData;
2992
3062
  }
2993
3063
  const customData = { ...args.currentData };
2994
- const changes = _17.reduce(
3064
+ const changes = _18.reduce(
2995
3065
  args.proposedData,
2996
3066
  (result, value, key) => {
2997
3067
  if (args.currentData[key] !== value) {
@@ -3072,7 +3142,7 @@ var flagsSchema = Z5.object({
3072
3142
  // src/cli/cmd/cleanup.ts
3073
3143
  import { resolveOverridenLocale as resolveOverridenLocale5 } from "@lingo.dev/_spec";
3074
3144
  import { Command as Command8 } from "interactive-commander";
3075
- import _18 from "lodash";
3145
+ import _19 from "lodash";
3076
3146
  import Ora7 from "ora";
3077
3147
  var cleanup_default = new Command8().command("cleanup").description("Remove keys from target files that do not exist in the source file").helpOption("-h, --help", "Show help").option("--locale <locale>", "Specific locale to cleanup").option("--bucket <bucket>", "Specific bucket to cleanup").option("--dry-run", "Show what would be removed without making changes").option("--verbose", "Show verbose output").action(async function(options) {
3078
3148
  const ora = Ora7();
@@ -3102,7 +3172,7 @@ var cleanup_default = new Command8().command("cleanup").description("Remove keys
3102
3172
  try {
3103
3173
  const targetData = await bucketLoader.pull(targetLocale);
3104
3174
  const targetKeys = Object.keys(targetData);
3105
- const keysToRemove = _18.difference(targetKeys, sourceKeys);
3175
+ const keysToRemove = _19.difference(targetKeys, sourceKeys);
3106
3176
  if (keysToRemove.length === 0) {
3107
3177
  bucketOra.succeed(`[${targetLocale}] No keys to remove`);
3108
3178
  continue;
@@ -3111,7 +3181,7 @@ var cleanup_default = new Command8().command("cleanup").description("Remove keys
3111
3181
  bucketOra.info(`[${targetLocale}] Keys to remove: ${JSON.stringify(keysToRemove, null, 2)}`);
3112
3182
  }
3113
3183
  if (!options.dryRun) {
3114
- const cleanedData = _18.pick(targetData, sourceKeys);
3184
+ const cleanedData = _19.pick(targetData, sourceKeys);
3115
3185
  await bucketLoader.push(targetLocale, cleanedData);
3116
3186
  bucketOra.succeed(`[${targetLocale}] Removed ${keysToRemove.length} keys`);
3117
3187
  } else {
@@ -3163,7 +3233,7 @@ function displaySummary(results) {
3163
3233
  // package.json
3164
3234
  var package_default = {
3165
3235
  name: "lingo.dev",
3166
- version: "0.74.12",
3236
+ version: "0.74.14",
3167
3237
  description: "Lingo.dev CLI",
3168
3238
  private: false,
3169
3239
  publishConfig: {
@@ -3200,6 +3270,7 @@ var package_default = {
3200
3270
  dev: "tsup --watch",
3201
3271
  build: "tsc --noEmit && tsup",
3202
3272
  test: "vitest run",
3273
+ "test:watch": "vitest",
3203
3274
  clean: "rm -rf build"
3204
3275
  },
3205
3276
  keywords: [],