@lang-tag/cli 0.14.0 → 0.16.0
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/algorithms/case-utils.d.ts +12 -0
- package/algorithms/collector/dictionary-collector.d.ts +17 -0
- package/algorithms/collector/index.d.ts +10 -0
- package/algorithms/collector/namespace-collector.d.ts +12 -0
- package/algorithms/collector/type.d.ts +12 -0
- package/algorithms/config-generation/index.d.ts +1 -0
- package/algorithms/config-generation/path-based-config-generator.d.ts +3 -2
- package/algorithms/config-generation/prepend-namespace-to-path.d.ts +28 -0
- package/algorithms/import/flexible-import-algorithm.d.ts +232 -0
- package/algorithms/import/index.d.ts +2 -1
- package/algorithms/import/simple-mapping-import-algorithm.d.ts +120 -0
- package/algorithms/index.cjs +161 -28
- package/algorithms/index.d.ts +9 -3
- package/algorithms/index.js +177 -26
- package/config.d.ts +95 -75
- package/flexible-import-algorithm-C-S1c742.js +311 -0
- package/flexible-import-algorithm-Fa-l4jWj.cjs +327 -0
- package/index.cjs +236 -203
- package/index.js +233 -200
- package/package.json +1 -1
- package/templates/config/init-config.mustache +1 -0
- package/templates/import/imported-tag.mustache +14 -0
- /package/{template → templates/tag}/base-app.mustache +0 -0
- /package/{template → templates/tag}/base-library.mustache +0 -0
- /package/{template → templates/tag}/placeholder.mustache +0 -0
package/index.js
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { program } from "commander";
|
|
3
3
|
import fs, { readFileSync, existsSync } from "fs";
|
|
4
|
-
import { writeFile,
|
|
4
|
+
import { writeFile, readFile } from "fs/promises";
|
|
5
5
|
import JSON5 from "json5";
|
|
6
6
|
import * as path from "path";
|
|
7
|
-
import path__default, { sep,
|
|
7
|
+
import path__default, { sep, join, dirname } from "path";
|
|
8
8
|
import { globby } from "globby";
|
|
9
|
-
import path$1, { resolve
|
|
9
|
+
import path$1, { resolve } from "pathe";
|
|
10
10
|
import { pathToFileURL, fileURLToPath } from "url";
|
|
11
|
+
import "case";
|
|
11
12
|
import * as process$1 from "node:process";
|
|
12
13
|
import process__default from "node:process";
|
|
14
|
+
import { f as flexibleImportAlgorithm, N as NamespaceCollector, $ as $LT_ReadFileContent, a as $LT_ReadJSON, b as $LT_WriteJSON, c as $LT_EnsureDirectoryExists, d as $LT_WriteFileWithDirs } from "./flexible-import-algorithm-C-S1c742.js";
|
|
13
15
|
import * as acorn from "acorn";
|
|
14
16
|
import micromatch from "micromatch";
|
|
15
17
|
import chokidar from "chokidar";
|
|
@@ -478,13 +480,16 @@ function isConfigSame(c1, c2) {
|
|
|
478
480
|
return false;
|
|
479
481
|
}
|
|
480
482
|
const CONFIG_FILE_NAME = ".lang-tag.config.js";
|
|
481
|
-
const EXPORTS_FILE_NAME = "
|
|
483
|
+
const EXPORTS_FILE_NAME = "lang-tags.json";
|
|
482
484
|
const LANG_TAG_DEFAULT_CONFIG = {
|
|
483
485
|
tagName: "lang",
|
|
486
|
+
isLibrary: false,
|
|
484
487
|
includes: ["src/**/*.{js,ts,jsx,tsx}"],
|
|
485
488
|
excludes: ["node_modules", "dist", "build"],
|
|
486
|
-
|
|
489
|
+
localesDirectory: "locales",
|
|
490
|
+
baseLanguageCode: "en",
|
|
487
491
|
collect: {
|
|
492
|
+
collector: new NamespaceCollector(),
|
|
488
493
|
defaultNamespace: "common",
|
|
489
494
|
ignoreConflictsWithMatchingValues: true,
|
|
490
495
|
onCollectConfigFix: ({ config, langTagConfig }) => {
|
|
@@ -504,15 +509,19 @@ const LANG_TAG_DEFAULT_CONFIG = {
|
|
|
504
509
|
import: {
|
|
505
510
|
dir: "src/lang-libraries",
|
|
506
511
|
tagImportPath: 'import { lang } from "@/my-lang-tag-path"',
|
|
507
|
-
onImport: ({
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
}
|
|
512
|
+
onImport: flexibleImportAlgorithm({
|
|
513
|
+
filePath: {
|
|
514
|
+
includePackageInPath: true
|
|
515
|
+
}
|
|
516
|
+
})
|
|
517
|
+
// onImport: ({importedRelativePath, fileGenerationData}: LangTagCLIOnImportParams, actions)=> {
|
|
518
|
+
// const exportIndex = (fileGenerationData.index || 0) + 1;
|
|
519
|
+
// fileGenerationData.index = exportIndex;
|
|
520
|
+
//
|
|
521
|
+
// actions.setFile(path.basename(importedRelativePath));
|
|
522
|
+
// actions.setExportName(`translations${exportIndex}`);
|
|
523
|
+
// }
|
|
513
524
|
},
|
|
514
|
-
isLibrary: false,
|
|
515
|
-
language: "en",
|
|
516
525
|
translationArgPosition: 1,
|
|
517
526
|
onConfigGeneration: async (event) => {
|
|
518
527
|
}
|
|
@@ -532,7 +541,7 @@ async function $LT_ReadConfig(projectPath) {
|
|
|
532
541
|
if (tn === "langtag" || tn === "lang-tag") {
|
|
533
542
|
throw new Error('Custom tagName cannot be "lang-tag" or "langtag"! (It is not recommended for use with libraries)\n');
|
|
534
543
|
}
|
|
535
|
-
|
|
544
|
+
const config = {
|
|
536
545
|
...LANG_TAG_DEFAULT_CONFIG,
|
|
537
546
|
...userConfig,
|
|
538
547
|
import: {
|
|
@@ -544,39 +553,14 @@ async function $LT_ReadConfig(projectPath) {
|
|
|
544
553
|
...userConfig.collect
|
|
545
554
|
}
|
|
546
555
|
};
|
|
556
|
+
if (!config.collect.collector) {
|
|
557
|
+
throw new Error("Collector not found! (config.collect.collector)");
|
|
558
|
+
}
|
|
559
|
+
return config;
|
|
547
560
|
} catch (error) {
|
|
548
561
|
throw error;
|
|
549
562
|
}
|
|
550
563
|
}
|
|
551
|
-
async function $LT_EnsureDirectoryExists(filePath) {
|
|
552
|
-
await mkdir(filePath, { recursive: true });
|
|
553
|
-
}
|
|
554
|
-
async function $LT_RemoveDirectory(dirPath) {
|
|
555
|
-
try {
|
|
556
|
-
await rm(dirPath, { recursive: true, force: true });
|
|
557
|
-
} catch (error) {
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
async function $LT_WriteJSON(filePath, data) {
|
|
561
|
-
await writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
562
|
-
}
|
|
563
|
-
async function $LT_ReadJSON(filePath) {
|
|
564
|
-
const content = await readFile(filePath, "utf-8");
|
|
565
|
-
return JSON.parse(content);
|
|
566
|
-
}
|
|
567
|
-
async function $LT_WriteFileWithDirs(filePath, content) {
|
|
568
|
-
const dir = dirname(filePath);
|
|
569
|
-
try {
|
|
570
|
-
await mkdir(dir, { recursive: true });
|
|
571
|
-
} catch (error) {
|
|
572
|
-
}
|
|
573
|
-
await writeFile(filePath, content, "utf-8");
|
|
574
|
-
}
|
|
575
|
-
async function $LT_ReadFileContent(relativeFilePath) {
|
|
576
|
-
const cwd = process.cwd();
|
|
577
|
-
const absolutePath = resolve$1(cwd, relativeFilePath);
|
|
578
|
-
return await readFile(absolutePath, "utf-8");
|
|
579
|
-
}
|
|
580
564
|
function parseObjectAST(code) {
|
|
581
565
|
const nodes = [];
|
|
582
566
|
try {
|
|
@@ -978,6 +962,8 @@ function $LT_CreateDefaultLogger(debugMode, translationArgPosition = 1) {
|
|
|
978
962
|
async function $LT_GetCommandEssentials() {
|
|
979
963
|
const config = await $LT_ReadConfig(process__default.cwd());
|
|
980
964
|
const logger = $LT_CreateDefaultLogger(config.debug, config.translationArgPosition);
|
|
965
|
+
config.collect.collector.config = config;
|
|
966
|
+
config.collect.collector.logger = logger;
|
|
981
967
|
return {
|
|
982
968
|
config,
|
|
983
969
|
logger
|
|
@@ -1040,36 +1026,26 @@ function deepMergeTranslations(target, source) {
|
|
|
1040
1026
|
}
|
|
1041
1027
|
return changed;
|
|
1042
1028
|
}
|
|
1043
|
-
async function $
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
}
|
|
1049
|
-
await $LT_EnsureDirectoryExists(config.outputDir);
|
|
1050
|
-
for (let namespace of Object.keys(namespaces)) {
|
|
1051
|
-
if (!namespace) {
|
|
1029
|
+
async function $LT_WriteToCollections({ config, collections, logger, clean }) {
|
|
1030
|
+
await config.collect.collector.preWrite(clean);
|
|
1031
|
+
const changedCollections = [];
|
|
1032
|
+
for (let collectionName of Object.keys(collections)) {
|
|
1033
|
+
if (!collectionName) {
|
|
1052
1034
|
continue;
|
|
1053
1035
|
}
|
|
1054
|
-
const filePath =
|
|
1055
|
-
process__default.cwd(),
|
|
1056
|
-
config.outputDir,
|
|
1057
|
-
namespace + ".json"
|
|
1058
|
-
);
|
|
1036
|
+
const filePath = await config.collect.collector.resolveCollectionFilePath(collectionName);
|
|
1059
1037
|
let originalJSON = {};
|
|
1060
1038
|
try {
|
|
1061
1039
|
originalJSON = await $LT_ReadJSON(filePath);
|
|
1062
1040
|
} catch (e) {
|
|
1063
|
-
|
|
1064
|
-
logger.warn(`Original namespace file "{namespace}.json" not found. A new one will be created.`, { namespace });
|
|
1065
|
-
}
|
|
1041
|
+
await config.collect.collector.onMissingCollection(collectionName);
|
|
1066
1042
|
}
|
|
1067
|
-
if (deepMergeTranslations(originalJSON,
|
|
1068
|
-
|
|
1043
|
+
if (deepMergeTranslations(originalJSON, collections[collectionName])) {
|
|
1044
|
+
changedCollections.push(collectionName);
|
|
1069
1045
|
await $LT_WriteJSON(filePath, originalJSON);
|
|
1070
1046
|
}
|
|
1071
1047
|
}
|
|
1072
|
-
|
|
1048
|
+
await config.collect.collector.postWrite(changedCollections);
|
|
1073
1049
|
}
|
|
1074
1050
|
async function $LT_CollectCandidateFilesWithTags(props) {
|
|
1075
1051
|
const { config, logger } = props;
|
|
@@ -1104,47 +1080,39 @@ async function $LT_WriteAsExportFile({ config, logger, files }) {
|
|
|
1104
1080
|
if (!packageJson) {
|
|
1105
1081
|
throw new Error("package.json not found");
|
|
1106
1082
|
}
|
|
1107
|
-
const
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
config: C,
|
|
1118
|
-
variableName: tag.variableName
|
|
1119
|
-
};
|
|
1120
|
-
})
|
|
1121
|
-
};
|
|
1122
|
-
}
|
|
1123
|
-
const data = {
|
|
1124
|
-
language: config.language,
|
|
1125
|
-
packageName: packageJson.name || "",
|
|
1126
|
-
files: langTagFiles
|
|
1083
|
+
const exportData = {
|
|
1084
|
+
baseLanguageCode: config.baseLanguageCode,
|
|
1085
|
+
files: files.map(({ relativeFilePath, tags }) => ({
|
|
1086
|
+
relativeFilePath,
|
|
1087
|
+
tags: tags.map((tag) => ({
|
|
1088
|
+
variableName: tag.variableName,
|
|
1089
|
+
config: tag.parameterConfig,
|
|
1090
|
+
translations: tag.parameterTranslations
|
|
1091
|
+
}))
|
|
1092
|
+
}))
|
|
1127
1093
|
};
|
|
1128
|
-
await
|
|
1094
|
+
await writeFile(EXPORTS_FILE_NAME, JSON.stringify(exportData), "utf-8");
|
|
1129
1095
|
logger.success(`Written {file}`, { file: EXPORTS_FILE_NAME });
|
|
1130
1096
|
}
|
|
1131
|
-
async function $
|
|
1097
|
+
async function $LT_GroupTagsToCollections({ logger, files, config }) {
|
|
1132
1098
|
let totalTags = 0;
|
|
1133
|
-
const
|
|
1134
|
-
function
|
|
1135
|
-
const
|
|
1136
|
-
|
|
1137
|
-
|
|
1099
|
+
const collections = {};
|
|
1100
|
+
function getTranslationsCollection(namespace) {
|
|
1101
|
+
const collectionName = config.collect.collector.aggregateCollection(namespace);
|
|
1102
|
+
const collection = collections[collectionName] || {};
|
|
1103
|
+
if (!(collectionName in collections)) {
|
|
1104
|
+
collections[collectionName] = collection;
|
|
1138
1105
|
}
|
|
1139
|
-
return
|
|
1106
|
+
return collection;
|
|
1140
1107
|
}
|
|
1141
1108
|
const allConflicts = [];
|
|
1142
1109
|
const existingValuesByNamespace = /* @__PURE__ */ new Map();
|
|
1143
1110
|
for (const file of files) {
|
|
1144
1111
|
totalTags += file.tags.length;
|
|
1145
|
-
for (const
|
|
1112
|
+
for (const _tag of file.tags) {
|
|
1113
|
+
const tag = config.collect.collector.transformTag(_tag);
|
|
1146
1114
|
const tagConfig = tag.parameterConfig;
|
|
1147
|
-
const
|
|
1115
|
+
const collection = getTranslationsCollection(tagConfig.namespace);
|
|
1148
1116
|
let existingValues = existingValuesByNamespace.get(tagConfig.namespace);
|
|
1149
1117
|
if (!existingValues) {
|
|
1150
1118
|
existingValues = /* @__PURE__ */ new Map();
|
|
@@ -1187,7 +1155,7 @@ async function $LT_GroupTagsToNamespaces({ logger, files, config }) {
|
|
|
1187
1155
|
};
|
|
1188
1156
|
const target = await ensureNestedObject(
|
|
1189
1157
|
tagConfig.path,
|
|
1190
|
-
|
|
1158
|
+
collection,
|
|
1191
1159
|
valueTracker,
|
|
1192
1160
|
addConflict
|
|
1193
1161
|
);
|
|
@@ -1207,7 +1175,7 @@ async function $LT_GroupTagsToNamespaces({ logger, files, config }) {
|
|
|
1207
1175
|
let shouldContinue = true;
|
|
1208
1176
|
config.collect.onCollectFinish({
|
|
1209
1177
|
totalTags,
|
|
1210
|
-
namespaces,
|
|
1178
|
+
namespaces: collections,
|
|
1211
1179
|
conflicts: allConflicts,
|
|
1212
1180
|
logger,
|
|
1213
1181
|
exit() {
|
|
@@ -1218,11 +1186,11 @@ async function $LT_GroupTagsToNamespaces({ logger, files, config }) {
|
|
|
1218
1186
|
throw new Error(`LangTagConflictResolution:Processing stopped due to collect finish handler`);
|
|
1219
1187
|
}
|
|
1220
1188
|
}
|
|
1221
|
-
return
|
|
1189
|
+
return collections;
|
|
1222
1190
|
}
|
|
1223
|
-
async function ensureNestedObject(path2,
|
|
1224
|
-
if (!path2 || !path2.trim()) return
|
|
1225
|
-
let current =
|
|
1191
|
+
async function ensureNestedObject(path2, rootCollection, valueTracker, addConflict) {
|
|
1192
|
+
if (!path2 || !path2.trim()) return rootCollection;
|
|
1193
|
+
let current = rootCollection;
|
|
1226
1194
|
let currentPath = "";
|
|
1227
1195
|
for (const key of path2.split(".")) {
|
|
1228
1196
|
currentPath = currentPath ? `${currentPath}.${key}` : key;
|
|
@@ -1322,19 +1290,10 @@ async function $LT_CMD_Collect(options) {
|
|
|
1322
1290
|
return;
|
|
1323
1291
|
}
|
|
1324
1292
|
try {
|
|
1325
|
-
const
|
|
1293
|
+
const collections = await $LT_GroupTagsToCollections({ logger, files, config });
|
|
1326
1294
|
const totalTags = files.reduce((sum, file) => sum + file.tags.length, 0);
|
|
1327
1295
|
logger.debug("Found {totalTags} translation tags", { totalTags });
|
|
1328
|
-
|
|
1329
|
-
if (!changedNamespaces?.length) {
|
|
1330
|
-
logger.info("No changes were made based on the current configuration and files");
|
|
1331
|
-
return;
|
|
1332
|
-
}
|
|
1333
|
-
const n = changedNamespaces.map((n2) => `"${n2}.json"`).join(", ");
|
|
1334
|
-
logger.success("Updated namespaces {outputDir} ({namespaces})", {
|
|
1335
|
-
outputDir: config.outputDir,
|
|
1336
|
-
namespaces: n
|
|
1337
|
-
});
|
|
1296
|
+
await $LT_WriteToCollections({ config, collections, logger, clean: options?.clean });
|
|
1338
1297
|
} catch (e) {
|
|
1339
1298
|
const prefix = "LangTagConflictResolution:";
|
|
1340
1299
|
if (e.message.startsWith(prefix)) {
|
|
@@ -1400,15 +1359,8 @@ async function handleFile(config, logger, cwdRelativeFilePath, event) {
|
|
|
1400
1359
|
const absoluteFilePath = path__default.join(cwd, cwdRelativeFilePath);
|
|
1401
1360
|
await checkAndRegenerateFileLangTags(config, logger, absoluteFilePath, cwdRelativeFilePath);
|
|
1402
1361
|
const files = await $LT_CollectCandidateFilesWithTags({ filesToScan: [cwdRelativeFilePath], config, logger });
|
|
1403
|
-
const namespaces = await $
|
|
1404
|
-
|
|
1405
|
-
if (changedNamespaces.length > 0) {
|
|
1406
|
-
const n = changedNamespaces.map((n2) => `"${n2}.json"`).join(", ");
|
|
1407
|
-
logger.success("Updated namespaces {outputDir} ({namespaces})", {
|
|
1408
|
-
outputDir: config.outputDir,
|
|
1409
|
-
namespaces: n
|
|
1410
|
-
});
|
|
1411
|
-
}
|
|
1362
|
+
const namespaces = await $LT_GroupTagsToCollections({ logger, files, config });
|
|
1363
|
+
await $LT_WriteToCollections({ config, collections: namespaces, logger });
|
|
1412
1364
|
}
|
|
1413
1365
|
async function detectModuleSystem() {
|
|
1414
1366
|
const packageJsonPath = join(process.cwd(), "package.json");
|
|
@@ -1448,7 +1400,13 @@ const generationAlgorithm = pathBasedConfigGenerator({
|
|
|
1448
1400
|
// },
|
|
1449
1401
|
// admin: {
|
|
1450
1402
|
// '>': 'management', // rename "admin" to "management"
|
|
1451
|
-
// users: false // ignore "users"
|
|
1403
|
+
// users: false // ignore "users",
|
|
1404
|
+
// ui: {
|
|
1405
|
+
// '>>': { // 'redirect' - ignore everything, jump to 'ui' namespace and prefix all paths with 'admin'
|
|
1406
|
+
// namespace: 'ui',
|
|
1407
|
+
// pathPrefix: 'admin'
|
|
1408
|
+
// }
|
|
1409
|
+
// }
|
|
1452
1410
|
// }
|
|
1453
1411
|
// }
|
|
1454
1412
|
// }
|
|
@@ -1461,7 +1419,8 @@ const config = {
|
|
|
1461
1419
|
isLibrary: false,
|
|
1462
1420
|
includes: ['src/**/*.{js,ts,jsx,tsx}'],
|
|
1463
1421
|
excludes: ['node_modules', 'dist', 'build', '**/*.test.ts'],
|
|
1464
|
-
|
|
1422
|
+
localesDirectory: 'public/locales',
|
|
1423
|
+
baseLanguageCode: 'en',
|
|
1465
1424
|
onConfigGeneration: async event => {
|
|
1466
1425
|
// We do not modify imported configurations
|
|
1467
1426
|
if (event.isImportedLibrary) return;
|
|
@@ -1503,97 +1462,171 @@ async function $LT_CMD_InitConfig() {
|
|
|
1503
1462
|
logger.error(error?.message);
|
|
1504
1463
|
}
|
|
1505
1464
|
}
|
|
1506
|
-
function $
|
|
1465
|
+
async function $LT_CollectExportFiles(logger) {
|
|
1507
1466
|
const nodeModulesPath = path$1.join(process__default.cwd(), "node_modules");
|
|
1508
1467
|
if (!fs.existsSync(nodeModulesPath)) {
|
|
1509
1468
|
logger.error('"node_modules" directory not found');
|
|
1510
1469
|
return [];
|
|
1511
1470
|
}
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1471
|
+
const results = [];
|
|
1472
|
+
try {
|
|
1473
|
+
const exportFiles = await globby([
|
|
1474
|
+
`node_modules/**/${EXPORTS_FILE_NAME}`
|
|
1475
|
+
], {
|
|
1476
|
+
cwd: process__default.cwd(),
|
|
1477
|
+
onlyFiles: true,
|
|
1478
|
+
ignore: ["**/node_modules/**/node_modules/**"],
|
|
1479
|
+
deep: 4
|
|
1480
|
+
});
|
|
1481
|
+
for (const exportFile of exportFiles) {
|
|
1482
|
+
const fullExportPath = path$1.resolve(exportFile);
|
|
1483
|
+
const packageJsonPath = findPackageJsonForExport(fullExportPath, nodeModulesPath);
|
|
1484
|
+
if (packageJsonPath) {
|
|
1485
|
+
results.push({
|
|
1486
|
+
exportPath: fullExportPath,
|
|
1487
|
+
packageJsonPath
|
|
1488
|
+
});
|
|
1489
|
+
} else {
|
|
1490
|
+
logger.warn("Found export file but could not match package.json: {exportPath}", {
|
|
1491
|
+
exportPath: fullExportPath
|
|
1492
|
+
});
|
|
1525
1493
|
}
|
|
1526
|
-
} catch (error) {
|
|
1527
|
-
logger.error('Error reading directory "{dir}": {error}', {
|
|
1528
|
-
dir,
|
|
1529
|
-
error: String(error)
|
|
1530
|
-
});
|
|
1531
1494
|
}
|
|
1532
|
-
|
|
1495
|
+
logger.debug("Found {count} export files with matching package.json in node_modules", {
|
|
1496
|
+
count: results.length
|
|
1497
|
+
});
|
|
1498
|
+
} catch (error) {
|
|
1499
|
+
logger.error("Error scanning node_modules with globby: {error}", {
|
|
1500
|
+
error: String(error)
|
|
1501
|
+
});
|
|
1533
1502
|
}
|
|
1534
|
-
return
|
|
1503
|
+
return results;
|
|
1535
1504
|
}
|
|
1536
|
-
|
|
1537
|
-
const
|
|
1538
|
-
const
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
let exportName = match.variableName || "";
|
|
1549
|
-
config.import.onImport({
|
|
1550
|
-
packageName: exportData.packageName,
|
|
1551
|
-
importedRelativePath: langTagFilePath,
|
|
1552
|
-
originalExportName: match.variableName,
|
|
1553
|
-
translations: parsedTranslations,
|
|
1554
|
-
config: parsedConfig,
|
|
1555
|
-
fileGenerationData
|
|
1556
|
-
}, {
|
|
1557
|
-
setFile: (f) => {
|
|
1558
|
-
file = f;
|
|
1559
|
-
},
|
|
1560
|
-
setExportName: (name) => {
|
|
1561
|
-
exportName = name;
|
|
1562
|
-
},
|
|
1563
|
-
setConfig: (newConfig) => {
|
|
1564
|
-
parsedConfig = newConfig;
|
|
1565
|
-
}
|
|
1566
|
-
});
|
|
1567
|
-
if (!file || !exportName) {
|
|
1568
|
-
throw new Error(`[lang-tag] onImport did not set fileName or exportName for package: ${exportData.packageName}, file: '${file}' (original: '${langTagFilePath}'), exportName: '${exportName}' (original: ${match.variableName})`);
|
|
1569
|
-
}
|
|
1570
|
-
let exports = generationFiles[file];
|
|
1571
|
-
if (!exports) {
|
|
1572
|
-
exports = {};
|
|
1573
|
-
generationFiles[file] = exports;
|
|
1574
|
-
}
|
|
1575
|
-
const param1 = config.translationArgPosition === 1 ? parsedTranslations : parsedConfig;
|
|
1576
|
-
const param2 = config.translationArgPosition === 1 ? parsedConfig : parsedTranslations;
|
|
1577
|
-
exports[exportName] = `${config.tagName}(${JSON5.stringify(param1, void 0, 4)}, ${JSON5.stringify(param2, void 0, 4)})`;
|
|
1505
|
+
function findPackageJsonForExport(exportPath, nodeModulesPath) {
|
|
1506
|
+
const relativePath = path$1.relative(nodeModulesPath, exportPath);
|
|
1507
|
+
const pathParts = relativePath.split(path$1.sep);
|
|
1508
|
+
if (pathParts.length < 2) {
|
|
1509
|
+
return null;
|
|
1510
|
+
}
|
|
1511
|
+
if (pathParts[0].startsWith("@")) {
|
|
1512
|
+
if (pathParts.length >= 3) {
|
|
1513
|
+
const packageDir = path$1.join(nodeModulesPath, pathParts[0], pathParts[1]);
|
|
1514
|
+
const packageJsonPath = path$1.join(packageDir, "package.json");
|
|
1515
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
1516
|
+
return packageJsonPath;
|
|
1578
1517
|
}
|
|
1579
1518
|
}
|
|
1519
|
+
} else {
|
|
1520
|
+
const packageDir = path$1.join(nodeModulesPath, pathParts[0]);
|
|
1521
|
+
const packageJsonPath = path$1.join(packageDir, "package.json");
|
|
1522
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
1523
|
+
return packageJsonPath;
|
|
1524
|
+
}
|
|
1580
1525
|
}
|
|
1581
|
-
|
|
1526
|
+
return null;
|
|
1527
|
+
}
|
|
1528
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
1529
|
+
const __dirname = dirname(__filename);
|
|
1530
|
+
const templatePath = join(__dirname, "templates", "import", "imported-tag.mustache");
|
|
1531
|
+
const template = readFileSync(templatePath, "utf-8");
|
|
1532
|
+
function renderTemplate$1(data) {
|
|
1533
|
+
return mustache.render(template, data, {}, { escape: (text) => text });
|
|
1534
|
+
}
|
|
1535
|
+
async function generateImportFiles(config, logger, importManager) {
|
|
1536
|
+
const importedFiles = importManager.getImportedFiles();
|
|
1537
|
+
for (const importedFile of importedFiles) {
|
|
1582
1538
|
const filePath = resolve(
|
|
1583
1539
|
process$1.cwd(),
|
|
1584
1540
|
config.import.dir,
|
|
1585
|
-
|
|
1541
|
+
importedFile.pathRelativeToImportDir
|
|
1586
1542
|
);
|
|
1587
|
-
const
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1543
|
+
const processedExports = importedFile.tags.map((tag) => {
|
|
1544
|
+
const parameter1 = config.translationArgPosition === 1 ? tag.translations : tag.config;
|
|
1545
|
+
const parameter2 = config.translationArgPosition === 1 ? tag.config : tag.translations;
|
|
1546
|
+
const hasParameter2 = parameter2 !== null && parameter2 !== void 0 && (typeof parameter2 !== "object" || Object.keys(parameter2).length > 0);
|
|
1547
|
+
return {
|
|
1548
|
+
name: tag.variableName,
|
|
1549
|
+
parameter1: JSON5.stringify(parameter1, void 0, 4),
|
|
1550
|
+
parameter2: hasParameter2 ? JSON5.stringify(parameter2, void 0, 4) : null,
|
|
1551
|
+
hasParameter2,
|
|
1552
|
+
config: {
|
|
1553
|
+
tagName: config.tagName
|
|
1554
|
+
}
|
|
1555
|
+
};
|
|
1556
|
+
});
|
|
1557
|
+
const templateData = {
|
|
1558
|
+
tagImportPath: config.import.tagImportPath,
|
|
1559
|
+
exports: processedExports
|
|
1560
|
+
};
|
|
1561
|
+
const content = renderTemplate$1(templateData);
|
|
1562
|
+
await $LT_EnsureDirectoryExists(dirname(filePath));
|
|
1594
1563
|
await writeFile(filePath, content, "utf-8");
|
|
1595
|
-
logger.success('
|
|
1564
|
+
logger.success('Created tag file: "{file}"', { file: importedFile.pathRelativeToImportDir });
|
|
1596
1565
|
}
|
|
1566
|
+
}
|
|
1567
|
+
class ImportManager {
|
|
1568
|
+
importedFiles = [];
|
|
1569
|
+
constructor() {
|
|
1570
|
+
this.importedFiles = [];
|
|
1571
|
+
}
|
|
1572
|
+
importTag(pathRelativeToImportDir, tag) {
|
|
1573
|
+
if (!pathRelativeToImportDir) {
|
|
1574
|
+
throw new Error(`pathRelativeToImportDir required, got: ${pathRelativeToImportDir}`);
|
|
1575
|
+
}
|
|
1576
|
+
if (!tag?.variableName) {
|
|
1577
|
+
throw new Error(`tag.variableName required, got: ${tag?.variableName}`);
|
|
1578
|
+
}
|
|
1579
|
+
if (!this.isValidJavaScriptIdentifier(tag.variableName)) {
|
|
1580
|
+
throw new Error(`Invalid JavaScript identifier: "${tag.variableName}". Variable names must start with a letter, underscore, or dollar sign, and contain only letters, digits, underscores, and dollar signs.`);
|
|
1581
|
+
}
|
|
1582
|
+
if (tag.translations == null) {
|
|
1583
|
+
throw new Error(`tag.translations required`);
|
|
1584
|
+
}
|
|
1585
|
+
let importedFile = this.importedFiles.find(
|
|
1586
|
+
(file) => file.pathRelativeToImportDir === pathRelativeToImportDir
|
|
1587
|
+
);
|
|
1588
|
+
if (importedFile) {
|
|
1589
|
+
const duplicateTag = importedFile.tags.find(
|
|
1590
|
+
(existingTag) => existingTag.variableName === tag.variableName
|
|
1591
|
+
);
|
|
1592
|
+
if (duplicateTag) {
|
|
1593
|
+
throw new Error(`Duplicate variable name "${tag.variableName}" in file "${pathRelativeToImportDir}". Variable names must be unique within the same file.`);
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
if (!importedFile) {
|
|
1597
|
+
importedFile = { pathRelativeToImportDir, tags: [] };
|
|
1598
|
+
this.importedFiles.push(importedFile);
|
|
1599
|
+
}
|
|
1600
|
+
importedFile.tags.push(tag);
|
|
1601
|
+
}
|
|
1602
|
+
getImportedFiles() {
|
|
1603
|
+
return [...this.importedFiles];
|
|
1604
|
+
}
|
|
1605
|
+
getImportedFilesCount() {
|
|
1606
|
+
return this.importedFiles.length;
|
|
1607
|
+
}
|
|
1608
|
+
hasImportedFiles() {
|
|
1609
|
+
return this.importedFiles.length > 0;
|
|
1610
|
+
}
|
|
1611
|
+
isValidJavaScriptIdentifier(name) {
|
|
1612
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
async function $LT_ImportLibraries(config, logger) {
|
|
1616
|
+
const exportFiles = await $LT_CollectExportFiles(logger);
|
|
1617
|
+
const importManager = new ImportManager();
|
|
1618
|
+
let exports = [];
|
|
1619
|
+
for (const { exportPath, packageJsonPath } of exportFiles) {
|
|
1620
|
+
const exportData = await $LT_ReadJSON(exportPath);
|
|
1621
|
+
const packageJSON = await $LT_ReadJSON(packageJsonPath);
|
|
1622
|
+
exports.push({ packageJSON, exportData });
|
|
1623
|
+
}
|
|
1624
|
+
config.import.onImport({ exports, importManager, logger, langTagConfig: config });
|
|
1625
|
+
if (!importManager.hasImportedFiles()) {
|
|
1626
|
+
logger.warn("No tags were imported from any library files");
|
|
1627
|
+
return;
|
|
1628
|
+
}
|
|
1629
|
+
await generateImportFiles(config, logger, importManager);
|
|
1597
1630
|
if (config.import.onImportFinish) config.import.onImportFinish();
|
|
1598
1631
|
}
|
|
1599
1632
|
async function $LT_ImportTranslations() {
|
|
@@ -1603,15 +1636,15 @@ async function $LT_ImportTranslations() {
|
|
|
1603
1636
|
await $LT_ImportLibraries(config, logger);
|
|
1604
1637
|
logger.success("Successfully imported translations from libraries.");
|
|
1605
1638
|
}
|
|
1606
|
-
function renderTemplate(
|
|
1607
|
-
return mustache.render(
|
|
1639
|
+
function renderTemplate(template2, data) {
|
|
1640
|
+
return mustache.render(template2, data, {}, { escape: (text) => text });
|
|
1608
1641
|
}
|
|
1609
1642
|
function loadTemplate(templateName) {
|
|
1610
|
-
const
|
|
1611
|
-
const
|
|
1612
|
-
const
|
|
1643
|
+
const __filename2 = fileURLToPath(import.meta.url);
|
|
1644
|
+
const __dirname2 = dirname(__filename2);
|
|
1645
|
+
const templatePath2 = join(__dirname2, "templates", "tag", `${templateName}.mustache`);
|
|
1613
1646
|
try {
|
|
1614
|
-
return readFileSync(
|
|
1647
|
+
return readFileSync(templatePath2, "utf-8");
|
|
1615
1648
|
} catch (error) {
|
|
1616
1649
|
throw new Error(`Failed to load template ${templateName}: ${error}`);
|
|
1617
1650
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
-
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Imported library translations
|
|
3
|
+
*
|
|
4
|
+
* You can modify these translations as needed. On next import:
|
|
5
|
+
* - Your changes will be preserved ( for now only translations values are preserved )
|
|
6
|
+
* - New translations will be added
|
|
7
|
+
* - Unused translations will be commented out
|
|
8
|
+
*/
|
|
9
|
+
{{tagImportPath}}
|
|
10
|
+
|
|
11
|
+
{{#exports}}
|
|
12
|
+
export const {{name}} = {{config.tagName}}({{parameter1}}{{#hasParameter2}}, {{parameter2}}{{/hasParameter2}});
|
|
13
|
+
|
|
14
|
+
{{/exports}}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|