lingo.dev 0.78.0 → 0.78.2
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 +105 -59
- package/build/cli.cjs.map +1 -1
- package/build/cli.mjs +82 -36
- package/build/cli.mjs.map +1 -1
- package/package.json +3 -3
package/build/cli.cjs
CHANGED
|
@@ -297,7 +297,7 @@ function findLocaleFiles(bucket) {
|
|
|
297
297
|
case "xcode-stringsdict":
|
|
298
298
|
return findLocaleFilesForFilename("Localizable.stringsdict");
|
|
299
299
|
default:
|
|
300
|
-
|
|
300
|
+
return null;
|
|
301
301
|
}
|
|
302
302
|
}
|
|
303
303
|
function findLocaleFilesWithExtension(ext) {
|
|
@@ -681,38 +681,50 @@ var init_default = new (0, _interactivecommander.InteractiveCommand)().command("
|
|
|
681
681
|
};
|
|
682
682
|
} else {
|
|
683
683
|
let selectedPatterns = [];
|
|
684
|
-
const
|
|
685
|
-
if (
|
|
686
|
-
spinner.
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
684
|
+
const localeFiles = findLocaleFiles(options.bucket);
|
|
685
|
+
if (!localeFiles) {
|
|
686
|
+
spinner.warn(
|
|
687
|
+
`Bucket type "${options.bucket}" does not supported automatic initialization. Add paths to "i18n.json" manually.`
|
|
688
|
+
);
|
|
689
|
+
newConfig.buckets = {
|
|
690
|
+
[options.bucket]: {
|
|
691
|
+
include: options.paths || []
|
|
692
|
+
}
|
|
693
|
+
};
|
|
693
694
|
} else {
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
695
|
+
const { patterns, defaultPatterns } = localeFiles;
|
|
696
|
+
if (patterns.length > 0) {
|
|
697
|
+
spinner.succeed("Found existing locale files:");
|
|
698
|
+
selectedPatterns = await _prompts.checkbox.call(void 0, {
|
|
699
|
+
message: "Select the paths to use",
|
|
700
|
+
choices: patterns.map((value) => ({
|
|
701
|
+
value
|
|
702
|
+
}))
|
|
703
|
+
});
|
|
704
|
+
} else {
|
|
705
|
+
spinner.succeed("No existing locale files found.");
|
|
703
706
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
[options.bucket]: {
|
|
713
|
-
include: selectedPatterns || []
|
|
707
|
+
if (selectedPatterns.length === 0) {
|
|
708
|
+
const useDefault = await _prompts.confirm.call(void 0, {
|
|
709
|
+
message: `Use (and create) default path ${defaultPatterns.join(", ")}?`
|
|
710
|
+
});
|
|
711
|
+
if (useDefault) {
|
|
712
|
+
ensurePatterns(defaultPatterns, options.source);
|
|
713
|
+
selectedPatterns = defaultPatterns;
|
|
714
|
+
}
|
|
714
715
|
}
|
|
715
|
-
|
|
716
|
+
if (selectedPatterns.length === 0) {
|
|
717
|
+
const customPaths = await _prompts.input.call(void 0, {
|
|
718
|
+
message: "Enter paths to use"
|
|
719
|
+
});
|
|
720
|
+
selectedPatterns = customPaths.includes(",") ? customPaths.split(",") : customPaths.split(" ");
|
|
721
|
+
}
|
|
722
|
+
newConfig.buckets = {
|
|
723
|
+
[options.bucket]: {
|
|
724
|
+
include: selectedPatterns || []
|
|
725
|
+
}
|
|
726
|
+
};
|
|
727
|
+
}
|
|
716
728
|
}
|
|
717
729
|
await saveConfig(newConfig);
|
|
718
730
|
spinner.succeed("Lingo.dev project initialized");
|
|
@@ -1691,12 +1703,10 @@ function createXcodeXcstringsLoader(defaultLocale) {
|
|
|
1691
1703
|
}
|
|
1692
1704
|
}
|
|
1693
1705
|
} else if (isSourceLanguage) {
|
|
1694
|
-
|
|
1695
|
-
if (hasOtherLocalizations) {
|
|
1696
|
-
resultData[translationKey] = translationKey;
|
|
1697
|
-
}
|
|
1706
|
+
resultData[translationKey] = translationKey;
|
|
1698
1707
|
}
|
|
1699
1708
|
}
|
|
1709
|
+
console.log(resultData);
|
|
1700
1710
|
return resultData;
|
|
1701
1711
|
},
|
|
1702
1712
|
async push(locale, payload, originalInput) {
|
|
@@ -1710,7 +1720,7 @@ function createXcodeXcstringsLoader(defaultLocale) {
|
|
|
1710
1720
|
const hasDoNotTranslateFlag = originalInput && originalInput.strings && originalInput.strings[key] && originalInput.strings[key].shouldTranslate === false;
|
|
1711
1721
|
if (typeof value === "string") {
|
|
1712
1722
|
langDataToMerge.strings[key] = {
|
|
1713
|
-
extractionState:
|
|
1723
|
+
extractionState: _optionalChain([originalInput, 'optionalAccess', _70 => _70.strings, 'optionalAccess', _71 => _71[key], 'optionalAccess', _72 => _72.extractionState]),
|
|
1714
1724
|
localizations: {
|
|
1715
1725
|
[locale]: {
|
|
1716
1726
|
stringUnit: {
|
|
@@ -1850,7 +1860,7 @@ function createPoDataLoader(params) {
|
|
|
1850
1860
|
Object.entries(entries).forEach(([msgid, entry]) => {
|
|
1851
1861
|
if (msgid && entry.msgid) {
|
|
1852
1862
|
const context = entry.msgctxt || "";
|
|
1853
|
-
const fullEntry = _optionalChain([parsedPo, 'access',
|
|
1863
|
+
const fullEntry = _optionalChain([parsedPo, 'access', _73 => _73.translations, 'access', _74 => _74[context], 'optionalAccess', _75 => _75[msgid]]);
|
|
1854
1864
|
if (fullEntry) {
|
|
1855
1865
|
result[msgid] = fullEntry;
|
|
1856
1866
|
}
|
|
@@ -1860,7 +1870,7 @@ function createPoDataLoader(params) {
|
|
|
1860
1870
|
return result;
|
|
1861
1871
|
},
|
|
1862
1872
|
async push(locale, data, originalInput) {
|
|
1863
|
-
const sections = _optionalChain([originalInput, 'optionalAccess',
|
|
1873
|
+
const sections = _optionalChain([originalInput, 'optionalAccess', _76 => _76.split, 'call', _77 => _77("\n\n"), 'access', _78 => _78.filter, 'call', _79 => _79(Boolean)]) || [];
|
|
1864
1874
|
const result = sections.map((section) => {
|
|
1865
1875
|
const sectionPo = _gettextparser2.default.po.parse(section);
|
|
1866
1876
|
const contextKey = _lodash2.default.keys(sectionPo.translations)[0];
|
|
@@ -1902,7 +1912,7 @@ function createPoContentLoader() {
|
|
|
1902
1912
|
entry.msgid,
|
|
1903
1913
|
{
|
|
1904
1914
|
...entry,
|
|
1905
|
-
msgstr: [_optionalChain([data, 'access',
|
|
1915
|
+
msgstr: [_optionalChain([data, 'access', _80 => _80[entry.msgid], 'optionalAccess', _81 => _81.singular]), _optionalChain([data, 'access', _82 => _82[entry.msgid], 'optionalAccess', _83 => _83.plural]) || null].filter(Boolean)
|
|
1906
1916
|
}
|
|
1907
1917
|
]).fromPairs().value();
|
|
1908
1918
|
return result;
|
|
@@ -2148,7 +2158,7 @@ function createDatoClient(params) {
|
|
|
2148
2158
|
only_valid: "true",
|
|
2149
2159
|
ids: !records.length ? void 0 : records.join(",")
|
|
2150
2160
|
}
|
|
2151
|
-
}).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess',
|
|
2161
|
+
}).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _84 => _84.response, 'optionalAccess', _85 => _85.body, 'optionalAccess', _86 => _86.data, 'optionalAccess', _87 => _87[0]]) || error));
|
|
2152
2162
|
},
|
|
2153
2163
|
findRecordsForModel: async (modelId, records) => {
|
|
2154
2164
|
try {
|
|
@@ -2158,9 +2168,9 @@ function createDatoClient(params) {
|
|
|
2158
2168
|
filter: {
|
|
2159
2169
|
type: modelId,
|
|
2160
2170
|
only_valid: "true",
|
|
2161
|
-
ids: !_optionalChain([records, 'optionalAccess',
|
|
2171
|
+
ids: !_optionalChain([records, 'optionalAccess', _88 => _88.length]) ? void 0 : records.join(",")
|
|
2162
2172
|
}
|
|
2163
|
-
}).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess',
|
|
2173
|
+
}).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _89 => _89.response, 'optionalAccess', _90 => _90.body, 'optionalAccess', _91 => _91.data, 'optionalAccess', _92 => _92[0]]) || error));
|
|
2164
2174
|
return result;
|
|
2165
2175
|
} catch (_error) {
|
|
2166
2176
|
throw new Error(
|
|
@@ -2174,9 +2184,9 @@ function createDatoClient(params) {
|
|
|
2174
2184
|
},
|
|
2175
2185
|
updateRecord: async (id, payload) => {
|
|
2176
2186
|
try {
|
|
2177
|
-
await dato.items.update(id, payload).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess',
|
|
2187
|
+
await dato.items.update(id, payload).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _93 => _93.response, 'optionalAccess', _94 => _94.body, 'optionalAccess', _95 => _95.data, 'optionalAccess', _96 => _96[0]]) || error));
|
|
2178
2188
|
} catch (_error) {
|
|
2179
|
-
if (_optionalChain([_error, 'optionalAccess',
|
|
2189
|
+
if (_optionalChain([_error, 'optionalAccess', _97 => _97.attributes, 'optionalAccess', _98 => _98.details, 'optionalAccess', _99 => _99.message])) {
|
|
2180
2190
|
throw new Error(
|
|
2181
2191
|
[
|
|
2182
2192
|
`${_error.attributes.details.message}`,
|
|
@@ -2197,9 +2207,9 @@ function createDatoClient(params) {
|
|
|
2197
2207
|
},
|
|
2198
2208
|
enableFieldLocalization: async (args) => {
|
|
2199
2209
|
try {
|
|
2200
|
-
await dato.fields.update(`${args.modelId}::${args.fieldId}`, { localized: true }).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess',
|
|
2210
|
+
await dato.fields.update(`${args.modelId}::${args.fieldId}`, { localized: true }).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _100 => _100.response, 'optionalAccess', _101 => _101.body, 'optionalAccess', _102 => _102.data, 'optionalAccess', _103 => _103[0]]) || error));
|
|
2201
2211
|
} catch (_error) {
|
|
2202
|
-
if (_optionalChain([_error, 'optionalAccess',
|
|
2212
|
+
if (_optionalChain([_error, 'optionalAccess', _104 => _104.attributes, 'optionalAccess', _105 => _105.code]) === "NOT_FOUND") {
|
|
2203
2213
|
throw new Error(
|
|
2204
2214
|
[
|
|
2205
2215
|
`Field "${args.fieldId}" not found in model "${args.modelId}".`,
|
|
@@ -2207,7 +2217,7 @@ function createDatoClient(params) {
|
|
|
2207
2217
|
].join("\n\n")
|
|
2208
2218
|
);
|
|
2209
2219
|
}
|
|
2210
|
-
if (_optionalChain([_error, 'optionalAccess',
|
|
2220
|
+
if (_optionalChain([_error, 'optionalAccess', _106 => _106.attributes, 'optionalAccess', _107 => _107.details, 'optionalAccess', _108 => _108.message])) {
|
|
2211
2221
|
throw new Error(
|
|
2212
2222
|
[`${_error.attributes.details.message}`, `Error: ${JSON.stringify(_error, null, 2)}`].join("\n\n")
|
|
2213
2223
|
);
|
|
@@ -2273,7 +2283,7 @@ function createDatoApiLoader(config, onConfigUpdate) {
|
|
|
2273
2283
|
}
|
|
2274
2284
|
}
|
|
2275
2285
|
const records = await dato.findRecordsForModel(modelId);
|
|
2276
|
-
const recordChoices = createRecordChoices(records, _optionalChain([config, 'access',
|
|
2286
|
+
const recordChoices = createRecordChoices(records, _optionalChain([config, 'access', _109 => _109.models, 'access', _110 => _110[modelId], 'optionalAccess', _111 => _111.records]) || [], project);
|
|
2277
2287
|
const selectedRecords = await promptRecordSelection(modelName, recordChoices);
|
|
2278
2288
|
result.models[modelId].records = records.filter((record) => selectedRecords.includes(record.id));
|
|
2279
2289
|
updatedConfig.models[modelId].records = selectedRecords;
|
|
@@ -2285,14 +2295,14 @@ function createDatoApiLoader(config, onConfigUpdate) {
|
|
|
2285
2295
|
},
|
|
2286
2296
|
async pull(locale, input2, initCtx) {
|
|
2287
2297
|
const result = {};
|
|
2288
|
-
for (const modelId of _lodash2.default.keys(_optionalChain([initCtx, 'optionalAccess',
|
|
2289
|
-
let records = _optionalChain([initCtx, 'optionalAccess',
|
|
2298
|
+
for (const modelId of _lodash2.default.keys(_optionalChain([initCtx, 'optionalAccess', _112 => _112.models]) || {})) {
|
|
2299
|
+
let records = _optionalChain([initCtx, 'optionalAccess', _113 => _113.models, 'access', _114 => _114[modelId], 'access', _115 => _115.records]) || [];
|
|
2290
2300
|
const recordIds = records.map((record) => record.id);
|
|
2291
2301
|
records = await dato.findRecords(recordIds);
|
|
2292
2302
|
console.log(`Fetched ${records.length} records for model ${modelId}`);
|
|
2293
2303
|
if (records.length > 0) {
|
|
2294
2304
|
result[modelId] = {
|
|
2295
|
-
fields: _optionalChain([initCtx, 'optionalAccess',
|
|
2305
|
+
fields: _optionalChain([initCtx, 'optionalAccess', _116 => _116.models, 'optionalAccess', _117 => _117[modelId], 'optionalAccess', _118 => _118.fields]) || [],
|
|
2296
2306
|
records
|
|
2297
2307
|
};
|
|
2298
2308
|
}
|
|
@@ -2351,7 +2361,7 @@ function createRecordChoices(records, selectedIds = [], project) {
|
|
|
2351
2361
|
return records.map((record) => ({
|
|
2352
2362
|
name: `${record.id} - https://${project.internal_domain}/editor/item_types/${record.item_type.id}/items/${record.id}`,
|
|
2353
2363
|
value: record.id,
|
|
2354
|
-
checked: _optionalChain([selectedIds, 'optionalAccess',
|
|
2364
|
+
checked: _optionalChain([selectedIds, 'optionalAccess', _119 => _119.includes, 'call', _120 => _120(record.id)])
|
|
2355
2365
|
}));
|
|
2356
2366
|
}
|
|
2357
2367
|
async function promptRecordSelection(modelName, choices) {
|
|
@@ -2618,7 +2628,7 @@ var _nodewebvtt = require('node-webvtt'); var _nodewebvtt2 = _interopRequireDefa
|
|
|
2618
2628
|
function createVttLoader() {
|
|
2619
2629
|
return createLoader({
|
|
2620
2630
|
async pull(locale, input2) {
|
|
2621
|
-
const vtt = _optionalChain([_nodewebvtt2.default, 'access',
|
|
2631
|
+
const vtt = _optionalChain([_nodewebvtt2.default, 'access', _121 => _121.parse, 'call', _122 => _122(input2), 'optionalAccess', _123 => _123.cues]);
|
|
2622
2632
|
if (Object.keys(vtt).length === 0) {
|
|
2623
2633
|
return {};
|
|
2624
2634
|
} else {
|
|
@@ -2670,7 +2680,7 @@ function variableExtractLoader(params) {
|
|
|
2670
2680
|
for (let i = 0; i < matches.length; i++) {
|
|
2671
2681
|
const match = matches[i];
|
|
2672
2682
|
const currentValue = result[key].value;
|
|
2673
|
-
const newValue = _optionalChain([currentValue, 'optionalAccess',
|
|
2683
|
+
const newValue = _optionalChain([currentValue, 'optionalAccess', _124 => _124.replace, 'call', _125 => _125(match, `{variable:${i}}`)]);
|
|
2674
2684
|
result[key].value = newValue;
|
|
2675
2685
|
result[key].variables[i] = match;
|
|
2676
2686
|
}
|
|
@@ -2684,7 +2694,7 @@ function variableExtractLoader(params) {
|
|
|
2684
2694
|
for (let i = 0; i < valueObj.variables.length; i++) {
|
|
2685
2695
|
const variable = valueObj.variables[i];
|
|
2686
2696
|
const currentValue = result[key];
|
|
2687
|
-
const newValue = _optionalChain([currentValue, 'optionalAccess',
|
|
2697
|
+
const newValue = _optionalChain([currentValue, 'optionalAccess', _126 => _126.replace, 'call', _127 => _127(`{variable:${i}}`, variable)]);
|
|
2688
2698
|
result[key] = newValue;
|
|
2689
2699
|
}
|
|
2690
2700
|
}
|
|
@@ -2859,6 +2869,34 @@ function escapePhpString(str) {
|
|
|
2859
2869
|
return str.replaceAll("\\", "\\\\").replaceAll("'", "\\'").replaceAll("\r", "\\r").replaceAll("\n", "\\n").replaceAll(" ", "\\t");
|
|
2860
2870
|
}
|
|
2861
2871
|
|
|
2872
|
+
// src/cli/loaders/vue-json.ts
|
|
2873
|
+
|
|
2874
|
+
function createVueJsonLoader() {
|
|
2875
|
+
return createLoader({
|
|
2876
|
+
pull: async (locale, input2, ctx) => {
|
|
2877
|
+
const { i18n } = parseVueFile(input2);
|
|
2878
|
+
return _nullishCoalesce(i18n[locale], () => ( {}));
|
|
2879
|
+
},
|
|
2880
|
+
push: async (locale, data, originalInput) => {
|
|
2881
|
+
const { before, i18n, after } = parseVueFile(_nullishCoalesce(originalInput, () => ( "")));
|
|
2882
|
+
i18n[locale] = data;
|
|
2883
|
+
return `${before}<i18n>
|
|
2884
|
+
${JSON.stringify(i18n, null, 2)}
|
|
2885
|
+
</i18n>${after}`;
|
|
2886
|
+
}
|
|
2887
|
+
});
|
|
2888
|
+
}
|
|
2889
|
+
function parseVueFile(input2) {
|
|
2890
|
+
const [, before, jsonString = "{}", after] = input2.match(/^([\s\S]*)<i18n>([\s\S]*)<\/i18n>([\s\S]*)$/) || [];
|
|
2891
|
+
let i18n;
|
|
2892
|
+
try {
|
|
2893
|
+
i18n = JSON.parse(jsonString);
|
|
2894
|
+
} catch (error) {
|
|
2895
|
+
i18n = JSON.parse(_jsonrepair.jsonrepair.call(void 0, jsonString));
|
|
2896
|
+
}
|
|
2897
|
+
return { before, after, i18n };
|
|
2898
|
+
}
|
|
2899
|
+
|
|
2862
2900
|
// src/cli/loaders/index.ts
|
|
2863
2901
|
function createBucketLoader(bucketType, bucketPathPattern, options) {
|
|
2864
2902
|
switch (bucketType) {
|
|
@@ -3021,6 +3059,14 @@ function createBucketLoader(bucketType, bucketPathPattern, options) {
|
|
|
3021
3059
|
createFlatLoader(),
|
|
3022
3060
|
createUnlocalizableLoader(options.isCacheRestore)
|
|
3023
3061
|
);
|
|
3062
|
+
case "vue-json":
|
|
3063
|
+
return composeLoaders(
|
|
3064
|
+
createTextFileLoader(bucketPathPattern),
|
|
3065
|
+
createVueJsonLoader(),
|
|
3066
|
+
createSyncLoader(),
|
|
3067
|
+
createFlatLoader(),
|
|
3068
|
+
createUnlocalizableLoader()
|
|
3069
|
+
);
|
|
3024
3070
|
}
|
|
3025
3071
|
}
|
|
3026
3072
|
|
|
@@ -3193,11 +3239,11 @@ var i18n_default = new (0, _interactivecommander.Command)().command("i18n").desc
|
|
|
3193
3239
|
const auth = await validateAuth(settings);
|
|
3194
3240
|
ora.succeed(`Authenticated as ${auth.email}`);
|
|
3195
3241
|
let buckets = getBuckets(i18nConfig);
|
|
3196
|
-
if (_optionalChain([flags, 'access',
|
|
3242
|
+
if (_optionalChain([flags, 'access', _128 => _128.bucket, 'optionalAccess', _129 => _129.length])) {
|
|
3197
3243
|
buckets = buckets.filter((bucket) => flags.bucket.includes(bucket.type));
|
|
3198
3244
|
}
|
|
3199
3245
|
ora.succeed("Buckets retrieved");
|
|
3200
|
-
const targetLocales = _optionalChain([flags, 'access',
|
|
3246
|
+
const targetLocales = _optionalChain([flags, 'access', _130 => _130.locale, 'optionalAccess', _131 => _131.length]) ? flags.locale : i18nConfig.locale.targets;
|
|
3201
3247
|
const lockfileHelper = createLockfileHelper();
|
|
3202
3248
|
ora.start("Ensuring i18n.lock exists...");
|
|
3203
3249
|
if (!lockfileHelper.isLockfileExists()) {
|
|
@@ -3499,12 +3545,12 @@ function validateParams(i18nConfig, flags) {
|
|
|
3499
3545
|
message: "No buckets found in i18n.json. Please add at least one bucket containing i18n content.",
|
|
3500
3546
|
docUrl: "bucketNotFound"
|
|
3501
3547
|
});
|
|
3502
|
-
} else if (_optionalChain([flags, 'access',
|
|
3548
|
+
} else if (_optionalChain([flags, 'access', _132 => _132.locale, 'optionalAccess', _133 => _133.some, 'call', _134 => _134((locale) => !i18nConfig.locale.targets.includes(locale))])) {
|
|
3503
3549
|
throw new CLIError({
|
|
3504
3550
|
message: `One or more specified locales do not exist in i18n.json locale.targets. Please add them to the list and try again.`,
|
|
3505
3551
|
docUrl: "localeTargetNotFound"
|
|
3506
3552
|
});
|
|
3507
|
-
} else if (_optionalChain([flags, 'access',
|
|
3553
|
+
} else if (_optionalChain([flags, 'access', _135 => _135.bucket, 'optionalAccess', _136 => _136.some, 'call', _137 => _137((bucket) => !i18nConfig.buckets[bucket])])) {
|
|
3508
3554
|
throw new CLIError({
|
|
3509
3555
|
message: `One or more specified buckets do not exist in i18n.json. Please add them to the list and try again.`,
|
|
3510
3556
|
docUrl: "bucketNotFound"
|
|
@@ -3784,7 +3830,7 @@ var mcp_default = new (0, _interactivecommander.Command)().command("mcp").descri
|
|
|
3784
3830
|
// package.json
|
|
3785
3831
|
var package_default = {
|
|
3786
3832
|
name: "lingo.dev",
|
|
3787
|
-
version: "0.78.
|
|
3833
|
+
version: "0.78.2",
|
|
3788
3834
|
description: "Lingo.dev CLI",
|
|
3789
3835
|
private: false,
|
|
3790
3836
|
publishConfig: {
|