ai-i18n-tools 1.0.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.
Files changed (260) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +157 -0
  3. package/dist/api/openrouter.d.ts +115 -0
  4. package/dist/api/openrouter.d.ts.map +1 -0
  5. package/dist/api/openrouter.js +399 -0
  6. package/dist/api/openrouter.js.map +1 -0
  7. package/dist/cli/doc-translate.d.ts +90 -0
  8. package/dist/cli/doc-translate.d.ts.map +1 -0
  9. package/dist/cli/doc-translate.js +1153 -0
  10. package/dist/cli/doc-translate.js.map +1 -0
  11. package/dist/cli/export-ui-xliff.d.ts +32 -0
  12. package/dist/cli/export-ui-xliff.d.ts.map +1 -0
  13. package/dist/cli/export-ui-xliff.js +153 -0
  14. package/dist/cli/export-ui-xliff.js.map +1 -0
  15. package/dist/cli/extract-strings.d.ts +12 -0
  16. package/dist/cli/extract-strings.d.ts.map +1 -0
  17. package/dist/cli/extract-strings.js +80 -0
  18. package/dist/cli/extract-strings.js.map +1 -0
  19. package/dist/cli/file-utils.d.ts +10 -0
  20. package/dist/cli/file-utils.d.ts.map +1 -0
  21. package/dist/cli/file-utils.js +77 -0
  22. package/dist/cli/file-utils.js.map +1 -0
  23. package/dist/cli/format.d.ts +21 -0
  24. package/dist/cli/format.d.ts.map +1 -0
  25. package/dist/cli/format.js +75 -0
  26. package/dist/cli/format.js.map +1 -0
  27. package/dist/cli/helpers.d.ts +27 -0
  28. package/dist/cli/helpers.d.ts.map +1 -0
  29. package/dist/cli/helpers.js +84 -0
  30. package/dist/cli/helpers.js.map +1 -0
  31. package/dist/cli/index.d.ts +3 -0
  32. package/dist/cli/index.d.ts.map +1 -0
  33. package/dist/cli/index.js +772 -0
  34. package/dist/cli/index.js.map +1 -0
  35. package/dist/cli/log-output.d.ts +13 -0
  36. package/dist/cli/log-output.d.ts.map +1 -0
  37. package/dist/cli/log-output.js +75 -0
  38. package/dist/cli/log-output.js.map +1 -0
  39. package/dist/cli/translate-svg.d.ts +7 -0
  40. package/dist/cli/translate-svg.d.ts.map +1 -0
  41. package/dist/cli/translate-svg.js +167 -0
  42. package/dist/cli/translate-svg.js.map +1 -0
  43. package/dist/cli/translate-ui-strings.d.ts +27 -0
  44. package/dist/cli/translate-ui-strings.d.ts.map +1 -0
  45. package/dist/cli/translate-ui-strings.js +357 -0
  46. package/dist/cli/translate-ui-strings.js.map +1 -0
  47. package/dist/core/cache-tracking-keys.d.ts +12 -0
  48. package/dist/core/cache-tracking-keys.d.ts.map +1 -0
  49. package/dist/core/cache-tracking-keys.js +20 -0
  50. package/dist/core/cache-tracking-keys.js.map +1 -0
  51. package/dist/core/cache.d.ts +153 -0
  52. package/dist/core/cache.d.ts.map +1 -0
  53. package/dist/core/cache.js +546 -0
  54. package/dist/core/cache.js.map +1 -0
  55. package/dist/core/config.d.ts +58 -0
  56. package/dist/core/config.d.ts.map +1 -0
  57. package/dist/core/config.js +392 -0
  58. package/dist/core/config.js.map +1 -0
  59. package/dist/core/doc-file-tracking.d.ts +8 -0
  60. package/dist/core/doc-file-tracking.d.ts.map +1 -0
  61. package/dist/core/doc-file-tracking.js +27 -0
  62. package/dist/core/doc-file-tracking.js.map +1 -0
  63. package/dist/core/errors.d.ts +19 -0
  64. package/dist/core/errors.d.ts.map +1 -0
  65. package/dist/core/errors.js +23 -0
  66. package/dist/core/errors.js.map +1 -0
  67. package/dist/core/locale-utils.d.ts +20 -0
  68. package/dist/core/locale-utils.d.ts.map +1 -0
  69. package/dist/core/locale-utils.js +75 -0
  70. package/dist/core/locale-utils.js.map +1 -0
  71. package/dist/core/output-paths.d.ts +22 -0
  72. package/dist/core/output-paths.d.ts.map +1 -0
  73. package/dist/core/output-paths.js +130 -0
  74. package/dist/core/output-paths.js.map +1 -0
  75. package/dist/core/prompt-builder.d.ts +62 -0
  76. package/dist/core/prompt-builder.d.ts.map +1 -0
  77. package/dist/core/prompt-builder.js +232 -0
  78. package/dist/core/prompt-builder.js.map +1 -0
  79. package/dist/core/prompts.d.ts +27 -0
  80. package/dist/core/prompts.d.ts.map +1 -0
  81. package/dist/core/prompts.js +57 -0
  82. package/dist/core/prompts.js.map +1 -0
  83. package/dist/core/svg-asset-paths.d.ts +40 -0
  84. package/dist/core/svg-asset-paths.d.ts.map +1 -0
  85. package/dist/core/svg-asset-paths.js +107 -0
  86. package/dist/core/svg-asset-paths.js.map +1 -0
  87. package/dist/core/types.d.ts +388 -0
  88. package/dist/core/types.d.ts.map +1 -0
  89. package/dist/core/types.js +265 -0
  90. package/dist/core/types.js.map +1 -0
  91. package/dist/core/ui-languages.d.ts +66 -0
  92. package/dist/core/ui-languages.d.ts.map +1 -0
  93. package/dist/core/ui-languages.js +277 -0
  94. package/dist/core/ui-languages.js.map +1 -0
  95. package/dist/core/user-edited-model.d.ts +3 -0
  96. package/dist/core/user-edited-model.d.ts.map +1 -0
  97. package/dist/core/user-edited-model.js +3 -0
  98. package/dist/core/user-edited-model.js.map +1 -0
  99. package/dist/edit-cache-app/app.js +1326 -0
  100. package/dist/edit-cache-app/index.html +287 -0
  101. package/dist/edit-cache-app/styles.css +664 -0
  102. package/dist/extractors/base-extractor.d.ts +15 -0
  103. package/dist/extractors/base-extractor.d.ts.map +1 -0
  104. package/dist/extractors/base-extractor.js +23 -0
  105. package/dist/extractors/base-extractor.js.map +1 -0
  106. package/dist/extractors/classify-segment.d.ts +6 -0
  107. package/dist/extractors/classify-segment.d.ts.map +1 -0
  108. package/dist/extractors/classify-segment.js +20 -0
  109. package/dist/extractors/classify-segment.js.map +1 -0
  110. package/dist/extractors/json-extractor.d.ts +16 -0
  111. package/dist/extractors/json-extractor.d.ts.map +1 -0
  112. package/dist/extractors/json-extractor.js +128 -0
  113. package/dist/extractors/json-extractor.js.map +1 -0
  114. package/dist/extractors/markdown-extractor.d.ts +15 -0
  115. package/dist/extractors/markdown-extractor.d.ts.map +1 -0
  116. package/dist/extractors/markdown-extractor.js +205 -0
  117. package/dist/extractors/markdown-extractor.js.map +1 -0
  118. package/dist/extractors/svg-extractor.d.ts +19 -0
  119. package/dist/extractors/svg-extractor.d.ts.map +1 -0
  120. package/dist/extractors/svg-extractor.js +132 -0
  121. package/dist/extractors/svg-extractor.js.map +1 -0
  122. package/dist/extractors/ui-string-extractor.d.ts +40 -0
  123. package/dist/extractors/ui-string-extractor.d.ts.map +1 -0
  124. package/dist/extractors/ui-string-extractor.js +146 -0
  125. package/dist/extractors/ui-string-extractor.js.map +1 -0
  126. package/dist/extractors/ui-string-locations.d.ts +23 -0
  127. package/dist/extractors/ui-string-locations.d.ts.map +1 -0
  128. package/dist/extractors/ui-string-locations.js +138 -0
  129. package/dist/extractors/ui-string-locations.js.map +1 -0
  130. package/dist/glossary/glossary.d.ts +34 -0
  131. package/dist/glossary/glossary.d.ts.map +1 -0
  132. package/dist/glossary/glossary.js +260 -0
  133. package/dist/glossary/glossary.js.map +1 -0
  134. package/dist/glossary/matcher.d.ts +10 -0
  135. package/dist/glossary/matcher.d.ts.map +1 -0
  136. package/dist/glossary/matcher.js +12 -0
  137. package/dist/glossary/matcher.js.map +1 -0
  138. package/dist/index.d.ts +44 -0
  139. package/dist/index.d.ts.map +1 -0
  140. package/dist/index.js +44 -0
  141. package/dist/index.js.map +1 -0
  142. package/dist/processors/admonition-placeholders.d.ts +8 -0
  143. package/dist/processors/admonition-placeholders.d.ts.map +1 -0
  144. package/dist/processors/admonition-placeholders.js +59 -0
  145. package/dist/processors/admonition-placeholders.js.map +1 -0
  146. package/dist/processors/anchor-placeholders.d.ts +8 -0
  147. package/dist/processors/anchor-placeholders.d.ts.map +1 -0
  148. package/dist/processors/anchor-placeholders.js +37 -0
  149. package/dist/processors/anchor-placeholders.js.map +1 -0
  150. package/dist/processors/batch-processor.d.ts +10 -0
  151. package/dist/processors/batch-processor.d.ts.map +1 -0
  152. package/dist/processors/batch-processor.js +33 -0
  153. package/dist/processors/batch-processor.js.map +1 -0
  154. package/dist/processors/bold-code-placeholders.d.ts +14 -0
  155. package/dist/processors/bold-code-placeholders.d.ts.map +1 -0
  156. package/dist/processors/bold-code-placeholders.js +116 -0
  157. package/dist/processors/bold-code-placeholders.js.map +1 -0
  158. package/dist/processors/doc-postprocess.d.ts +51 -0
  159. package/dist/processors/doc-postprocess.d.ts.map +1 -0
  160. package/dist/processors/doc-postprocess.js +215 -0
  161. package/dist/processors/doc-postprocess.js.map +1 -0
  162. package/dist/processors/emphasis-placeholders.d.ts +6 -0
  163. package/dist/processors/emphasis-placeholders.d.ts.map +1 -0
  164. package/dist/processors/emphasis-placeholders.js +262 -0
  165. package/dist/processors/emphasis-placeholders.js.map +1 -0
  166. package/dist/processors/flat-link-rewrite.d.ts +32 -0
  167. package/dist/processors/flat-link-rewrite.d.ts.map +1 -0
  168. package/dist/processors/flat-link-rewrite.js +90 -0
  169. package/dist/processors/flat-link-rewrite.js.map +1 -0
  170. package/dist/processors/glossary-force-placeholders.d.ts +12 -0
  171. package/dist/processors/glossary-force-placeholders.d.ts.map +1 -0
  172. package/dist/processors/glossary-force-placeholders.js +58 -0
  173. package/dist/processors/glossary-force-placeholders.js.map +1 -0
  174. package/dist/processors/inline-code-placeholders.d.ts +11 -0
  175. package/dist/processors/inline-code-placeholders.d.ts.map +1 -0
  176. package/dist/processors/inline-code-placeholders.js +87 -0
  177. package/dist/processors/inline-code-placeholders.js.map +1 -0
  178. package/dist/processors/placeholder-handler.d.ts +38 -0
  179. package/dist/processors/placeholder-handler.d.ts.map +1 -0
  180. package/dist/processors/placeholder-handler.js +55 -0
  181. package/dist/processors/placeholder-handler.js.map +1 -0
  182. package/dist/processors/translation-placeholder-leaks.d.ts +2 -0
  183. package/dist/processors/translation-placeholder-leaks.d.ts.map +1 -0
  184. package/dist/processors/translation-placeholder-leaks.js +9 -0
  185. package/dist/processors/translation-placeholder-leaks.js.map +1 -0
  186. package/dist/processors/url-placeholders.d.ts +10 -0
  187. package/dist/processors/url-placeholders.d.ts.map +1 -0
  188. package/dist/processors/url-placeholders.js +29 -0
  189. package/dist/processors/url-placeholders.js.map +1 -0
  190. package/dist/processors/validator.d.ts +23 -0
  191. package/dist/processors/validator.d.ts.map +1 -0
  192. package/dist/processors/validator.js +186 -0
  193. package/dist/processors/validator.js.map +1 -0
  194. package/dist/runtime/i18next-helpers.d.ts +146 -0
  195. package/dist/runtime/i18next-helpers.d.ts.map +1 -0
  196. package/dist/runtime/i18next-helpers.js +192 -0
  197. package/dist/runtime/i18next-helpers.js.map +1 -0
  198. package/dist/runtime/index.d.ts +4 -0
  199. package/dist/runtime/index.d.ts.map +1 -0
  200. package/dist/runtime/index.js +4 -0
  201. package/dist/runtime/index.js.map +1 -0
  202. package/dist/runtime/template.d.ts +21 -0
  203. package/dist/runtime/template.d.ts.map +1 -0
  204. package/dist/runtime/template.js +28 -0
  205. package/dist/runtime/template.js.map +1 -0
  206. package/dist/runtime/ui-language-display.d.ts +16 -0
  207. package/dist/runtime/ui-language-display.d.ts.map +1 -0
  208. package/dist/runtime/ui-language-display.js +26 -0
  209. package/dist/runtime/ui-language-display.js.map +1 -0
  210. package/dist/server/translation-editor.d.ts +25 -0
  211. package/dist/server/translation-editor.d.ts.map +1 -0
  212. package/dist/server/translation-editor.js +583 -0
  213. package/dist/server/translation-editor.js.map +1 -0
  214. package/dist/utils/concurrency.d.ts +31 -0
  215. package/dist/utils/concurrency.d.ts.map +1 -0
  216. package/dist/utils/concurrency.js +103 -0
  217. package/dist/utils/concurrency.js.map +1 -0
  218. package/dist/utils/hash.d.ts +5 -0
  219. package/dist/utils/hash.d.ts.map +1 -0
  220. package/dist/utils/hash.js +9 -0
  221. package/dist/utils/hash.js.map +1 -0
  222. package/dist/utils/ignore-parser.d.ts +7 -0
  223. package/dist/utils/ignore-parser.d.ts.map +1 -0
  224. package/dist/utils/ignore-parser.js +26 -0
  225. package/dist/utils/ignore-parser.js.map +1 -0
  226. package/dist/utils/logger.d.ts +45 -0
  227. package/dist/utils/logger.d.ts.map +1 -0
  228. package/dist/utils/logger.js +158 -0
  229. package/dist/utils/logger.js.map +1 -0
  230. package/docs/GETTING_STARTED.md +697 -0
  231. package/docs/PACKAGE_OVERVIEW.md +427 -0
  232. package/docs/ai-i18n-tools-context.md +481 -0
  233. package/package.json +117 -0
  234. package/translated-docs/README.de.md +157 -0
  235. package/translated-docs/README.es.md +157 -0
  236. package/translated-docs/README.fr.md +157 -0
  237. package/translated-docs/README.hi.md +157 -0
  238. package/translated-docs/README.ja.md +157 -0
  239. package/translated-docs/README.ko.md +157 -0
  240. package/translated-docs/README.pt-BR.md +157 -0
  241. package/translated-docs/README.zh-CN.md +157 -0
  242. package/translated-docs/README.zh-TW.md +157 -0
  243. package/translated-docs/docs/GETTING_STARTED.de.md +682 -0
  244. package/translated-docs/docs/GETTING_STARTED.es.md +682 -0
  245. package/translated-docs/docs/GETTING_STARTED.fr.md +682 -0
  246. package/translated-docs/docs/GETTING_STARTED.hi.md +682 -0
  247. package/translated-docs/docs/GETTING_STARTED.ja.md +682 -0
  248. package/translated-docs/docs/GETTING_STARTED.ko.md +682 -0
  249. package/translated-docs/docs/GETTING_STARTED.pt-BR.md +682 -0
  250. package/translated-docs/docs/GETTING_STARTED.zh-CN.md +682 -0
  251. package/translated-docs/docs/GETTING_STARTED.zh-TW.md +682 -0
  252. package/translated-docs/docs/PACKAGE_OVERVIEW.de.md +428 -0
  253. package/translated-docs/docs/PACKAGE_OVERVIEW.es.md +428 -0
  254. package/translated-docs/docs/PACKAGE_OVERVIEW.fr.md +428 -0
  255. package/translated-docs/docs/PACKAGE_OVERVIEW.hi.md +428 -0
  256. package/translated-docs/docs/PACKAGE_OVERVIEW.ja.md +428 -0
  257. package/translated-docs/docs/PACKAGE_OVERVIEW.ko.md +428 -0
  258. package/translated-docs/docs/PACKAGE_OVERVIEW.pt-BR.md +428 -0
  259. package/translated-docs/docs/PACKAGE_OVERVIEW.zh-CN.md +428 -0
  260. package/translated-docs/docs/PACKAGE_OVERVIEW.zh-TW.md +428 -0
