kythia-core 0.11.0-beta → 0.12.0-beta

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.
Files changed (260) hide show
  1. package/dist/Kythia.d.ts +45 -0
  2. package/dist/Kythia.d.ts.map +1 -0
  3. package/dist/Kythia.js +443 -0
  4. package/dist/Kythia.js.map +1 -0
  5. package/dist/KythiaClient.d.ts +3 -0
  6. package/dist/KythiaClient.d.ts.map +1 -0
  7. package/dist/KythiaClient.js +69 -0
  8. package/dist/KythiaClient.js.map +1 -0
  9. package/dist/cli/Command.d.ts +9 -0
  10. package/dist/cli/Command.d.ts.map +1 -0
  11. package/dist/cli/Command.js +19 -0
  12. package/dist/cli/Command.js.map +1 -0
  13. package/dist/cli/commands/CacheClearCommand.d.ts +8 -0
  14. package/dist/cli/commands/CacheClearCommand.d.ts.map +1 -0
  15. package/dist/cli/commands/CacheClearCommand.js +94 -0
  16. package/dist/cli/commands/CacheClearCommand.js.map +1 -0
  17. package/dist/cli/commands/LangCheckCommand.d.ts +7 -0
  18. package/dist/cli/commands/LangCheckCommand.d.ts.map +1 -0
  19. package/dist/cli/commands/LangCheckCommand.js +345 -0
  20. package/dist/cli/commands/LangCheckCommand.js.map +1 -0
  21. package/dist/cli/commands/LangTranslateCommand.d.ts +8 -0
  22. package/dist/cli/commands/LangTranslateCommand.d.ts.map +1 -0
  23. package/dist/cli/commands/LangTranslateCommand.js +221 -0
  24. package/dist/cli/commands/LangTranslateCommand.js.map +1 -0
  25. package/dist/cli/commands/MakeMigrationCommand.d.ts +7 -0
  26. package/dist/cli/commands/MakeMigrationCommand.d.ts.map +1 -0
  27. package/dist/cli/commands/MakeMigrationCommand.js +55 -0
  28. package/dist/cli/commands/MakeMigrationCommand.js.map +1 -0
  29. package/dist/cli/commands/MakeModelCommand.d.ts +7 -0
  30. package/dist/cli/commands/MakeModelCommand.d.ts.map +1 -0
  31. package/dist/cli/commands/MakeModelCommand.js +56 -0
  32. package/dist/cli/commands/MakeModelCommand.js.map +1 -0
  33. package/dist/cli/commands/MigrateCommand.d.ts +14 -0
  34. package/dist/cli/commands/MigrateCommand.d.ts.map +1 -0
  35. package/dist/cli/commands/MigrateCommand.js +190 -0
  36. package/dist/cli/commands/MigrateCommand.js.map +1 -0
  37. package/dist/cli/commands/NamespaceCommand.d.ts +7 -0
  38. package/dist/cli/commands/NamespaceCommand.d.ts.map +1 -0
  39. package/dist/cli/commands/NamespaceCommand.js +92 -0
  40. package/dist/cli/commands/NamespaceCommand.js.map +1 -0
  41. package/dist/cli/commands/StructureCommand.d.ts +7 -0
  42. package/dist/cli/commands/StructureCommand.d.ts.map +1 -0
  43. package/dist/cli/commands/StructureCommand.js +51 -0
  44. package/dist/cli/commands/StructureCommand.js.map +1 -0
  45. package/dist/cli/commands/UpversionCommand.d.ts +7 -0
  46. package/dist/cli/commands/UpversionCommand.d.ts.map +1 -0
  47. package/dist/cli/commands/UpversionCommand.js +68 -0
  48. package/dist/cli/commands/UpversionCommand.js.map +1 -0
  49. package/dist/cli/index.d.ts +3 -0
  50. package/dist/cli/index.d.ts.map +1 -0
  51. package/dist/cli/index.js +44 -0
  52. package/dist/cli/index.js.map +1 -0
  53. package/dist/cli/utils/db.d.ts +9 -0
  54. package/dist/cli/utils/db.d.ts.map +1 -0
  55. package/dist/cli/utils/db.js +90 -0
  56. package/dist/cli/utils/db.js.map +1 -0
  57. package/dist/database/KythiaMigrator.d.ts +4 -0
  58. package/dist/database/KythiaMigrator.d.ts.map +1 -0
  59. package/dist/database/KythiaMigrator.js +94 -0
  60. package/dist/database/KythiaMigrator.js.map +1 -0
  61. package/dist/database/KythiaModel.d.ts +83 -0
  62. package/dist/database/KythiaModel.d.ts.map +1 -0
  63. package/dist/database/KythiaModel.js +1121 -0
  64. package/dist/database/KythiaModel.js.map +1 -0
  65. package/dist/database/KythiaSequelize.d.ts +4 -0
  66. package/dist/database/KythiaSequelize.d.ts.map +1 -0
  67. package/dist/database/KythiaSequelize.js +99 -0
  68. package/dist/database/KythiaSequelize.js.map +1 -0
  69. package/dist/database/KythiaStorage.d.ts +21 -0
  70. package/dist/database/KythiaStorage.d.ts.map +1 -0
  71. package/dist/database/KythiaStorage.js +80 -0
  72. package/dist/database/KythiaStorage.js.map +1 -0
  73. package/dist/database/ModelLoader.d.ts +4 -0
  74. package/dist/database/ModelLoader.d.ts.map +1 -0
  75. package/dist/database/ModelLoader.js +54 -0
  76. package/dist/database/ModelLoader.js.map +1 -0
  77. package/dist/index.d.ts +10 -0
  78. package/dist/index.d.ts.map +1 -0
  79. package/dist/index.js +36 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/lang/en.json +85 -0
  82. package/dist/managers/AddonManager.d.ts +45 -0
  83. package/dist/managers/AddonManager.d.ts.map +1 -0
  84. package/dist/managers/AddonManager.js +932 -0
  85. package/dist/managers/AddonManager.js.map +1 -0
  86. package/dist/managers/EventManager.d.ts +19 -0
  87. package/dist/managers/EventManager.d.ts.map +1 -0
  88. package/dist/managers/EventManager.js +55 -0
  89. package/dist/managers/EventManager.js.map +1 -0
  90. package/dist/managers/InteractionManager.d.ts +41 -0
  91. package/dist/managers/InteractionManager.d.ts.map +1 -0
  92. package/dist/managers/InteractionManager.js +441 -0
  93. package/dist/managers/InteractionManager.js.map +1 -0
  94. package/dist/managers/MiddlewareManager.d.ts +14 -0
  95. package/dist/managers/MiddlewareManager.d.ts.map +1 -0
  96. package/dist/managers/MiddlewareManager.js +75 -0
  97. package/dist/managers/MiddlewareManager.js.map +1 -0
  98. package/dist/managers/ShutdownManager.d.ts +22 -0
  99. package/dist/managers/ShutdownManager.d.ts.map +1 -0
  100. package/dist/managers/ShutdownManager.js +151 -0
  101. package/dist/managers/ShutdownManager.js.map +1 -0
  102. package/dist/managers/TranslatorManager.d.ts +19 -0
  103. package/dist/managers/TranslatorManager.d.ts.map +1 -0
  104. package/dist/managers/TranslatorManager.js +118 -0
  105. package/dist/managers/TranslatorManager.js.map +1 -0
  106. package/dist/middlewares/botPermissions.d.ts +4 -0
  107. package/dist/middlewares/botPermissions.d.ts.map +1 -0
  108. package/dist/middlewares/botPermissions.js +28 -0
  109. package/dist/middlewares/botPermissions.js.map +1 -0
  110. package/dist/middlewares/cooldown.d.ts +4 -0
  111. package/dist/middlewares/cooldown.d.ts.map +1 -0
  112. package/dist/middlewares/cooldown.js +42 -0
  113. package/dist/middlewares/cooldown.js.map +1 -0
  114. package/dist/middlewares/isInMainGuild.d.ts +4 -0
  115. package/dist/middlewares/isInMainGuild.d.ts.map +1 -0
  116. package/dist/middlewares/isInMainGuild.js +52 -0
  117. package/dist/middlewares/isInMainGuild.js.map +1 -0
  118. package/dist/middlewares/ownerOnly.d.ts +4 -0
  119. package/dist/middlewares/ownerOnly.d.ts.map +1 -0
  120. package/dist/middlewares/ownerOnly.js +24 -0
  121. package/dist/middlewares/ownerOnly.js.map +1 -0
  122. package/dist/middlewares/teamOnly.d.ts +4 -0
  123. package/dist/middlewares/teamOnly.d.ts.map +1 -0
  124. package/dist/middlewares/teamOnly.js +26 -0
  125. package/dist/middlewares/teamOnly.js.map +1 -0
  126. package/dist/middlewares/userPermissions.d.ts +4 -0
  127. package/dist/middlewares/userPermissions.d.ts.map +1 -0
  128. package/dist/middlewares/userPermissions.js +28 -0
  129. package/dist/middlewares/userPermissions.js.map +1 -0
  130. package/dist/middlewares/voteLocked.d.ts +4 -0
  131. package/dist/middlewares/voteLocked.d.ts.map +1 -0
  132. package/dist/middlewares/voteLocked.js +50 -0
  133. package/dist/middlewares/voteLocked.js.map +1 -0
  134. package/dist/structures/BaseCommand.d.ts +23 -0
  135. package/dist/structures/BaseCommand.d.ts.map +1 -0
  136. package/dist/structures/BaseCommand.js +42 -0
  137. package/dist/structures/BaseCommand.js.map +1 -0
  138. package/dist/types/AddonManager.d.ts +58 -0
  139. package/dist/types/AddonManager.d.ts.map +1 -0
  140. package/dist/types/AddonManager.js +3 -0
  141. package/dist/types/AddonManager.js.map +1 -0
  142. package/dist/types/DiscordHelpers.d.ts +7 -0
  143. package/dist/types/DiscordHelpers.d.ts.map +1 -0
  144. package/dist/types/DiscordHelpers.js +3 -0
  145. package/dist/types/DiscordHelpers.js.map +1 -0
  146. package/dist/types/EventManager.d.ts +10 -0
  147. package/dist/types/EventManager.d.ts.map +1 -0
  148. package/dist/types/EventManager.js +3 -0
  149. package/dist/types/EventManager.js.map +1 -0
  150. package/dist/types/InteractionManager.d.ts +35 -0
  151. package/dist/types/InteractionManager.d.ts.map +1 -0
  152. package/dist/types/InteractionManager.js +3 -0
  153. package/dist/types/InteractionManager.js.map +1 -0
  154. package/dist/types/KythiaClient.d.ts +9 -0
  155. package/dist/types/KythiaClient.d.ts.map +1 -0
  156. package/dist/types/KythiaClient.js +3 -0
  157. package/dist/types/KythiaClient.js.map +1 -0
  158. package/dist/types/KythiaConfig.d.ts +291 -0
  159. package/dist/types/KythiaConfig.d.ts.map +1 -0
  160. package/dist/types/KythiaConfig.js +3 -0
  161. package/dist/types/KythiaConfig.js.map +1 -0
  162. package/dist/types/KythiaContainer.d.ts +38 -0
  163. package/dist/types/KythiaContainer.d.ts.map +1 -0
  164. package/dist/types/KythiaContainer.js +3 -0
  165. package/dist/types/KythiaContainer.js.map +1 -0
  166. package/dist/types/KythiaLogger.d.ts +5 -0
  167. package/dist/types/KythiaLogger.d.ts.map +1 -0
  168. package/dist/types/KythiaLogger.js +3 -0
  169. package/dist/types/KythiaLogger.js.map +1 -0
  170. package/dist/types/KythiaMigrator.d.ts +9 -0
  171. package/dist/types/KythiaMigrator.d.ts.map +1 -0
  172. package/dist/types/KythiaMigrator.js +3 -0
  173. package/dist/types/KythiaMigrator.js.map +1 -0
  174. package/dist/types/KythiaModel.d.ts +31 -0
  175. package/dist/types/KythiaModel.d.ts.map +1 -0
  176. package/dist/types/KythiaModel.js +3 -0
  177. package/dist/types/KythiaModel.js.map +1 -0
  178. package/dist/types/KythiaOptions.d.ts +13 -0
  179. package/dist/types/KythiaOptions.d.ts.map +1 -0
  180. package/dist/types/KythiaOptions.js +3 -0
  181. package/dist/types/KythiaOptions.js.map +1 -0
  182. package/dist/types/KythiaSequelize.d.ts +13 -0
  183. package/dist/types/KythiaSequelize.d.ts.map +1 -0
  184. package/dist/types/KythiaSequelize.js +3 -0
  185. package/dist/types/KythiaSequelize.js.map +1 -0
  186. package/dist/types/KythiaStorage.d.ts +22 -0
  187. package/dist/types/KythiaStorage.d.ts.map +1 -0
  188. package/dist/types/KythiaStorage.js +3 -0
  189. package/dist/types/KythiaStorage.js.map +1 -0
  190. package/dist/types/MiddlewareManager.d.ts +14 -0
  191. package/dist/types/MiddlewareManager.d.ts.map +1 -0
  192. package/dist/types/MiddlewareManager.js +3 -0
  193. package/dist/types/MiddlewareManager.js.map +1 -0
  194. package/dist/types/ModelLoader.d.ts +8 -0
  195. package/dist/types/ModelLoader.d.ts.map +1 -0
  196. package/dist/types/ModelLoader.js +3 -0
  197. package/dist/types/ModelLoader.js.map +1 -0
  198. package/dist/types/ShutdownManager.d.ts +15 -0
  199. package/dist/types/ShutdownManager.d.ts.map +1 -0
  200. package/dist/types/ShutdownManager.js +3 -0
  201. package/dist/types/ShutdownManager.js.map +1 -0
  202. package/dist/types/TranslatorManager.d.ts +16 -0
  203. package/dist/types/TranslatorManager.d.ts.map +1 -0
  204. package/dist/types/TranslatorManager.js +3 -0
  205. package/dist/types/TranslatorManager.js.map +1 -0
  206. package/dist/types/index.d.ts +13 -0
  207. package/dist/types/index.d.ts.map +1 -0
  208. package/dist/types/index.js +29 -0
  209. package/dist/types/index.js.map +1 -0
  210. package/dist/utils/color.d.ts +15 -0
  211. package/dist/utils/color.d.ts.map +1 -0
  212. package/dist/utils/color.js +156 -0
  213. package/dist/utils/color.js.map +1 -0
  214. package/dist/utils/discord.d.ts +8 -0
  215. package/dist/utils/discord.d.ts.map +1 -0
  216. package/dist/utils/discord.js +53 -0
  217. package/dist/utils/discord.js.map +1 -0
  218. package/dist/utils/formatter.d.ts +3 -0
  219. package/dist/utils/formatter.d.ts.map +1 -0
  220. package/dist/utils/formatter.js +89 -0
  221. package/dist/utils/formatter.js.map +1 -0
  222. package/dist/utils/index.d.ts +12 -0
  223. package/dist/utils/index.d.ts.map +1 -0
  224. package/dist/utils/index.js +54 -0
  225. package/dist/utils/index.js.map +1 -0
  226. package/dist/utils/logger.d.ts +5 -0
  227. package/dist/utils/logger.d.ts.map +1 -0
  228. package/dist/utils/logger.js +150 -0
  229. package/dist/utils/logger.js.map +1 -0
  230. package/package.json +28 -6
  231. package/src/lang/en.json +85 -0
  232. package/changelog.md +0 -53
  233. package/index.js +0 -15
  234. package/src/Kythia.js +0 -556
  235. package/src/KythiaClient.js +0 -94
  236. package/src/cli/Command.js +0 -68
  237. package/src/cli/commands/CacheClearCommand.js +0 -136
  238. package/src/cli/commands/LangCheckCommand.js +0 -367
  239. package/src/cli/commands/LangTranslateCommand.js +0 -336
  240. package/src/cli/commands/MakeMigrationCommand.js +0 -82
  241. package/src/cli/commands/MakeModelCommand.js +0 -81
  242. package/src/cli/commands/MigrateCommand.js +0 -259
  243. package/src/cli/commands/NamespaceCommand.js +0 -112
  244. package/src/cli/commands/StructureCommand.js +0 -70
  245. package/src/cli/commands/UpversionCommand.js +0 -94
  246. package/src/cli/index.js +0 -69
  247. package/src/cli/utils/db.js +0 -117
  248. package/src/database/KythiaMigrator.js +0 -116
  249. package/src/database/KythiaModel.js +0 -1557
  250. package/src/database/KythiaSequelize.js +0 -128
  251. package/src/database/KythiaStorage.js +0 -117
  252. package/src/database/ModelLoader.js +0 -79
  253. package/src/managers/AddonManager.js +0 -1219
  254. package/src/managers/EventManager.js +0 -104
  255. package/src/managers/InteractionManager.js +0 -815
  256. package/src/managers/ShutdownManager.js +0 -218
  257. package/src/structures/BaseCommand.js +0 -53
  258. package/src/utils/color.js +0 -180
  259. package/src/utils/formatter.js +0 -99
  260. package/src/utils/index.js +0 -4
