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.cjs +131 -60
- package/build/cli.cjs.map +1 -1
- package/build/cli.mjs +192 -121
- package/build/cli.mjs.map +1 -1
- package/package.json +2 -1
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
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
|
846
|
+
import _6 from "lodash";
|
|
786
847
|
function createFlutterLoader() {
|
|
787
848
|
return createLoader({
|
|
788
849
|
async pull(locale, input) {
|
|
789
|
-
const result =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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 || "", {
|
|
913
|
-
|
|
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
|
-
|
|
986
|
+
const newRow = {
|
|
922
987
|
id: key,
|
|
923
|
-
...Object.fromEntries(columns.map((column) => [column,
|
|
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, {
|
|
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(([
|
|
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
|
|
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 =
|
|
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
|
|
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) =>
|
|
1319
|
-
isNumber: (v) => !
|
|
1320
|
-
isBoolean: (v) =>
|
|
1321
|
-
isIsoDate: (v) =>
|
|
1322
|
-
isSystemId: (v) =>
|
|
1323
|
-
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,
|
|
1335
|
-
const result =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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] =
|
|
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 =
|
|
1556
|
-
for (const [modelId, modelInfo] of
|
|
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
|
|
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 =
|
|
1562
|
-
const targetFieldValue =
|
|
1631
|
+
const sourceFieldValue = _11.get(fieldValue, [originalLocale]);
|
|
1632
|
+
const targetFieldValue = _11.get(data, [modelId, record.id, fieldId]);
|
|
1563
1633
|
if (targetFieldValue) {
|
|
1564
|
-
|
|
1634
|
+
_11.set(record, [fieldId, locale], targetFieldValue);
|
|
1565
1635
|
} else {
|
|
1566
|
-
|
|
1636
|
+
_11.set(record, [fieldId, locale], sourceFieldValue);
|
|
1567
1637
|
}
|
|
1568
|
-
|
|
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
|
|
1649
|
+
import _13 from "lodash";
|
|
1580
1650
|
|
|
1581
1651
|
// src/cli/loaders/dato/_utils.ts
|
|
1582
|
-
import
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
1918
|
-
for (const [recordId, record] of
|
|
1919
|
-
for (const [fieldName, fieldValue] of
|
|
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
|
-
|
|
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 =
|
|
1931
|
-
for (const [modelId, modelInfo] of
|
|
1932
|
-
for (const [virtualRecordId, record] of
|
|
1933
|
-
for (const [fieldName, fieldValue] of
|
|
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 =
|
|
2005
|
+
const originalFieldValue = _14.get(originalInput, [modelId, recordId, fieldName]);
|
|
1936
2006
|
const rawValue = createRawDatoValue(fieldValue, originalFieldValue, true);
|
|
1937
|
-
|
|
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 (
|
|
2016
|
+
if (_14.has(rawDatoValue, "document") && _14.get(rawDatoValue, "schema") === "dast") {
|
|
1947
2017
|
return "structured_text";
|
|
1948
|
-
} else if (
|
|
2018
|
+
} else if (_14.has(rawDatoValue, "no_index") || _14.has(rawDatoValue, "twitter_card")) {
|
|
1949
2019
|
return "seo";
|
|
1950
|
-
} else if (
|
|
2020
|
+
} else if (_14.get(rawDatoValue, "type") === "item") {
|
|
1951
2021
|
return "single_block";
|
|
1952
|
-
} else if (
|
|
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 (
|
|
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 (
|
|
2030
|
+
} else if (_14.isString(rawDatoValue)) {
|
|
1961
2031
|
return "string";
|
|
1962
2032
|
} else if (_isVideo(rawDatoValue)) {
|
|
1963
2033
|
return "video";
|
|
1964
|
-
} else if (
|
|
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 (!
|
|
2096
|
+
if (!_14.isNil(node.value)) {
|
|
2027
2097
|
acc[[...path9, "value"].join(".")] = node.value;
|
|
2028
|
-
} else if (
|
|
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
|
|
2110
|
+
return _14.chain(rawSeo).pick(["title", "description"]).value();
|
|
2041
2111
|
}
|
|
2042
2112
|
function serializeBlock(rawBlock) {
|
|
2043
|
-
if (
|
|
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
|
|
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
|
|
2123
|
+
return _14.chain(rawBlockList).map((block) => serializeBlock(block)).value();
|
|
2054
2124
|
}
|
|
2055
2125
|
function serializeVideo(rawVideo) {
|
|
2056
|
-
return
|
|
2126
|
+
return _14.chain(rawVideo).pick(["title"]).value();
|
|
2057
2127
|
}
|
|
2058
2128
|
function serializeFile(rawFile) {
|
|
2059
|
-
return
|
|
2129
|
+
return _14.chain(rawFile).pick(["alt", "title"]).value();
|
|
2060
2130
|
}
|
|
2061
2131
|
function serializeGallery(rawGallery) {
|
|
2062
|
-
return
|
|
2132
|
+
return _14.chain(rawGallery).map((item) => serializeFile(item)).value();
|
|
2063
2133
|
}
|
|
2064
2134
|
function deserializeFile(parsedFile, originalRawFile) {
|
|
2065
|
-
return
|
|
2135
|
+
return _14.chain(parsedFile).defaults(originalRawFile).value();
|
|
2066
2136
|
}
|
|
2067
2137
|
function deserializeGallery(parsedGallery, originalRawGallery) {
|
|
2068
|
-
return
|
|
2138
|
+
return _14.chain(parsedGallery).map((item, i) => deserializeFile(item, originalRawGallery[i])).value();
|
|
2069
2139
|
}
|
|
2070
2140
|
function deserializeVideo(parsedVideo, originalRawVideo) {
|
|
2071
|
-
return
|
|
2141
|
+
return _14.chain(parsedVideo).defaults(originalRawVideo).value();
|
|
2072
2142
|
}
|
|
2073
2143
|
function deserializeBlock(payload, rawNode, isClean = false) {
|
|
2074
|
-
const result =
|
|
2075
|
-
for (const [attributeName, attributeValue] of
|
|
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
|
-
|
|
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
|
|
2155
|
+
return _14.chain(parsedSeo).pick(["title", "description"]).defaults(originalRawSeo).value();
|
|
2086
2156
|
}
|
|
2087
2157
|
function deserializeBlockList(parsedBlockList, originalRawBlockList, isClean = false) {
|
|
2088
|
-
return
|
|
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 =
|
|
2092
|
-
for (const [path9, value] of
|
|
2093
|
-
const realPath =
|
|
2094
|
-
const deserializedValue = createRawDatoValue(value,
|
|
2095
|
-
|
|
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
|
|
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
|
|
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
|
|
2111
|
-
(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
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
2500
|
-
lockfile.checksums[sectionKey] =
|
|
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 =
|
|
2576
|
+
const currentChecksums = _17.mapValues(sourceData, (value) => MD5(value));
|
|
2507
2577
|
const savedChecksums = lockfile.checksums[sectionKey] || {};
|
|
2508
|
-
const updatedData =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
2921
|
+
const newKeys = _18.difference(Object.keys(args.sourceData), Object.keys(args.targetData));
|
|
2852
2922
|
const updatedKeys = Object.keys(args.updatedSourceData);
|
|
2853
|
-
const result =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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.
|
|
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: [],
|