@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/index.cjs CHANGED
@@ -9,7 +9,9 @@ const path = require("path");
9
9
  const globby = require("globby");
10
10
  const path$1 = require("pathe");
11
11
  const url = require("url");
12
+ require("case");
12
13
  const process$1 = require("node:process");
14
+ const flexibleImportAlgorithm = require("./flexible-import-algorithm-Fa-l4jWj.cjs");
13
15
  const acorn = require("acorn");
14
16
  const micromatch = require("micromatch");
15
17
  const chokidar = require("chokidar");
@@ -498,13 +500,16 @@ function isConfigSame(c1, c2) {
498
500
  return false;
499
501
  }
500
502
  const CONFIG_FILE_NAME = ".lang-tag.config.js";
501
- const EXPORTS_FILE_NAME = ".lang-tag.exports.json";
503
+ const EXPORTS_FILE_NAME = "lang-tags.json";
502
504
  const LANG_TAG_DEFAULT_CONFIG = {
503
505
  tagName: "lang",
506
+ isLibrary: false,
504
507
  includes: ["src/**/*.{js,ts,jsx,tsx}"],
505
508
  excludes: ["node_modules", "dist", "build"],
506
- outputDir: "locales/en",
509
+ localesDirectory: "locales",
510
+ baseLanguageCode: "en",
507
511
  collect: {
512
+ collector: new flexibleImportAlgorithm.NamespaceCollector(),
508
513
  defaultNamespace: "common",
509
514
  ignoreConflictsWithMatchingValues: true,
510
515
  onCollectConfigFix: ({ config, langTagConfig }) => {
@@ -524,15 +529,19 @@ const LANG_TAG_DEFAULT_CONFIG = {
524
529
  import: {
525
530
  dir: "src/lang-libraries",
526
531
  tagImportPath: 'import { lang } from "@/my-lang-tag-path"',
527
- onImport: ({ importedRelativePath, fileGenerationData }, actions) => {
528
- const exportIndex = (fileGenerationData.index || 0) + 1;
529
- fileGenerationData.index = exportIndex;
530
- actions.setFile(path$1.basename(importedRelativePath));
531
- actions.setExportName(`translations${exportIndex}`);
532
- }
532
+ onImport: flexibleImportAlgorithm.flexibleImportAlgorithm({
533
+ filePath: {
534
+ includePackageInPath: true
535
+ }
536
+ })
537
+ // onImport: ({importedRelativePath, fileGenerationData}: LangTagCLIOnImportParams, actions)=> {
538
+ // const exportIndex = (fileGenerationData.index || 0) + 1;
539
+ // fileGenerationData.index = exportIndex;
540
+ //
541
+ // actions.setFile(path.basename(importedRelativePath));
542
+ // actions.setExportName(`translations${exportIndex}`);
543
+ // }
533
544
  },
534
- isLibrary: false,
535
- language: "en",
536
545
  translationArgPosition: 1,
537
546
  onConfigGeneration: async (event) => {
538
547
  }
@@ -552,7 +561,7 @@ async function $LT_ReadConfig(projectPath) {
552
561
  if (tn === "langtag" || tn === "lang-tag") {
553
562
  throw new Error('Custom tagName cannot be "lang-tag" or "langtag"! (It is not recommended for use with libraries)\n');
554
563
  }
555
- return {
564
+ const config = {
556
565
  ...LANG_TAG_DEFAULT_CONFIG,
557
566
  ...userConfig,
558
567
  import: {
@@ -564,39 +573,14 @@ async function $LT_ReadConfig(projectPath) {
564
573
  ...userConfig.collect
565
574
  }
566
575
  };
576
+ if (!config.collect.collector) {
577
+ throw new Error("Collector not found! (config.collect.collector)");
578
+ }
579
+ return config;
567
580
  } catch (error) {
568
581
  throw error;
569
582
  }
570
583
  }
571
- async function $LT_EnsureDirectoryExists(filePath) {
572
- await promises.mkdir(filePath, { recursive: true });
573
- }
574
- async function $LT_RemoveDirectory(dirPath) {
575
- try {
576
- await promises.rm(dirPath, { recursive: true, force: true });
577
- } catch (error) {
578
- }
579
- }
580
- async function $LT_WriteJSON(filePath, data) {
581
- await promises.writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
582
- }
583
- async function $LT_ReadJSON(filePath) {
584
- const content = await promises.readFile(filePath, "utf-8");
585
- return JSON.parse(content);
586
- }
587
- async function $LT_WriteFileWithDirs(filePath, content) {
588
- const dir = path.dirname(filePath);
589
- try {
590
- await promises.mkdir(dir, { recursive: true });
591
- } catch (error) {
592
- }
593
- await promises.writeFile(filePath, content, "utf-8");
594
- }
595
- async function $LT_ReadFileContent(relativeFilePath) {
596
- const cwd = process.cwd();
597
- const absolutePath = path.resolve(cwd, relativeFilePath);
598
- return await promises.readFile(absolutePath, "utf-8");
599
- }
600
584
  function parseObjectAST(code) {
601
585
  const nodes = [];
602
586
  try {
@@ -809,7 +793,7 @@ function printLines(lines, startLineNumber, errorLines = /* @__PURE__ */ new Set
809
793
  }
810
794
  async function getLangTagCodeSection(tagInfo) {
811
795
  const { tag, relativeFilePath } = tagInfo;
812
- const fileContent = await $LT_ReadFileContent(relativeFilePath);
796
+ const fileContent = await flexibleImportAlgorithm.$LT_ReadFileContent(relativeFilePath);
813
797
  const fileLines = fileContent.split("\n");
814
798
  const startLine = tag.line;
815
799
  const endLine = tag.line + tag.fullMatch.split("\n").length - 1;
@@ -998,6 +982,8 @@ function $LT_CreateDefaultLogger(debugMode, translationArgPosition = 1) {
998
982
  async function $LT_GetCommandEssentials() {
999
983
  const config = await $LT_ReadConfig(process$1.cwd());
1000
984
  const logger = $LT_CreateDefaultLogger(config.debug, config.translationArgPosition);
985
+ config.collect.collector.config = config;
986
+ config.collect.collector.logger = logger;
1001
987
  return {
1002
988
  config,
1003
989
  logger
@@ -1060,36 +1046,26 @@ function deepMergeTranslations(target, source) {
1060
1046
  }
1061
1047
  return changed;
1062
1048
  }
1063
- async function $LT_WriteToNamespaces({ config, namespaces, logger, clean }) {
1064
- const changedNamespaces = [];
1065
- if (clean) {
1066
- logger.info("Cleaning output directory...");
1067
- await $LT_RemoveDirectory(config.outputDir);
1068
- }
1069
- await $LT_EnsureDirectoryExists(config.outputDir);
1070
- for (let namespace of Object.keys(namespaces)) {
1071
- if (!namespace) {
1049
+ async function $LT_WriteToCollections({ config, collections, logger, clean }) {
1050
+ await config.collect.collector.preWrite(clean);
1051
+ const changedCollections = [];
1052
+ for (let collectionName of Object.keys(collections)) {
1053
+ if (!collectionName) {
1072
1054
  continue;
1073
1055
  }
1074
- const filePath = path$1.resolve(
1075
- process$1.cwd(),
1076
- config.outputDir,
1077
- namespace + ".json"
1078
- );
1056
+ const filePath = await config.collect.collector.resolveCollectionFilePath(collectionName);
1079
1057
  let originalJSON = {};
1080
1058
  try {
1081
- originalJSON = await $LT_ReadJSON(filePath);
1059
+ originalJSON = await flexibleImportAlgorithm.$LT_ReadJSON(filePath);
1082
1060
  } catch (e) {
1083
- if (!clean) {
1084
- logger.warn(`Original namespace file "{namespace}.json" not found. A new one will be created.`, { namespace });
1085
- }
1061
+ await config.collect.collector.onMissingCollection(collectionName);
1086
1062
  }
1087
- if (deepMergeTranslations(originalJSON, namespaces[namespace])) {
1088
- changedNamespaces.push(namespace);
1089
- await $LT_WriteJSON(filePath, originalJSON);
1063
+ if (deepMergeTranslations(originalJSON, collections[collectionName])) {
1064
+ changedCollections.push(collectionName);
1065
+ await flexibleImportAlgorithm.$LT_WriteJSON(filePath, originalJSON);
1090
1066
  }
1091
1067
  }
1092
- return changedNamespaces;
1068
+ await config.collect.collector.postWrite(changedCollections);
1093
1069
  }
1094
1070
  async function $LT_CollectCandidateFilesWithTags(props) {
1095
1071
  const { config, logger } = props;
@@ -1120,51 +1096,43 @@ async function $LT_CollectCandidateFilesWithTags(props) {
1120
1096
  return candidates;
1121
1097
  }
1122
1098
  async function $LT_WriteAsExportFile({ config, logger, files }) {
1123
- const packageJson = await $LT_ReadJSON(path.resolve(process.cwd(), "package.json"));
1099
+ const packageJson = await flexibleImportAlgorithm.$LT_ReadJSON(path.resolve(process.cwd(), "package.json"));
1124
1100
  if (!packageJson) {
1125
1101
  throw new Error("package.json not found");
1126
1102
  }
1127
- const langTagFiles = {};
1128
- for (const file of files) {
1129
- langTagFiles[file.relativeFilePath] = {
1130
- matches: file.tags.map((tag) => {
1131
- let T = config.translationArgPosition === 1 ? tag.parameter1Text : tag.parameter2Text;
1132
- let C = config.translationArgPosition === 1 ? tag.parameter2Text : tag.parameter1Text;
1133
- if (!T) T = "{}";
1134
- if (!C) C = "{}";
1135
- return {
1136
- translations: T,
1137
- config: C,
1138
- variableName: tag.variableName
1139
- };
1140
- })
1141
- };
1142
- }
1143
- const data = {
1144
- language: config.language,
1145
- packageName: packageJson.name || "",
1146
- files: langTagFiles
1103
+ const exportData = {
1104
+ baseLanguageCode: config.baseLanguageCode,
1105
+ files: files.map(({ relativeFilePath, tags }) => ({
1106
+ relativeFilePath,
1107
+ tags: tags.map((tag) => ({
1108
+ variableName: tag.variableName,
1109
+ config: tag.parameterConfig,
1110
+ translations: tag.parameterTranslations
1111
+ }))
1112
+ }))
1147
1113
  };
1148
- await $LT_WriteJSON(EXPORTS_FILE_NAME, data);
1114
+ await promises.writeFile(EXPORTS_FILE_NAME, JSON.stringify(exportData), "utf-8");
1149
1115
  logger.success(`Written {file}`, { file: EXPORTS_FILE_NAME });
1150
1116
  }
1151
- async function $LT_GroupTagsToNamespaces({ logger, files, config }) {
1117
+ async function $LT_GroupTagsToCollections({ logger, files, config }) {
1152
1118
  let totalTags = 0;
1153
- const namespaces = {};
1154
- function getTranslations(namespace) {
1155
- const namespaceTranslations = namespaces[namespace] || {};
1156
- if (!(namespace in namespaces)) {
1157
- namespaces[namespace] = namespaceTranslations;
1119
+ const collections = {};
1120
+ function getTranslationsCollection(namespace) {
1121
+ const collectionName = config.collect.collector.aggregateCollection(namespace);
1122
+ const collection = collections[collectionName] || {};
1123
+ if (!(collectionName in collections)) {
1124
+ collections[collectionName] = collection;
1158
1125
  }
1159
- return namespaceTranslations;
1126
+ return collection;
1160
1127
  }
1161
1128
  const allConflicts = [];
1162
1129
  const existingValuesByNamespace = /* @__PURE__ */ new Map();
1163
1130
  for (const file of files) {
1164
1131
  totalTags += file.tags.length;
1165
- for (const tag of file.tags) {
1132
+ for (const _tag of file.tags) {
1133
+ const tag = config.collect.collector.transformTag(_tag);
1166
1134
  const tagConfig = tag.parameterConfig;
1167
- const namespaceTranslations = getTranslations(tagConfig.namespace);
1135
+ const collection = getTranslationsCollection(tagConfig.namespace);
1168
1136
  let existingValues = existingValuesByNamespace.get(tagConfig.namespace);
1169
1137
  if (!existingValues) {
1170
1138
  existingValues = /* @__PURE__ */ new Map();
@@ -1207,7 +1175,7 @@ async function $LT_GroupTagsToNamespaces({ logger, files, config }) {
1207
1175
  };
1208
1176
  const target = await ensureNestedObject(
1209
1177
  tagConfig.path,
1210
- namespaceTranslations,
1178
+ collection,
1211
1179
  valueTracker,
1212
1180
  addConflict
1213
1181
  );
@@ -1227,7 +1195,7 @@ async function $LT_GroupTagsToNamespaces({ logger, files, config }) {
1227
1195
  let shouldContinue = true;
1228
1196
  config.collect.onCollectFinish({
1229
1197
  totalTags,
1230
- namespaces,
1198
+ namespaces: collections,
1231
1199
  conflicts: allConflicts,
1232
1200
  logger,
1233
1201
  exit() {
@@ -1238,11 +1206,11 @@ async function $LT_GroupTagsToNamespaces({ logger, files, config }) {
1238
1206
  throw new Error(`LangTagConflictResolution:Processing stopped due to collect finish handler`);
1239
1207
  }
1240
1208
  }
1241
- return namespaces;
1209
+ return collections;
1242
1210
  }
1243
- async function ensureNestedObject(path2, root, valueTracker, addConflict) {
1244
- if (!path2 || !path2.trim()) return root;
1245
- let current = root;
1211
+ async function ensureNestedObject(path2, rootCollection, valueTracker, addConflict) {
1212
+ if (!path2 || !path2.trim()) return rootCollection;
1213
+ let current = rootCollection;
1246
1214
  let currentPath = "";
1247
1215
  for (const key of path2.split(".")) {
1248
1216
  currentPath = currentPath ? `${currentPath}.${key}` : key;
@@ -1342,19 +1310,10 @@ async function $LT_CMD_Collect(options) {
1342
1310
  return;
1343
1311
  }
1344
1312
  try {
1345
- const namespaces = await $LT_GroupTagsToNamespaces({ logger, files, config });
1313
+ const collections = await $LT_GroupTagsToCollections({ logger, files, config });
1346
1314
  const totalTags = files.reduce((sum, file) => sum + file.tags.length, 0);
1347
1315
  logger.debug("Found {totalTags} translation tags", { totalTags });
1348
- const changedNamespaces = await $LT_WriteToNamespaces({ config, namespaces, logger, clean: options?.clean });
1349
- if (!changedNamespaces?.length) {
1350
- logger.info("No changes were made based on the current configuration and files");
1351
- return;
1352
- }
1353
- const n = changedNamespaces.map((n2) => `"${n2}.json"`).join(", ");
1354
- logger.success("Updated namespaces {outputDir} ({namespaces})", {
1355
- outputDir: config.outputDir,
1356
- namespaces: n
1357
- });
1316
+ await $LT_WriteToCollections({ config, collections, logger, clean: options?.clean });
1358
1317
  } catch (e) {
1359
1318
  const prefix = "LangTagConflictResolution:";
1360
1319
  if (e.message.startsWith(prefix)) {
@@ -1420,15 +1379,8 @@ async function handleFile(config, logger, cwdRelativeFilePath, event) {
1420
1379
  const absoluteFilePath = path.join(cwd, cwdRelativeFilePath);
1421
1380
  await checkAndRegenerateFileLangTags(config, logger, absoluteFilePath, cwdRelativeFilePath);
1422
1381
  const files = await $LT_CollectCandidateFilesWithTags({ filesToScan: [cwdRelativeFilePath], config, logger });
1423
- const namespaces = await $LT_GroupTagsToNamespaces({ logger, files, config });
1424
- const changedNamespaces = await $LT_WriteToNamespaces({ config, namespaces, logger });
1425
- if (changedNamespaces.length > 0) {
1426
- const n = changedNamespaces.map((n2) => `"${n2}.json"`).join(", ");
1427
- logger.success("Updated namespaces {outputDir} ({namespaces})", {
1428
- outputDir: config.outputDir,
1429
- namespaces: n
1430
- });
1431
- }
1382
+ const namespaces = await $LT_GroupTagsToCollections({ logger, files, config });
1383
+ await $LT_WriteToCollections({ config, collections: namespaces, logger });
1432
1384
  }
1433
1385
  async function detectModuleSystem() {
1434
1386
  const packageJsonPath = path.join(process.cwd(), "package.json");
@@ -1468,7 +1420,13 @@ const generationAlgorithm = pathBasedConfigGenerator({
1468
1420
  // },
1469
1421
  // admin: {
1470
1422
  // '>': 'management', // rename "admin" to "management"
1471
- // users: false // ignore "users"
1423
+ // users: false // ignore "users",
1424
+ // ui: {
1425
+ // '>>': { // 'redirect' - ignore everything, jump to 'ui' namespace and prefix all paths with 'admin'
1426
+ // namespace: 'ui',
1427
+ // pathPrefix: 'admin'
1428
+ // }
1429
+ // }
1472
1430
  // }
1473
1431
  // }
1474
1432
  // }
@@ -1481,7 +1439,8 @@ const config = {
1481
1439
  isLibrary: false,
1482
1440
  includes: ['src/**/*.{js,ts,jsx,tsx}'],
1483
1441
  excludes: ['node_modules', 'dist', 'build', '**/*.test.ts'],
1484
- outputDir: 'public/locales/en',
1442
+ localesDirectory: 'public/locales',
1443
+ baseLanguageCode: 'en',
1485
1444
  onConfigGeneration: async event => {
1486
1445
  // We do not modify imported configurations
1487
1446
  if (event.isImportedLibrary) return;
@@ -1523,115 +1482,189 @@ async function $LT_CMD_InitConfig() {
1523
1482
  logger.error(error?.message);
1524
1483
  }
1525
1484
  }
1526
- function $LT_CollectNodeModulesExportFilePaths(logger) {
1485
+ async function $LT_CollectExportFiles(logger) {
1527
1486
  const nodeModulesPath = path$1.join(process$1.cwd(), "node_modules");
1528
1487
  if (!fs.existsSync(nodeModulesPath)) {
1529
1488
  logger.error('"node_modules" directory not found');
1530
1489
  return [];
1531
1490
  }
1532
- function findExportJson(dir, depth = 0, maxDepth = 3) {
1533
- if (depth > maxDepth) return [];
1534
- let results = [];
1535
- try {
1536
- const files = fs.readdirSync(dir);
1537
- for (const file of files) {
1538
- const fullPath = path$1.join(dir, file);
1539
- const stat = fs.statSync(fullPath);
1540
- if (stat.isDirectory()) {
1541
- results = results.concat(findExportJson(fullPath, depth + 1, maxDepth));
1542
- } else if (file === EXPORTS_FILE_NAME) {
1543
- results.push(fullPath);
1544
- }
1491
+ const results = [];
1492
+ try {
1493
+ const exportFiles = await globby.globby([
1494
+ `node_modules/**/${EXPORTS_FILE_NAME}`
1495
+ ], {
1496
+ cwd: process$1.cwd(),
1497
+ onlyFiles: true,
1498
+ ignore: ["**/node_modules/**/node_modules/**"],
1499
+ deep: 4
1500
+ });
1501
+ for (const exportFile of exportFiles) {
1502
+ const fullExportPath = path$1.resolve(exportFile);
1503
+ const packageJsonPath = findPackageJsonForExport(fullExportPath, nodeModulesPath);
1504
+ if (packageJsonPath) {
1505
+ results.push({
1506
+ exportPath: fullExportPath,
1507
+ packageJsonPath
1508
+ });
1509
+ } else {
1510
+ logger.warn("Found export file but could not match package.json: {exportPath}", {
1511
+ exportPath: fullExportPath
1512
+ });
1545
1513
  }
1546
- } catch (error) {
1547
- logger.error('Error reading directory "{dir}": {error}', {
1548
- dir,
1549
- error: String(error)
1550
- });
1551
1514
  }
1552
- return results;
1515
+ logger.debug("Found {count} export files with matching package.json in node_modules", {
1516
+ count: results.length
1517
+ });
1518
+ } catch (error) {
1519
+ logger.error("Error scanning node_modules with globby: {error}", {
1520
+ error: String(error)
1521
+ });
1553
1522
  }
1554
- return findExportJson(nodeModulesPath);
1523
+ return results;
1555
1524
  }
1556
- async function $LT_ImportLibraries(config, logger) {
1557
- const files = $LT_CollectNodeModulesExportFilePaths(logger);
1558
- const generationFiles = {};
1559
- for (const filePath of files) {
1560
- const exportData = await $LT_ReadJSON(filePath);
1561
- for (let langTagFilePath in exportData.files) {
1562
- const fileGenerationData = {};
1563
- const matches = exportData.files[langTagFilePath].matches;
1564
- for (let match of matches) {
1565
- let parsedTranslations = typeof match.translations === "string" ? JSON5.parse(match.translations) : match.translations;
1566
- let parsedConfig = typeof match.config === "string" ? JSON5.parse(match.config) : match.config === void 0 ? {} : match.config;
1567
- let file = langTagFilePath;
1568
- let exportName = match.variableName || "";
1569
- config.import.onImport({
1570
- packageName: exportData.packageName,
1571
- importedRelativePath: langTagFilePath,
1572
- originalExportName: match.variableName,
1573
- translations: parsedTranslations,
1574
- config: parsedConfig,
1575
- fileGenerationData
1576
- }, {
1577
- setFile: (f) => {
1578
- file = f;
1579
- },
1580
- setExportName: (name) => {
1581
- exportName = name;
1582
- },
1583
- setConfig: (newConfig) => {
1584
- parsedConfig = newConfig;
1585
- }
1586
- });
1587
- if (!file || !exportName) {
1588
- 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})`);
1589
- }
1590
- let exports2 = generationFiles[file];
1591
- if (!exports2) {
1592
- exports2 = {};
1593
- generationFiles[file] = exports2;
1594
- }
1595
- const param1 = config.translationArgPosition === 1 ? parsedTranslations : parsedConfig;
1596
- const param2 = config.translationArgPosition === 1 ? parsedConfig : parsedTranslations;
1597
- exports2[exportName] = `${config.tagName}(${JSON5.stringify(param1, void 0, 4)}, ${JSON5.stringify(param2, void 0, 4)})`;
1525
+ function findPackageJsonForExport(exportPath, nodeModulesPath) {
1526
+ const relativePath = path$1.relative(nodeModulesPath, exportPath);
1527
+ const pathParts = relativePath.split(path$1.sep);
1528
+ if (pathParts.length < 2) {
1529
+ return null;
1530
+ }
1531
+ if (pathParts[0].startsWith("@")) {
1532
+ if (pathParts.length >= 3) {
1533
+ const packageDir = path$1.join(nodeModulesPath, pathParts[0], pathParts[1]);
1534
+ const packageJsonPath = path$1.join(packageDir, "package.json");
1535
+ if (fs.existsSync(packageJsonPath)) {
1536
+ return packageJsonPath;
1598
1537
  }
1599
1538
  }
1539
+ } else {
1540
+ const packageDir = path$1.join(nodeModulesPath, pathParts[0]);
1541
+ const packageJsonPath = path$1.join(packageDir, "package.json");
1542
+ if (fs.existsSync(packageJsonPath)) {
1543
+ return packageJsonPath;
1544
+ }
1600
1545
  }
1601
- for (let fileName of Object.keys(generationFiles)) {
1546
+ return null;
1547
+ }
1548
+ const __filename$1 = url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index.cjs", document.baseURI).href);
1549
+ const __dirname$1 = path.dirname(__filename$1);
1550
+ const templatePath = path.join(__dirname$1, "templates", "import", "imported-tag.mustache");
1551
+ const template = fs.readFileSync(templatePath, "utf-8");
1552
+ function renderTemplate$1(data) {
1553
+ return mustache.render(template, data, {}, { escape: (text) => text });
1554
+ }
1555
+ async function generateImportFiles(config, logger, importManager) {
1556
+ const importedFiles = importManager.getImportedFiles();
1557
+ for (const importedFile of importedFiles) {
1602
1558
  const filePath = path$1.resolve(
1603
1559
  process__namespace.cwd(),
1604
1560
  config.import.dir,
1605
- fileName
1561
+ importedFile.pathRelativeToImportDir
1606
1562
  );
1607
- const exports2 = Object.entries(generationFiles[fileName]).map(([name, tag]) => {
1608
- return `export const ${name} = ${tag};`;
1609
- }).join("\n\n");
1610
- const content = `${config.import.tagImportPath}
1611
-
1612
- ${exports2}`;
1613
- await $LT_EnsureDirectoryExists(path$1.dirname(filePath));
1563
+ const processedExports = importedFile.tags.map((tag) => {
1564
+ const parameter1 = config.translationArgPosition === 1 ? tag.translations : tag.config;
1565
+ const parameter2 = config.translationArgPosition === 1 ? tag.config : tag.translations;
1566
+ const hasParameter2 = parameter2 !== null && parameter2 !== void 0 && (typeof parameter2 !== "object" || Object.keys(parameter2).length > 0);
1567
+ return {
1568
+ name: tag.variableName,
1569
+ parameter1: JSON5.stringify(parameter1, void 0, 4),
1570
+ parameter2: hasParameter2 ? JSON5.stringify(parameter2, void 0, 4) : null,
1571
+ hasParameter2,
1572
+ config: {
1573
+ tagName: config.tagName
1574
+ }
1575
+ };
1576
+ });
1577
+ const templateData = {
1578
+ tagImportPath: config.import.tagImportPath,
1579
+ exports: processedExports
1580
+ };
1581
+ const content = renderTemplate$1(templateData);
1582
+ await flexibleImportAlgorithm.$LT_EnsureDirectoryExists(path.dirname(filePath));
1614
1583
  await promises.writeFile(filePath, content, "utf-8");
1615
- logger.success('Imported node_modules file: "{fileName}"', { fileName });
1584
+ logger.success('Created tag file: "{file}"', { file: importedFile.pathRelativeToImportDir });
1616
1585
  }
1586
+ }
1587
+ class ImportManager {
1588
+ importedFiles = [];
1589
+ constructor() {
1590
+ this.importedFiles = [];
1591
+ }
1592
+ importTag(pathRelativeToImportDir, tag) {
1593
+ if (!pathRelativeToImportDir) {
1594
+ throw new Error(`pathRelativeToImportDir required, got: ${pathRelativeToImportDir}`);
1595
+ }
1596
+ if (!tag?.variableName) {
1597
+ throw new Error(`tag.variableName required, got: ${tag?.variableName}`);
1598
+ }
1599
+ if (!this.isValidJavaScriptIdentifier(tag.variableName)) {
1600
+ 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.`);
1601
+ }
1602
+ if (tag.translations == null) {
1603
+ throw new Error(`tag.translations required`);
1604
+ }
1605
+ let importedFile = this.importedFiles.find(
1606
+ (file) => file.pathRelativeToImportDir === pathRelativeToImportDir
1607
+ );
1608
+ if (importedFile) {
1609
+ const duplicateTag = importedFile.tags.find(
1610
+ (existingTag) => existingTag.variableName === tag.variableName
1611
+ );
1612
+ if (duplicateTag) {
1613
+ throw new Error(`Duplicate variable name "${tag.variableName}" in file "${pathRelativeToImportDir}". Variable names must be unique within the same file.`);
1614
+ }
1615
+ }
1616
+ if (!importedFile) {
1617
+ importedFile = { pathRelativeToImportDir, tags: [] };
1618
+ this.importedFiles.push(importedFile);
1619
+ }
1620
+ importedFile.tags.push(tag);
1621
+ }
1622
+ getImportedFiles() {
1623
+ return [...this.importedFiles];
1624
+ }
1625
+ getImportedFilesCount() {
1626
+ return this.importedFiles.length;
1627
+ }
1628
+ hasImportedFiles() {
1629
+ return this.importedFiles.length > 0;
1630
+ }
1631
+ isValidJavaScriptIdentifier(name) {
1632
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
1633
+ }
1634
+ }
1635
+ async function $LT_ImportLibraries(config, logger) {
1636
+ const exportFiles = await $LT_CollectExportFiles(logger);
1637
+ const importManager = new ImportManager();
1638
+ let exports2 = [];
1639
+ for (const { exportPath, packageJsonPath } of exportFiles) {
1640
+ const exportData = await flexibleImportAlgorithm.$LT_ReadJSON(exportPath);
1641
+ const packageJSON = await flexibleImportAlgorithm.$LT_ReadJSON(packageJsonPath);
1642
+ exports2.push({ packageJSON, exportData });
1643
+ }
1644
+ config.import.onImport({ exports: exports2, importManager, logger, langTagConfig: config });
1645
+ if (!importManager.hasImportedFiles()) {
1646
+ logger.warn("No tags were imported from any library files");
1647
+ return;
1648
+ }
1649
+ await generateImportFiles(config, logger, importManager);
1617
1650
  if (config.import.onImportFinish) config.import.onImportFinish();
1618
1651
  }
1619
1652
  async function $LT_ImportTranslations() {
1620
1653
  const { config, logger } = await $LT_GetCommandEssentials();
1621
- await $LT_EnsureDirectoryExists(config.import.dir);
1654
+ await flexibleImportAlgorithm.$LT_EnsureDirectoryExists(config.import.dir);
1622
1655
  logger.info("Importing translations from libraries...");
1623
1656
  await $LT_ImportLibraries(config, logger);
1624
1657
  logger.success("Successfully imported translations from libraries.");
1625
1658
  }
1626
- function renderTemplate(template, data) {
1627
- return mustache.render(template, data, {}, { escape: (text) => text });
1659
+ function renderTemplate(template2, data) {
1660
+ return mustache.render(template2, data, {}, { escape: (text) => text });
1628
1661
  }
1629
1662
  function loadTemplate(templateName) {
1630
- const __filename = url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index.cjs", document.baseURI).href);
1631
- const __dirname = path.dirname(__filename);
1632
- const templatePath = path.join(__dirname, "template", `${templateName}.mustache`);
1663
+ const __filename2 = url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename2).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index.cjs", document.baseURI).href);
1664
+ const __dirname = path.dirname(__filename2);
1665
+ const templatePath2 = path.join(__dirname, "templates", "tag", `${templateName}.mustache`);
1633
1666
  try {
1634
- return fs.readFileSync(templatePath, "utf-8");
1667
+ return fs.readFileSync(templatePath2, "utf-8");
1635
1668
  } catch (error) {
1636
1669
  throw new Error(`Failed to load template ${templateName}: ${error}`);
1637
1670
  }
@@ -1719,7 +1752,7 @@ async function $LT_CMD_InitTagFile(options = {}) {
1719
1752
  return;
1720
1753
  }
1721
1754
  try {
1722
- await $LT_WriteFileWithDirs(outputPath, renderedContent);
1755
+ await flexibleImportAlgorithm.$LT_WriteFileWithDirs(outputPath, renderedContent);
1723
1756
  logger.success("Lang-tag file created successfully: {outputPath}", { outputPath });
1724
1757
  logger.info("Next steps:");
1725
1758
  logger.info("1. Import the {tagName} function in your files:", { tagName: renderOptions.tagName });