@@ -1,136 +0,0 @@
1
- /**
2
- * 🧹 Redis Cache Flusher
3
- *
4
- * @file src/cli/commands/CacheClearCommand.js
5
- * @copyright © 2025 kenndeclouv
6
- * @assistant chaa & graa
7
- * @version 0.11.0-beta
8
- *
9
- * @description
10
- * Interactive utility to flush Redis cache. Supports intelligent handling of
11
- * multiple Redis instances defined in environment variables.
12
- *
13
- * ✨ Core Features:
14
- * - Multi-Target: Detects and lists all Redis URLs from config.
15
- * - Safety First: Requires explicit confirmation before flushing.
16
- * - Target Selection: Allows flushing specific instances or all at once.
17
- */
18
-
19
- const Command = require('../Command');
20
- const pc = require('picocolors');
21
- const readline = require('node:readline');
22
- const Redis = require('ioredis');
23
- require('@dotenvx/dotenvx/config');
24
-
25
- function askQuestion(query) {
26
- const rl = readline.createInterface({
27
- input: process.stdin,
28
- output: process.stdout,
29
- });
30
- return new Promise((resolve) =>
31
- rl.question(query, (ans) => {
32
- rl.close();
33
- resolve(ans);
34
- }),
35
- );
36
- }
37
-
38
- class CacheClearCommand extends Command {
39
- signature = 'cache:clear';
40
- description = 'Flush Redis cache (supports multi-instance selection)';
41
-
42
- async handle() {
43
- console.log(pc.dim('🔍 Detecting Redis configuration...'));
44
-
45
- const redisUrlsRaw = process.env.REDIS_URLS;
46
-
47
- if (!redisUrlsRaw) {
48
- console.error(pc.red('❌ REDIS_URLS not found in .env'));
49
- process.exit(1);
50
- }
51
-
52
- const urls = redisUrlsRaw
53
- .split(',')
54
- .map((u) => u.trim())
55
- .filter((u) => u.length > 0);
56
-
57
- if (urls.length === 0) {
58
- console.error(pc.red('❌ No valid Redis URLs found.'));
59
- process.exit(1);
60
- }
61
-
62
- let targets = [];
63
-
64
- if (urls.length === 1) {
65
- targets = [urls[0]];
66
- console.log(pc.cyan(`🎯 Target: ${targets[0]}`));
67
- } else {
68
- console.log(
69
- pc.yellow(`⚠️ Multiple Redis instances detected (${urls.length}):`),
70
- );
71
- console.log(
72
- pc.dim('---------------------------------------------------'),
73
- );
74
- console.log(`0. ${pc.bgRed(pc.white(' FLUSH ALL INSTANCES '))}`);
75
- urls.forEach((url, index) => {
76
- const maskedUrl = url.replace(/:([^@]+)@/, ':****@');
77
- console.log(`${index + 1}. ${maskedUrl}`);
78
- });
79
- console.log(
80
- pc.dim('---------------------------------------------------'),
81
- );
82
-
83
- const answer = await askQuestion(
84
- pc.cyan('Select target to flush (number): '),
85
- );
86
- const choice = parseInt(answer, 10);
87
-
88
- if (Number.isNaN(choice) || choice < 0 || choice > urls.length) {
89
- console.error(pc.red('❌ Invalid selection.'));
90
- process.exit(1);
91
- }
92
-
93
- if (choice === 0) {
94
- targets = urls;
95
- } else {
96
- targets = [urls[choice - 1]];
97
- }
98
- }
99
-
100
- const confirm = await askQuestion(
101
- pc.bgRed(pc.white(' DANGER ')) +
102
- pc.yellow(
103
- ` Are you sure you want to FLUSHALL ${targets.length} instance(s)? (y/n): `,
104
- ),
105
- );
106
-
107
- if (confirm.toLowerCase() !== 'y' && confirm.toLowerCase() !== 'yes') {
108
- console.log(pc.cyan('🛡️ Operation cancelled.'));
109
- process.exit(0);
110
- }
111
-
112
- console.log('');
113
- for (const url of targets) {
114
- const masked = url.replace(/:([^@]+)@/, ':****@');
115
- try {
116
- console.log(pc.dim(`🔌 Connecting to ${masked}...`));
117
- const redis = new Redis(url, {
118
- maxRetriesPerRequest: 1,
119
- retryStrategy: null,
120
- });
121
-
122
- await redis.flushall();
123
- console.log(pc.green(`✅ FLUSHALL Success: ${masked}`));
124
-
125
- redis.quit();
126
- } catch (err) {
127
- console.error(pc.red(`❌ Failed to flush ${masked}: ${err.message}`));
128
- }
129
- }
130
-
131
- console.log(pc.green('\n✨ Cache clearing process completed.'));
132
- process.exit(0);
133
- }
134
- }
135
-
136
- module.exports = CacheClearCommand;
@@ -1,367 +0,0 @@
1
- /**
2
- * 🕵️‍♂️ Translation Integrity Linter
3
- *
4
- * @file src/cli/commands/LangCheckCommand.js
5
- * @copyright © 2025 kenndeclouv
6
- * @assistant chaa & graa
7
- * @version 0.11.0-beta
8
- *
9
- * @description
10
- * Performs a deep AST analysis of the codebase to find `t()` translation function calls.
11
- * Verifies that every used key exists in the language files (JSON) and reports usage errors.
12
- *
13
- * ✨ Core Features:
14
- * - AST Parsing: Uses Babel parser for accurate key detection (handles dynamic patterns).
15
- * - Key Verification: Recursively checks nested JSON structures.
16
- * - Unused Key Detection: Reports keys defined in JSON but never used in code.
17
- */
18
-
19
- const Command = require('../Command');
20
- const fs = require('node:fs');
21
- const path = require('node:path');
22
- const glob = require('glob');
23
- const parser = require('@babel/parser');
24
- const traverse = require('@babel/traverse').default;
25
-
26
- function getAllKeys(obj, prefix = '') {
27
- Object.keys(obj).forEach((key) => {
28
- if (key === '_value' || key === 'text') {
29
- if (Object.keys(obj).length === 1) return;
30
- if (prefix) allDefinedKeys.add(prefix);
31
- return;
32
- }
33
- const fullKey = prefix ? `${prefix}.${key}` : key;
34
- if (typeof obj[key] === 'object' && obj[key] !== null) {
35
- if (key !== 'jobs' && key !== 'shop') {
36
- getAllKeys(obj[key], fullKey);
37
- } else {
38
- allDefinedKeys.add(fullKey);
39
- }
40
- } else {
41
- allDefinedKeys.add(fullKey);
42
- }
43
- });
44
- }
45
-
46
- class LangCheckCommand extends Command {
47
- signature = 'lang:check';
48
- description =
49
- 'Lint translation key usage in code and language files (AST-based)';
50
-
51
- async handle() {
52
- const PROJECT_ROOT = path.join(__dirname, '..', '..', '..');
53
- const SCAN_DIRECTORIES = ['addons', 'src'];
54
- const LANG_DIR = path.join(PROJECT_ROOT, 'src', 'lang');
55
- const DEFAULT_LANG = 'en';
56
- const IGNORE_PATTERNS = [
57
- '**/node_modules/**',
58
- '**/dist/**',
59
- '**/tests/**',
60
- '**/assets/**',
61
- '**/dashboard/web/public/**',
62
- '**/temp/**',
63
- '**/leetMap.js',
64
- '**/generate_*.js',
65
- '**/refactor_*.js',
66
- '**/undo_*.js',
67
- '**/*.d.ts',
68
- ];
69
-
70
- const locales = {};
71
- const usedStaticKeys = new Set();
72
- const usedDynamicKeys = new Set();
73
- const unanalyzableKeys = new Set();
74
- let filesScanned = 0;
75
- let filesWithErrors = 0;
76
-
77
- console.log('--- Kythia AST Translation Linter ---');
78
-
79
- function hasNestedKey(obj, pathExpr) {
80
- if (!obj || !pathExpr) return false;
81
- const parts = pathExpr.split('.');
82
- let current = obj;
83
- for (const part of parts) {
84
- if (
85
- typeof current !== 'object' ||
86
- current === null ||
87
- !Object.hasOwn(current, part)
88
- ) {
89
- return false;
90
- }
91
- current = current[part];
92
- }
93
- return true;
94
- }
95
-
96
- function _loadLocales() {
97
- console.log(`\n🔍 Reading language files from: ${LANG_DIR}`);
98
- try {
99
- const langFiles = fs
100
- .readdirSync(LANG_DIR)
101
- .filter(
102
- (file) =>
103
- file.endsWith('.json') &&
104
- !file.includes('_flat') &&
105
- !file.includes('_FLAT'),
106
- );
107
- if (langFiles.length === 0) {
108
- console.error(
109
- '\x1b[31m%s\x1b[0m',
110
- '❌ No .json files found in the language folder.',
111
- );
112
- return false;
113
- }
114
- for (const file of langFiles) {
115
- const lang = file.replace('.json', '');
116
- const content = fs.readFileSync(path.join(LANG_DIR, file), 'utf8');
117
- try {
118
- locales[lang] = JSON.parse(content);
119
- console.log(` > Successfully loaded: ${file}`);
120
- } catch (jsonError) {
121
- console.error(
122
- `\x1b[31m%s\x1b[0m`,
123
- `❌ Failed to parse JSON: ${file} - ${jsonError.message}`,
124
- );
125
- filesWithErrors++;
126
- }
127
- }
128
- if (!locales[DEFAULT_LANG]) {
129
- console.error(
130
- `\x1b[31m%s\x1b[0m`,
131
- `❌ Default language (${DEFAULT_LANG}) not found!`,
132
- );
133
- return false;
134
- }
135
- return true;
136
- } catch (error) {
137
- console.error(
138
- '\x1b[31m%s\x1b[0m',
139
- `❌ Failed to load language files: ${error.message}`,
140
- );
141
- return false;
142
- }
143
- }
144
-
145
- if (!_loadLocales()) {
146
- console.error('\x1b[31mCannot proceed (language files invalid).\x1b[0m');
147
- process.exit(1);
148
- }
149
-
150
- console.log(
151
- `\nScanning .js/.ts files in: ${SCAN_DIRECTORIES.join(', ')}...`,
152
- );
153
- SCAN_DIRECTORIES.forEach((dirName) => {
154
- const dirPath = path.join(PROJECT_ROOT, dirName);
155
- const files = glob.sync(`${dirPath}/**/*.{js,ts}`, {
156
- ignore: IGNORE_PATTERNS,
157
- dot: true,
158
- });
159
- files.forEach((filePath) => {
160
- filesScanned++;
161
- process.stdout.write(`\rScanning: ${filesScanned} files...`);
162
-
163
- try {
164
- const code = fs.readFileSync(filePath, 'utf8');
165
- const ast = parser.parse(code, {
166
- sourceType: 'module',
167
- plugins: [
168
- 'typescript',
169
- 'jsx',
170
- 'classProperties',
171
- 'objectRestSpread',
172
- ],
173
- errorRecovery: true,
174
- });
175
-
176
- traverse(ast, {
177
- CallExpression(nodePath) {
178
- const node = nodePath.node;
179
- if (
180
- node.callee.type === 'Identifier' &&
181
- node.callee.name === 't'
182
- ) {
183
- if (node.arguments.length >= 2) {
184
- const keyArg = node.arguments[1];
185
- if (keyArg.type === 'StringLiteral') {
186
- usedStaticKeys.add(keyArg.value);
187
- } else if (keyArg.type === 'TemplateLiteral') {
188
- let pattern = '';
189
- keyArg.quasis.forEach((quasi, _i) => {
190
- pattern += quasi.value.raw;
191
- if (!quasi.tail) {
192
- pattern += '*';
193
- }
194
- });
195
- pattern = pattern.replace(/_/g, '.');
196
- usedDynamicKeys.add(pattern);
197
- } else if (
198
- keyArg.type === 'BinaryExpression' &&
199
- keyArg.operator === '+'
200
- ) {
201
- if (keyArg.left.type === 'StringLiteral') {
202
- const pattern = `${keyArg.left.value.replace(/_/g, '.')}*`;
203
- usedDynamicKeys.add(pattern);
204
- } else {
205
- unanalyzableKeys.add(
206
- `Complex (+) at ${path.relative(PROJECT_ROOT, filePath)}:${node.loc?.start.line}`,
207
- );
208
- }
209
- } else {
210
- unanalyzableKeys.add(
211
- `Variable/Other at ${path.relative(PROJECT_ROOT, filePath)}:${node.loc?.start.line}`,
212
- );
213
- }
214
- }
215
- }
216
- },
217
- });
218
- } catch (parseError) {
219
- if (parseError.message.includes('Unexpected token')) {
220
- console.warn(
221
- `\n\x1b[33m[WARN] Syntax Error parsing ${path.relative(
222
- PROJECT_ROOT,
223
- filePath,
224
- )}:${parseError.loc?.line} - ${parseError.message}\x1b[0m`,
225
- );
226
- } else {
227
- console.error(
228
- `\n\x1b[31m[ERROR] Failed to parse ${path.relative(
229
- PROJECT_ROOT,
230
- filePath,
231
- )}: ${parseError.message}\x1b[0m`,
232
- );
233
- }
234
- filesWithErrors++;
235
- }
236
- });
237
- });
238
- process.stdout.write(`${'\r'.padEnd(process.stdout.columns || 60)}\r`);
239
-
240
- console.log(`\nScan completed. Total ${filesScanned} files processed.`);
241
- console.log(` > Found \x1b[33m${usedStaticKeys.size}\x1b[0m static keys.`);
242
- console.log(
243
- ` > Found \x1b[33m${usedDynamicKeys.size}\x1b[0m dynamic key patterns (check manually!).`,
244
- );
245
-
246
- if (unanalyzableKeys.size > 0) {
247
- console.log(
248
- ` > \x1b[31m${unanalyzableKeys.size}\x1b[0m t() calls could not be analyzed (variable/complex).`,
249
- );
250
- }
251
-
252
- console.log('\nVerifying static keys against language files...');
253
-
254
- let totalMissingStatic = 0;
255
- for (const lang in locales) {
256
- const missingInLang = [];
257
- for (const staticKey of usedStaticKeys) {
258
- if (!hasNestedKey(locales[lang], staticKey)) {
259
- missingInLang.push(staticKey);
260
- }
261
- }
262
- if (missingInLang.length > 0) {
263
- console.log(
264
- `\n❌ \x1b[31m[${lang.toUpperCase()}] Found ${missingInLang.length} missing static keys:\x1b[0m`,
265
- );
266
- missingInLang.sort().forEach((key) => {
267
- console.log(` - ${key}`);
268
- });
269
- totalMissingStatic += missingInLang.length;
270
- filesWithErrors++;
271
- } else {
272
- console.log(
273
- `\n✅ \x1b[32m[${lang.toUpperCase()}] All static keys found!\x1b[0m`,
274
- );
275
- }
276
- }
277
-
278
- if (usedDynamicKeys.size > 0) {
279
- console.log(
280
- `\n\n⚠️ \x1b[33mDynamic Key Patterns Detected (Check Manually):\x1b[0m`,
281
- );
282
- [...usedDynamicKeys].sort().forEach((pattern) => {
283
- console.log(` - ${pattern}`);
284
- });
285
- console.log(
286
- ` (Ensure all possible keys from these patterns exist in the language files)`,
287
- );
288
- }
289
-
290
- if (unanalyzableKeys.size > 0) {
291
- console.log(
292
- `\n\n⚠️ \x1b[31mComplex/Unanalyzable t() Calls (Check Manually):\x1b[0m`,
293
- );
294
- [...unanalyzableKeys].sort().forEach((loc) => {
295
- console.log(` - ${loc}`);
296
- });
297
- }
298
-
299
- console.log(`\nChecking UNUSED keys (based on ${DEFAULT_LANG}.json)...`);
300
-
301
- const defaultLocale = locales[DEFAULT_LANG];
302
- const allDefinedKeys = new Set();
303
-
304
- if (defaultLocale) {
305
- try {
306
- getAllKeys(defaultLocale);
307
- } catch (e) {
308
- console.error('Error collecting defined keys:', e);
309
- }
310
-
311
- const unusedKeys = [];
312
- for (const definedKey of allDefinedKeys) {
313
- if (!usedStaticKeys.has(definedKey)) {
314
- let matchedByDynamic = false;
315
- for (const dynamicPattern of usedDynamicKeys) {
316
- const regexPattern = `^${dynamicPattern
317
- .replace(/\./g, '\\.')
318
- .replace(/\*/g, '[^.]+?')}$`;
319
- if (new RegExp(regexPattern).test(definedKey)) {
320
- matchedByDynamic = true;
321
- break;
322
- }
323
- }
324
- if (!matchedByDynamic) {
325
- unusedKeys.push(definedKey);
326
- }
327
- }
328
- }
329
- if (unusedKeys.length > 0) {
330
- console.log(
331
- `\n⚠️ \x1b[33mFound ${unusedKeys.length} UNUSED keys in ${DEFAULT_LANG}.json (don't match static/dynamic patterns):\x1b[0m`,
332
- );
333
- unusedKeys.sort().forEach((key) => {
334
- console.log(` - ${key}`);
335
- });
336
- } else {
337
- console.log(
338
- `\n✅ \x1b[32m[${DEFAULT_LANG.toUpperCase()}] No unused keys found.\x1b[0m`,
339
- );
340
- }
341
- } else {
342
- console.warn(
343
- `\n\x1b[33m[WARN] Cannot check unused keys because ${DEFAULT_LANG}.json failed to load.\x1b[0m`,
344
- );
345
- }
346
-
347
- console.log('\n--- Done ---');
348
-
349
- if (filesWithErrors > 0 || totalMissingStatic > 0) {
350
- console.log(
351
- `\x1b[31mTotal ${totalMissingStatic} missing static key errors + ${filesWithErrors - totalMissingStatic} file errors found. Please fix them.\x1b[0m`,
352
- );
353
- process.exit(1);
354
- } else {
355
- console.log(
356
- '\x1b[32mCongratulations! Language files (for static keys) are already synced with the code.\x1b[0m',
357
- );
358
- if (usedDynamicKeys.size > 0 || unanalyzableKeys.size > 0) {
359
- console.log(
360
- "\x1b[33mHowever, don't forget to manually check the reported dynamic/complex keys above!\x1b[0m",
361
- );
362
- }
363
- }
364
- }
365
- }
366
-
367
- module.exports = LangCheckCommand;