@@ -0,0 +1,546 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { createRequire } from "node:module";
4
+ import { CacheError } from "./errors.js";
5
+ import { USER_EDITED_MODEL } from "./user-edited-model.js";
6
+ import { computeSegmentHash } from "../utils/hash.js";
7
+ import { resolveCacheTrackingKeyToAbs } from "./cache-tracking-keys.js";
8
+ const SCHEMA_VERSION = 1;
9
+ const require = createRequire(import.meta.url);
10
+ let sqliteModule = null;
11
+ function loadSqlite() {
12
+ // Delay node:sqlite evaluation until runtime so the CLI can install its
13
+ // warning filter before Node emits the module's ExperimentalWarning.
14
+ sqliteModule ?? (sqliteModule = require("node:sqlite"));
15
+ return sqliteModule;
16
+ }
17
+ /**
18
+ * SQLite translation cache. `better-sqlite3` uses a single native connection per instance
19
+ * (no JS-level pool); reuse one instance per process for best throughput.
20
+ */
21
+ export class TranslationCache {
22
+ constructor(cachePath) {
23
+ const { DatabaseSync } = loadSqlite();
24
+ if (cachePath === ":memory:") {
25
+ this.dbFilePath = null;
26
+ this.db = new DatabaseSync(":memory:");
27
+ this.applyMigrations();
28
+ return;
29
+ }
30
+ if (!fs.existsSync(cachePath)) {
31
+ fs.mkdirSync(cachePath, { recursive: true });
32
+ }
33
+ this.dbFilePath = path.join(cachePath, "cache.db");
34
+ this.db = new DatabaseSync(this.dbFilePath);
35
+ this.applyMigrations();
36
+ }
37
+ applyMigrations() {
38
+ const current = this.db.prepare("PRAGMA user_version").get()
39
+ .user_version;
40
+ if (current < 1) {
41
+ this.db.exec(`
42
+ CREATE TABLE IF NOT EXISTS translations (
43
+ source_hash TEXT NOT NULL,
44
+ locale TEXT NOT NULL,
45
+ source_text TEXT NOT NULL,
46
+ translated_text TEXT NOT NULL,
47
+ model TEXT,
48
+ filepath TEXT,
49
+ created_at TEXT DEFAULT (datetime('now')),
50
+ last_hit_at TEXT,
51
+ start_line INTEGER,
52
+ PRIMARY KEY (source_hash, locale)
53
+ );
54
+
55
+ CREATE TABLE IF NOT EXISTS file_tracking (
56
+ filepath TEXT NOT NULL,
57
+ locale TEXT NOT NULL,
58
+ source_hash TEXT NOT NULL,
59
+ last_translated TEXT DEFAULT (datetime('now')),
60
+ PRIMARY KEY (filepath, locale)
61
+ );
62
+
63
+ CREATE INDEX IF NOT EXISTS idx_translations_locale
64
+ ON translations(locale);
65
+
66
+ CREATE INDEX IF NOT EXISTS idx_translations_filepath
67
+ ON translations(filepath);
68
+ `);
69
+ this.db.exec(`PRAGMA user_version = ${SCHEMA_VERSION}`);
70
+ }
71
+ }
72
+ /** Segment hash (normalized whitespace, SHA-256, 16 hex chars). */
73
+ static computeHash(content) {
74
+ return computeSegmentHash(content);
75
+ }
76
+ /**
77
+ * Cached segment text and model id (as stored on last successful translation).
78
+ * Updates `last_hit_at` / optional filepath tracking like {@link getSegment}.
79
+ */
80
+ getSegmentDetails(sourceHash, locale, filepath, startLine) {
81
+ const selectStmt = this.db.prepare(`
82
+ SELECT translated_text, model FROM translations
83
+ WHERE source_hash = ? AND locale = ?
84
+ `);
85
+ const row = selectStmt.get(sourceHash, locale);
86
+ if (!row) {
87
+ return null;
88
+ }
89
+ const updates = ["last_hit_at = datetime('now')"];
90
+ const params = [];
91
+ if (filepath) {
92
+ updates.push("filepath = CASE WHEN (filepath IS NULL OR filepath = '') THEN ? ELSE filepath END");
93
+ params.push(filepath);
94
+ }
95
+ if (startLine !== undefined && startLine !== null) {
96
+ updates.push("start_line = CASE WHEN start_line IS NULL THEN ? ELSE start_line END");
97
+ params.push(startLine);
98
+ }
99
+ params.push(sourceHash, locale);
100
+ this.db
101
+ .prepare(`UPDATE translations SET ${updates.join(", ")} WHERE source_hash = ? AND locale = ?`)
102
+ .run(...params);
103
+ return { text: row.translated_text, model: row.model };
104
+ }
105
+ getSegment(sourceHash, locale, filepath, startLine) {
106
+ return this.getSegmentDetails(sourceHash, locale, filepath, startLine)?.text ?? null;
107
+ }
108
+ setSegment(sourceHash, locale, sourceText, translatedText, model, filepath, startLine) {
109
+ const stmt = this.db.prepare(`
110
+ INSERT INTO translations (source_hash, locale, source_text, translated_text, model, filepath, created_at, last_hit_at, start_line)
111
+ VALUES (?, ?, ?, ?, ?, ?, datetime('now'), datetime('now'), ?)
112
+ ON CONFLICT(source_hash, locale) DO UPDATE SET
113
+ source_text = excluded.source_text,
114
+ translated_text = excluded.translated_text,
115
+ model = excluded.model,
116
+ filepath = excluded.filepath,
117
+ last_hit_at = datetime('now'),
118
+ start_line = CASE WHEN translations.start_line IS NULL THEN excluded.start_line ELSE translations.start_line END
119
+ `);
120
+ stmt.run(sourceHash, locale, sourceText, translatedText, model, filepath ?? null, startLine ?? null);
121
+ }
122
+ getFileHash(filepath, locale) {
123
+ const stmt = this.db.prepare(`
124
+ SELECT source_hash FROM file_tracking
125
+ WHERE filepath = ? AND locale = ?
126
+ `);
127
+ const row = stmt.get(filepath, locale);
128
+ return row?.source_hash ?? null;
129
+ }
130
+ setFileStatus(filepath, locale, sourceHash) {
131
+ const stmt = this.db.prepare(`
132
+ INSERT OR REPLACE INTO file_tracking
133
+ (filepath, locale, source_hash)
134
+ VALUES (?, ?, ?)
135
+ `);
136
+ stmt.run(filepath, locale, sourceHash);
137
+ }
138
+ /**
139
+ * Remove file-tracking for one path/locale so the next run does not skip the file.
140
+ * Segment rows stay keyed by `(source_hash, locale)`; `--force` bypasses segment cache reads so rows refresh on re-translate.
141
+ */
142
+ clearFile(filepath, locale) {
143
+ this.db
144
+ .prepare("DELETE FROM file_tracking WHERE filepath = ? AND locale = ?")
145
+ .run(filepath, locale);
146
+ }
147
+ getStats() {
148
+ const segments = this.db.prepare("SELECT COUNT(*) as count FROM translations").get();
149
+ const files = this.db.prepare("SELECT COUNT(*) as count FROM file_tracking").get();
150
+ const byLocale = {};
151
+ const localeStats = this.db
152
+ .prepare("SELECT locale, COUNT(*) as count FROM translations GROUP BY locale")
153
+ .all();
154
+ for (const row of localeStats) {
155
+ byLocale[row.locale] = row.count;
156
+ }
157
+ return {
158
+ totalSegments: segments.count,
159
+ totalFiles: files.count,
160
+ byLocale,
161
+ };
162
+ }
163
+ /**
164
+ * Aggregate documentation-cache stats for dashboards (stale vs active, per locale/model).
165
+ */
166
+ getDetailedStats() {
167
+ const totalSegments = this.db.prepare("SELECT COUNT(*) as count FROM translations").get().count;
168
+ const totalFiles = this.db.prepare("SELECT COUNT(*) as count FROM file_tracking").get().count;
169
+ const staleSegments = this.db
170
+ .prepare("SELECT COUNT(*) as count FROM translations WHERE last_hit_at IS NULL")
171
+ .get().count;
172
+ const activeSegments = this.db
173
+ .prepare("SELECT COUNT(*) as count FROM translations WHERE last_hit_at IS NOT NULL")
174
+ .get().count;
175
+ const uniqueFilepaths = this.db
176
+ .prepare("SELECT COUNT(DISTINCT filepath) as count FROM translations WHERE filepath IS NOT NULL AND TRIM(filepath) != ''")
177
+ .get().count;
178
+ const localeRows = this.db
179
+ .prepare(`SELECT locale,
180
+ COUNT(*) as total,
181
+ SUM(CASE WHEN last_hit_at IS NULL THEN 1 ELSE 0 END) as stale,
182
+ SUM(CASE WHEN last_hit_at IS NOT NULL THEN 1 ELSE 0 END) as active
183
+ FROM translations
184
+ GROUP BY locale
185
+ ORDER BY locale`)
186
+ .all();
187
+ const modelRows = this.db
188
+ .prepare(`SELECT COALESCE(NULLIF(TRIM(model), ''), '(unknown)') as model, COUNT(*) as count
189
+ FROM translations
190
+ GROUP BY COALESCE(NULLIF(TRIM(model), ''), '(unknown)')
191
+ ORDER BY count DESC, model`)
192
+ .all();
193
+ const modelLocaleRows = this.db
194
+ .prepare(`SELECT COALESCE(NULLIF(TRIM(model), ''), '(unknown)') as model, locale, COUNT(*) as count
195
+ FROM translations
196
+ GROUP BY COALESCE(NULLIF(TRIM(model), ''), '(unknown)'), locale
197
+ ORDER BY model, locale`)
198
+ .all();
199
+ return {
200
+ totalSegments,
201
+ totalFiles,
202
+ staleSegments,
203
+ activeSegments,
204
+ byLocale: localeRows,
205
+ byModel: modelRows,
206
+ byModelLocale: modelLocaleRows,
207
+ uniqueFilepaths,
208
+ };
209
+ }
210
+ clear(locale) {
211
+ if (locale) {
212
+ this.db.prepare("DELETE FROM translations WHERE locale = ?").run(locale);
213
+ this.db.prepare("DELETE FROM file_tracking WHERE locale = ?").run(locale);
214
+ }
215
+ else {
216
+ this.db.prepare("DELETE FROM translations").run();
217
+ this.db.prepare("DELETE FROM file_tracking").run();
218
+ }
219
+ }
220
+ /**
221
+ * Set `last_hit_at = NULL` for markdown segments that were not hit this run.
222
+ * Scoped to markdown-like paths only so JSON (and other) rows are not cleared.
223
+ * @param keysHit - entries as `sourceHash|locale`.
224
+ */
225
+ resetLastHitAtForUnhitMarkdown(hitKeys) {
226
+ return this.resetLastHitAtForUnhitScoped(hitKeys, `(filepath IS NULL OR LOWER(filepath) LIKE '%.md' OR LOWER(filepath) LIKE '%.mdx')`);
227
+ }
228
+ /**
229
+ * Set `last_hit_at = NULL` for JSON UI/doc segments that were not hit this run.
230
+ * @param keysHit - entries as `sourceHash|locale`.
231
+ */
232
+ resetLastHitAtForUnhitJson(hitKeys) {
233
+ return this.resetLastHitAtForUnhitScoped(hitKeys, `(filepath IS NOT NULL AND LOWER(filepath) LIKE '%.json')`);
234
+ }
235
+ resetLastHitAtForUnhitScoped(hitKeys, filepathPredicateSql) {
236
+ if (hitKeys.size === 0) {
237
+ return 0;
238
+ }
239
+ const keys = Array.from(hitKeys);
240
+ const flatParams = keys.flatMap((k) => {
241
+ const [h, l] = k.split("|");
242
+ return [h, l];
243
+ });
244
+ this.db.exec("CREATE TEMP TABLE IF NOT EXISTS _hit_keys (source_hash TEXT, locale TEXT)");
245
+ const insertPlaceholders = keys.map(() => "(?, ?)").join(", ");
246
+ this.db.prepare(`INSERT INTO _hit_keys VALUES ${insertPlaceholders}`).run(...flatParams);
247
+ const result = this.db
248
+ .prepare(`UPDATE translations SET last_hit_at = NULL
249
+ WHERE ${filepathPredicateSql}
250
+ AND (source_hash, locale) NOT IN (SELECT source_hash, locale FROM _hit_keys)`)
251
+ .run();
252
+ this.db.exec("DROP TABLE IF EXISTS _hit_keys");
253
+ return Number(result.changes);
254
+ }
255
+ /**
256
+ * Like {@link resetLastHitAtForUnhitMarkdown}, but only rows whose `filepath` is in `allowedRelPaths`
257
+ * (e.g. markdown files in scope for this translate run after path filters).
258
+ */
259
+ resetLastHitAtForUnhitMarkdownInScope(hitKeys, allowedRelPaths) {
260
+ if (hitKeys.size === 0 || allowedRelPaths.length === 0) {
261
+ return 0;
262
+ }
263
+ const normalized = allowedRelPaths.map((p) => p.split("\\").join("/"));
264
+ return this.resetLastHitAtForUnhitScopedWithScope(hitKeys, `(filepath IS NULL OR LOWER(filepath) LIKE '%.md' OR LOWER(filepath) LIKE '%.mdx')`, normalized);
265
+ }
266
+ /**
267
+ * Like {@link resetLastHitAtForUnhitJson}, but only rows whose `filepath` is in `allowedRelPaths`.
268
+ */
269
+ resetLastHitAtForUnhitJsonInScope(hitKeys, allowedRelPaths) {
270
+ if (hitKeys.size === 0 || allowedRelPaths.length === 0) {
271
+ return 0;
272
+ }
273
+ const normalized = allowedRelPaths.map((p) => p.split("\\").join("/"));
274
+ return this.resetLastHitAtForUnhitScopedWithScope(hitKeys, `(filepath IS NOT NULL AND LOWER(filepath) LIKE '%.json')`, normalized);
275
+ }
276
+ resetLastHitAtForUnhitScopedWithScope(hitKeys, filepathPredicateSql, allowedRelPaths) {
277
+ const keys = Array.from(hitKeys);
278
+ const flatParams = keys.flatMap((k) => {
279
+ const [h, l] = k.split("|");
280
+ return [h, l];
281
+ });
282
+ this.db.exec("DROP TABLE IF EXISTS _hit_keys");
283
+ this.db.exec("CREATE TEMP TABLE _hit_keys (source_hash TEXT, locale TEXT)");
284
+ const insertPlaceholders = keys.map(() => "(?, ?)").join(", ");
285
+ this.db.prepare(`INSERT INTO _hit_keys VALUES ${insertPlaceholders}`).run(...flatParams);
286
+ this.db.exec("DROP TABLE IF EXISTS _scope_paths");
287
+ this.db.exec("CREATE TEMP TABLE _scope_paths (filepath TEXT PRIMARY KEY)");
288
+ const scopePlaceholders = allowedRelPaths.map(() => "(?)").join(", ");
289
+ this.db.prepare(`INSERT INTO _scope_paths VALUES ${scopePlaceholders}`).run(...allowedRelPaths);
290
+ const result = this.db
291
+ .prepare(`UPDATE translations SET last_hit_at = NULL
292
+ WHERE ${filepathPredicateSql}
293
+ AND filepath IN (SELECT filepath FROM _scope_paths)
294
+ AND (source_hash, locale) NOT IN (SELECT source_hash, locale FROM _hit_keys)`)
295
+ .run();
296
+ this.db.exec("DROP TABLE IF EXISTS _hit_keys");
297
+ this.db.exec("DROP TABLE IF EXISTS _scope_paths");
298
+ return Number(result.changes);
299
+ }
300
+ cleanupStaleTranslations(dryRun = false) {
301
+ const deletedRows = this.db
302
+ .prepare(`SELECT source_hash, locale, filepath FROM translations
303
+ WHERE last_hit_at IS NULL OR filepath IS NULL OR filepath = ''`)
304
+ .all();
305
+ if (!dryRun) {
306
+ this.db
307
+ .prepare(`DELETE FROM translations
308
+ WHERE last_hit_at IS NULL OR filepath IS NULL OR filepath = ''`)
309
+ .run();
310
+ }
311
+ return { count: deletedRows.length, deletedRows };
312
+ }
313
+ listTranslations(filters) {
314
+ const limit = filters?.limit ?? 50;
315
+ const offset = filters?.offset ?? 0;
316
+ const conditions = [];
317
+ const params = [];
318
+ if (filters?.filename?.trim()) {
319
+ conditions.push("LOWER(filepath) LIKE ?");
320
+ params.push(`%${filters.filename.trim().toLowerCase()}%`);
321
+ }
322
+ if (filters?.locale?.trim()) {
323
+ conditions.push("locale = ?");
324
+ params.push(filters.locale.trim());
325
+ }
326
+ if (filters?.model?.trim()) {
327
+ conditions.push("model = ?");
328
+ params.push(filters.model.trim());
329
+ }
330
+ if (filters?.source_hash?.trim()) {
331
+ conditions.push("LOWER(source_hash) LIKE ?");
332
+ params.push(`%${filters.source_hash.trim().toLowerCase()}%`);
333
+ }
334
+ if (filters?.source_text?.trim()) {
335
+ conditions.push("LOWER(source_text) LIKE ?");
336
+ params.push(`%${filters.source_text.trim().toLowerCase()}%`);
337
+ }
338
+ if (filters?.translated_text?.trim()) {
339
+ conditions.push("LOWER(translated_text) LIKE ?");
340
+ params.push(`%${filters.translated_text.trim().toLowerCase()}%`);
341
+ }
342
+ if (filters?.last_hit_at_null === true) {
343
+ conditions.push("last_hit_at IS NULL");
344
+ }
345
+ if (filters?.last_hit_at_not_null === true) {
346
+ conditions.push("last_hit_at IS NOT NULL");
347
+ }
348
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
349
+ const countStmt = this.db.prepare(`SELECT COUNT(*) as count FROM translations ${whereClause}`);
350
+ const total = countStmt.get(...params).count;
351
+ const selectStmt = this.db.prepare(`SELECT source_hash, locale, source_text, translated_text, model, filepath, created_at, last_hit_at, start_line
352
+ FROM translations ${whereClause}
353
+ ORDER BY filepath, locale, CASE WHEN start_line IS NULL THEN 1 ELSE 0 END, start_line, source_hash
354
+ LIMIT ? OFFSET ?`);
355
+ const rows = selectStmt.all(...params, limit, offset);
356
+ return { rows, total };
357
+ }
358
+ updateTranslation(sourceHash, locale, translatedText) {
359
+ this.db
360
+ .prepare(`UPDATE translations SET translated_text = ?, model = ? WHERE source_hash = ? AND locale = ?`)
361
+ .run(translatedText, USER_EDITED_MODEL, sourceHash, locale);
362
+ }
363
+ deleteTranslation(sourceHash, locale) {
364
+ this.db
365
+ .prepare("DELETE FROM translations WHERE source_hash = ? AND locale = ?")
366
+ .run(sourceHash, locale);
367
+ this.db
368
+ .prepare("DELETE FROM file_tracking WHERE source_hash = ? AND locale = ?")
369
+ .run(sourceHash, locale);
370
+ }
371
+ deleteByFilters(filters) {
372
+ const conditions = [];
373
+ const params = [];
374
+ if (filters?.filename?.trim()) {
375
+ conditions.push("LOWER(filepath) LIKE ?");
376
+ params.push(`%${filters.filename.trim().toLowerCase()}%`);
377
+ }
378
+ if (filters?.locale?.trim()) {
379
+ conditions.push("locale = ?");
380
+ params.push(filters.locale.trim());
381
+ }
382
+ if (filters?.model?.trim()) {
383
+ conditions.push("model = ?");
384
+ params.push(filters.model.trim());
385
+ }
386
+ if (filters?.source_hash?.trim()) {
387
+ conditions.push("LOWER(source_hash) LIKE ?");
388
+ params.push(`%${filters.source_hash.trim().toLowerCase()}%`);
389
+ }
390
+ if (filters?.source_text?.trim()) {
391
+ conditions.push("LOWER(source_text) LIKE ?");
392
+ params.push(`%${filters.source_text.trim().toLowerCase()}%`);
393
+ }
394
+ if (filters?.translated_text?.trim()) {
395
+ conditions.push("LOWER(translated_text) LIKE ?");
396
+ params.push(`%${filters.translated_text.trim().toLowerCase()}%`);
397
+ }
398
+ if (filters?.last_hit_at_null === true) {
399
+ conditions.push("last_hit_at IS NULL");
400
+ }
401
+ if (filters?.last_hit_at_not_null === true) {
402
+ conditions.push("last_hit_at IS NOT NULL");
403
+ }
404
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
405
+ this.db
406
+ .prepare(`DELETE FROM file_tracking WHERE (source_hash, locale) IN (SELECT source_hash, locale FROM translations ${whereClause})`)
407
+ .run(...params);
408
+ const result = this.db.prepare(`DELETE FROM translations ${whereClause}`).run(...params);
409
+ return Number(result.changes);
410
+ }
411
+ /** Deletes matching rows in `translations` only (see {@link deleteFileTrackingByPath} for tracking keys). */
412
+ deleteTranslationsByFilepath(filepath) {
413
+ const result = this.db.prepare("DELETE FROM translations WHERE filepath = ?").run(filepath);
414
+ return Number(result.changes);
415
+ }
416
+ /** Deletes all `file_tracking` rows for this cache key (all locales). */
417
+ deleteFileTrackingByPath(filepath) {
418
+ const result = this.db.prepare("DELETE FROM file_tracking WHERE filepath = ?").run(filepath);
419
+ return Number(result.changes);
420
+ }
421
+ /** Distinct `filepath` values in `file_tracking` (cache keys: `doc-block:…`, `svg-assets:…`, etc.). */
422
+ listFileTrackingPaths() {
423
+ const rows = this.db
424
+ .prepare(`SELECT DISTINCT filepath FROM file_tracking WHERE filepath IS NOT NULL AND filepath != '' ORDER BY filepath`)
425
+ .all();
426
+ return rows.map((r) => r.filepath);
427
+ }
428
+ /**
429
+ * Remove `file_tracking` rows whose resolved path does not exist on disk under `projectRoot`.
430
+ */
431
+ pruneOrphanedFileTrackingByDisk(projectRoot, dryRun) {
432
+ let removed = 0;
433
+ for (const fp of this.listFileTrackingPaths()) {
434
+ const abs = resolveCacheTrackingKeyToAbs(projectRoot, fp);
435
+ if (!fs.existsSync(abs)) {
436
+ if (!dryRun) {
437
+ removed += this.deleteFileTrackingByPath(fp);
438
+ }
439
+ else {
440
+ removed += 1;
441
+ }
442
+ }
443
+ }
444
+ return removed;
445
+ }
446
+ /**
447
+ * @deprecated Prefer {@link deleteTranslationsByFilepath} / {@link deleteFileTrackingByPath} explicitly.
448
+ * Deletes `translations` rows only (no longer deletes `file_tracking`).
449
+ */
450
+ deleteByFilepath(filepath) {
451
+ return this.deleteTranslationsByFilepath(filepath);
452
+ }
453
+ getUniqueLocales() {
454
+ const rows = this.db
455
+ .prepare(`SELECT DISTINCT locale FROM translations ORDER BY locale`)
456
+ .all();
457
+ return rows.map((r) => r.locale);
458
+ }
459
+ getUniqueFilepaths() {
460
+ const rows = this.db
461
+ .prepare(`SELECT DISTINCT filepath FROM translations WHERE filepath IS NOT NULL AND filepath != '' ORDER BY filepath`)
462
+ .all();
463
+ return rows.map((r) => r.filepath);
464
+ }
465
+ getUniqueModels() {
466
+ const rows = this.db
467
+ .prepare(`SELECT DISTINCT model FROM translations WHERE model IS NOT NULL AND model != '' ORDER BY model`)
468
+ .all();
469
+ return rows.map((r) => r.model);
470
+ }
471
+ close() {
472
+ this.db.close();
473
+ }
474
+ // --- Plan §1.4 async façade ---
475
+ async getSegmentAsync(hash, locale) {
476
+ return Promise.resolve(this.getSegment(hash, locale));
477
+ }
478
+ async setSegmentAsync(entry) {
479
+ this.setSegment(entry.sourceHash, entry.locale, entry.sourceText, entry.translatedText, entry.model, entry.filepath, entry.startLine ?? undefined);
480
+ return Promise.resolve();
481
+ }
482
+ async getFileStatus(filepath, locale) {
483
+ const stmt = this.db.prepare(`
484
+ SELECT source_hash, last_translated FROM file_tracking
485
+ WHERE filepath = ? AND locale = ?
486
+ `);
487
+ const row = stmt.get(filepath, locale);
488
+ if (!row) {
489
+ return null;
490
+ }
491
+ return Promise.resolve({
492
+ filepath,
493
+ locale,
494
+ sourceHash: row.source_hash,
495
+ lastTranslated: row.last_translated,
496
+ });
497
+ }
498
+ async setFileStatusAsync(filepath, locale, hash) {
499
+ this.setFileStatus(filepath, locale, hash);
500
+ return Promise.resolve();
501
+ }
502
+ /**
503
+ * @param markdownKeys - `sourceHash|locale` for markdown segments hit this run (may be empty).
504
+ * @param jsonKeys - `sourceHash|locale` for JSON segments hit this run (may be empty).
505
+ */
506
+ async resetLastHitAtForUnhit(markdownKeys, jsonKeys) {
507
+ if (markdownKeys.length > 0) {
508
+ this.resetLastHitAtForUnhitMarkdown(new Set(markdownKeys));
509
+ }
510
+ if (jsonKeys.length > 0) {
511
+ this.resetLastHitAtForUnhitJson(new Set(jsonKeys));
512
+ }
513
+ return Promise.resolve();
514
+ }
515
+ async cleanup() {
516
+ const { count, deletedRows } = this.cleanupStaleTranslations(false);
517
+ return Promise.resolve({
518
+ staleTranslationsRemoved: count,
519
+ deletedRows,
520
+ });
521
+ }
522
+ /** Hot SQLite backup to another file. */
523
+ async backupTo(destinationPath) {
524
+ if (this.dbFilePath === null) {
525
+ throw new CacheError("backup is not supported for :memory: databases");
526
+ }
527
+ const { backup } = loadSqlite();
528
+ fs.mkdirSync(path.dirname(path.resolve(destinationPath)), { recursive: true });
529
+ await backup(this.db, destinationPath);
530
+ }
531
+ /** Replace the on-disk DB with a copied file; closes and reopens the connection. */
532
+ restoreFrom(sourcePath) {
533
+ if (this.dbFilePath === null) {
534
+ throw new CacheError("restore is not supported for :memory: databases");
535
+ }
536
+ const { DatabaseSync } = loadSqlite();
537
+ if (!fs.existsSync(sourcePath)) {
538
+ throw new CacheError(`Backup file not found: ${sourcePath}`);
539
+ }
540
+ this.db.close();
541
+ fs.copyFileSync(sourcePath, this.dbFilePath);
542
+ this.db = new DatabaseSync(this.dbFilePath);
543
+ this.applyMigrations();
544
+ }
545
+ }
546
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/core/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import { coerceTargetLocalesField, englishLanguageNameForLocale, normalizeLocale, parseLocaleList } from "./locale-utils.js";
2
+ import { type DocumentationBlock, type I18nConfig, type I18nDocTranslateConfig, type OpenRouterConfig, type RawI18nConfigInput } from "./types.js";
3
+ export { coerceTargetLocalesField, englishLanguageNameForLocale, normalizeLocale, parseLocaleList };
4
+ /**
5
+ * Ordered OpenRouter models: non-empty `translationModels`, else legacy default + fallback.
6
+ */
7
+ export declare function resolveTranslationModels(o: OpenRouterConfig): string[];
8
+ /**
9
+ * Ordered OpenRouter models for UI translation: optional `ui.preferredModel` first, then
10
+ * {@link resolveTranslationModels} for `openrouter`, with the preferred id deduplicated from the tail.
11
+ */
12
+ export declare function resolveUITranslationModels(config: I18nConfig): string[];
13
+ /**
14
+ * Single-documentation view for translate-docs: one block plus root `cacheDir` and shared settings.
15
+ */
16
+ export declare function toDocTranslateConfig(root: I18nConfig, block: DocumentationBlock): I18nDocTranslateConfig;
17
+ export declare const defaultI18nConfigPartial: RawI18nConfigInput;
18
+ /**
19
+ * Merge user JSON (partial) with package defaults, then validate with Zod.
20
+ */
21
+ export declare function mergeWithDefaults(raw: unknown): RawI18nConfigInput;
22
+ export declare function validateI18nBusinessRules(config: I18nConfig): void;
23
+ /** Validate config for the `translate-svg` command (call after normal load). */
24
+ export declare function assertSvgCommandConfig(config: I18nConfig): void;
25
+ /**
26
+ * Parse and validate unified config (after optional merge with {@link mergeWithDefaults}).
27
+ */
28
+ export declare function parseI18nConfig(input: RawI18nConfigInput): I18nConfig;
29
+ /**
30
+ * Apply environment overrides (OpenRouter and optional locale hints).
31
+ * Does not re-validate; call {@link parseI18nConfig} after merge if shape may have changed.
32
+ */
33
+ export declare function applyEnvOverrides(config: I18nConfig): I18nConfig;
34
+ /**
35
+ * Load `ai-i18n-tools.config.json` or a given path; merge defaults; validate.
36
+ */
37
+ export declare function loadI18nConfigFromFile(configPath: string, cwd?: string): I18nConfig;
38
+ /** Default filename for `init` / CLI (Phase 4). */
39
+ export declare const DEFAULT_CONFIG_FILENAME = "ai-i18n-tools.config.json";
40
+ /**
41
+ * Template objects for `init`.
42
+ *
43
+ * `ui-markdown` - Workflow 1 (UI string extraction/translation) for a React/Next.js app.
44
+ * `ui-docusaurus` - Workflow 2 (markdown/JSON document translation) for Docusaurus sites.
45
+ *
46
+ * Both templates include all top-level fields so the generated file is self-documenting.
47
+ * See docs/GETTING_STARTED.md for a full annotated explanation of every field.
48
+ */
49
+ export declare const initConfigTemplates: {
50
+ readonly uiMarkdown: () => RawI18nConfigInput;
51
+ readonly uiDocusaurus: () => RawI18nConfigInput;
52
+ };
53
+ /**
54
+ * Write a starter config JSON for `ai-i18n-tools init`.
55
+ * See docs/GETTING_STARTED.md for a full annotated explanation of every field.
56
+ */
57
+ export declare function writeInitConfigFile(outPath: string, template: keyof typeof initConfigTemplates, cwd?: string): void;
58
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,wBAAwB,EACxB,4BAA4B,EAC5B,eAAe,EACf,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAQ3B,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,UAAU,EACf,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EAExB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,wBAAwB,EAAE,4BAA4B,EAAE,eAAe,EAAE,eAAe,EAAE,CAAC;AAWpG;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAkBtE;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAavE;AA0DD;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,kBAAkB,GACxB,sBAAsB,CAGxB;AAED,eAAO,MAAM,wBAAwB,EAAE,kBA8BtC,CAAC;AAEF;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,kBAAkB,CAUlE;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAsDlE;AAED,gFAAgF;AAChF,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAkB/D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,kBAAkB,GAAG,UAAU,CAcrE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAqBhE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,SAAgB,GAAG,UAAU,CA4B1F;AAED,mDAAmD;AACnD,eAAO,MAAM,uBAAuB,8BAA8B,CAAC;AAEnE;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB;+BACd,kBAAkB;iCAiDhB,kBAAkB;CAiD5B,CAAC;AAEX;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,OAAO,mBAAmB,EAC1C,GAAG,SAAgB,GAClB,IAAI,CAON"}