dialekt 0.1.0 → 0.1.1

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 (71) hide show
  1. package/README.md +8 -10
  2. package/TESTING.md +29 -29
  3. package/dist/cli/main.d.mts +1 -1
  4. package/dist/cli/main.mjs +549 -362
  5. package/dist/formatters-De4Q-X1d.mjs +516 -435
  6. package/dist/index.d.mts +162 -25
  7. package/dist/index.mjs +119 -34
  8. package/package.json +3 -3
  9. package/pnpm-workspace.yaml +3 -3
  10. package/src/adapter/types.test.ts +57 -57
  11. package/src/adapter/types.ts +7 -4
  12. package/src/benchmark/metrics.test.ts +141 -69
  13. package/src/benchmark/metrics.ts +6 -6
  14. package/src/benchmark/report.test.ts +38 -38
  15. package/src/benchmark/report.ts +6 -6
  16. package/src/benchmark/runner.test.ts +70 -72
  17. package/src/benchmark/runner.ts +4 -4
  18. package/src/cli/commands/add.test.ts +90 -109
  19. package/src/cli/commands/add.ts +40 -28
  20. package/src/cli/commands/benchmark.test.ts +77 -64
  21. package/src/cli/commands/benchmark.ts +64 -41
  22. package/src/cli/commands/languages.test.ts +45 -42
  23. package/src/cli/commands/languages.ts +16 -12
  24. package/src/cli/commands/missing.test.ts +143 -92
  25. package/src/cli/commands/missing.ts +24 -17
  26. package/src/cli/commands/translate.test.ts +79 -79
  27. package/src/cli/commands/translate.ts +41 -31
  28. package/src/cli/commands/unused.test.ts +62 -51
  29. package/src/cli/commands/unused.ts +18 -14
  30. package/src/cli/commands/validate.test.ts +130 -72
  31. package/src/cli/commands/validate.ts +25 -20
  32. package/src/cli/config-resolution.test.ts +169 -49
  33. package/src/cli/config-resolution.ts +5 -7
  34. package/src/cli/format.test.ts +50 -50
  35. package/src/cli/format.ts +57 -60
  36. package/src/cli/formatters.test.ts +128 -106
  37. package/src/cli/formatters.ts +72 -95
  38. package/src/cli/main.ts +13 -13
  39. package/src/config/define-config.test.ts +44 -29
  40. package/src/config/define-config.ts +1 -1
  41. package/src/config/load-config.test.ts +21 -18
  42. package/src/config/load-config.ts +5 -5
  43. package/src/config/types.test.ts +50 -44
  44. package/src/config/types.ts +2 -2
  45. package/src/index.ts +22 -26
  46. package/src/keys/flatten.test.ts +52 -52
  47. package/src/keys/flatten.ts +7 -9
  48. package/src/sdk/file-io.test.ts +47 -59
  49. package/src/sdk/file-io.ts +2 -2
  50. package/src/sdk/node-layer.test.ts +18 -18
  51. package/src/sdk/node-layer.ts +2 -2
  52. package/src/sdk/php-array-reader.test.ts +49 -40
  53. package/src/sdk/php-array-reader.ts +5 -5
  54. package/src/translation/chunking.test.ts +52 -44
  55. package/src/translation/chunking.ts +1 -1
  56. package/src/translation/missing-keys.test.ts +86 -93
  57. package/src/translation/missing-keys.ts +4 -6
  58. package/src/translation/model-registry.test.ts +41 -32
  59. package/src/translation/model-registry.ts +9 -9
  60. package/src/translation/one-shot-strategy.test.ts +105 -86
  61. package/src/translation/one-shot-strategy.ts +10 -12
  62. package/src/translation/orchestrator.test.ts +90 -101
  63. package/src/translation/orchestrator.ts +26 -26
  64. package/src/translation/prompt.test.ts +76 -76
  65. package/src/translation/prompt.ts +2 -2
  66. package/src/translation/tool-loop-strategy.test.ts +134 -107
  67. package/src/translation/tool-loop-strategy.ts +14 -18
  68. package/src/translation/types.test.ts +22 -22
  69. package/src/translation/types.ts +3 -3
  70. package/tsdown.config.ts +3 -3
  71. package/vitest.config.ts +3 -3
@@ -16,18 +16,18 @@ import {
16
16
  warning,
17
17
  info,
18
18
  keyValue,
19
- } from './format.js';
20
- import type { OutputFormat } from './format.js';
19
+ } from "./format.js";
20
+ import type { OutputFormat } from "./format.js";
21
21
 
22
22
  const C = {
23
- reset: '\x1b[0m',
24
- bold: '\x1b[1m',
25
- dim: '\x1b[2m',
26
- red: '\x1b[31m',
27
- green: '\x1b[32m',
28
- yellow: '\x1b[33m',
29
- blue: '\x1b[34m',
30
- cyan: '\x1b[36m',
23
+ reset: "\x1b[0m",
24
+ bold: "\x1b[1m",
25
+ dim: "\x1b[2m",
26
+ red: "\x1b[31m",
27
+ green: "\x1b[32m",
28
+ yellow: "\x1b[33m",
29
+ blue: "\x1b[34m",
30
+ cyan: "\x1b[36m",
31
31
  } as const;
32
32
 
33
33
  // ─── Missing keys formatter ──────────────────────────────────────────────────
@@ -43,12 +43,12 @@ export function formatMissingKeys(
43
43
  entries: readonly MissingKeyEntry[],
44
44
  format: OutputFormat,
45
45
  ): string {
46
- if (format === 'json') {
47
- return JSON.stringify(entries, null, 2) + '\n';
46
+ if (format === "json") {
47
+ return JSON.stringify(entries, null, 2) + "\n";
48
48
  }
49
49
 
50
50
  if (entries.length === 0) {
51
- return success('All translations are complete. No missing keys.') + '\n';
51
+ return success("All translations are complete. No missing keys.") + "\n";
52
52
  }
53
53
 
54
54
  const grouped = new Map<string, Map<string, Map<string, string[]>>>();
@@ -78,7 +78,9 @@ export function formatMissingKeys(
78
78
  for (const [locale, byResource] of byLocale) {
79
79
  let localeTotal = 0;
80
80
  for (const keys of byResource.values()) localeTotal += keys.length;
81
- lines.push(` ${color(`${g.arrow} ${locale}`, C.yellow)} ${color(`(${localeTotal})`, C.dim)}`);
81
+ lines.push(
82
+ ` ${color(`${g.arrow} ${locale}`, C.yellow)} ${color(`(${localeTotal})`, C.dim)}`,
83
+ );
82
84
 
83
85
  for (const [resource, keys] of byResource) {
84
86
  lines.push(` ${color(resource, C.bold)}`);
@@ -89,7 +91,7 @@ export function formatMissingKeys(
89
91
  }
90
92
  }
91
93
 
92
- return lines.join('\n') + '\n';
94
+ return lines.join("\n") + "\n";
93
95
  }
94
96
 
95
97
  // ─── Unused keys formatter ───────────────────────────────────────────────────
@@ -101,16 +103,13 @@ export interface UnusedKeyEntry {
101
103
  readonly key: string;
102
104
  }
103
105
 
104
- export function formatUnusedKeys(
105
- entries: readonly UnusedKeyEntry[],
106
- format: OutputFormat,
107
- ): string {
108
- if (format === 'json') {
109
- return JSON.stringify(entries, null, 2) + '\n';
106
+ export function formatUnusedKeys(entries: readonly UnusedKeyEntry[], format: OutputFormat): string {
107
+ if (format === "json") {
108
+ return JSON.stringify(entries, null, 2) + "\n";
110
109
  }
111
110
 
112
111
  if (entries.length === 0) {
113
- return success('All keys are referenced in source files. No unused keys.') + '\n';
112
+ return success("All keys are referenced in source files. No unused keys.") + "\n";
114
113
  }
115
114
 
116
115
  const grouped = new Map<string, Map<string, Map<string, string[]>>>();
@@ -140,7 +139,9 @@ export function formatUnusedKeys(
140
139
  for (const [locale, byResource] of byLocale) {
141
140
  let localeTotal = 0;
142
141
  for (const keys of byResource.values()) localeTotal += keys.length;
143
- lines.push(` ${color(`${g.arrow} ${locale}`, C.yellow)} ${color(`(${localeTotal})`, C.dim)}`);
142
+ lines.push(
143
+ ` ${color(`${g.arrow} ${locale}`, C.yellow)} ${color(`(${localeTotal})`, C.dim)}`,
144
+ );
144
145
 
145
146
  for (const [resource, keys] of byResource) {
146
147
  lines.push(` ${color(resource, C.bold)}`);
@@ -151,7 +152,7 @@ export function formatUnusedKeys(
151
152
  }
152
153
  }
153
154
 
154
- return lines.join('\n') + '\n';
155
+ return lines.join("\n") + "\n";
155
156
  }
156
157
 
157
158
  // ─── Validate formatter ──────────────────────────────────────────────────────
@@ -168,33 +169,27 @@ export interface ValidateResult {
168
169
  readonly entries: readonly ValidateEntry[];
169
170
  }
170
171
 
171
- export function formatValidate(
172
- result: ValidateResult,
173
- format: OutputFormat,
174
- ): string {
175
- if (format === 'json') {
176
- return JSON.stringify(result, null, 2) + '\n';
172
+ export function formatValidate(result: ValidateResult, format: OutputFormat): string {
173
+ if (format === "json") {
174
+ return JSON.stringify(result, null, 2) + "\n";
177
175
  }
178
176
 
179
177
  if (result.passing) {
180
- return '\n' + success('All translations are up to date.') + '\n';
178
+ return "\n" + success("All translations are up to date.") + "\n";
181
179
  }
182
180
 
183
- const rows = result.entries.map((e) => [
184
- e.adapter,
185
- e.locale,
186
- e.resource,
187
- e.count.toString(),
188
- ]);
181
+ const rows = result.entries.map((e) => [e.adapter, e.locale, e.resource, e.count.toString()]);
189
182
 
190
183
  const lines: string[] = [];
191
184
  lines.push(failure(`Missing keys found in ${result.entries.length} resource(s)`));
192
- lines.push('');
193
- lines.push(drawTable(['Adapter', 'Locale', 'Resource', 'Missing'], rows));
194
- lines.push('');
195
- lines.push(color(`Run ${color('dialekt translate', C.bold + C.cyan)} to fill missing keys.`, C.dim));
196
-
197
- return lines.join('\n') + '\n';
185
+ lines.push("");
186
+ lines.push(drawTable(["Adapter", "Locale", "Resource", "Missing"], rows));
187
+ lines.push("");
188
+ lines.push(
189
+ color(`Run ${color("dialekt translate", C.bold + C.cyan)} to fill missing keys.`, C.dim),
190
+ );
191
+
192
+ return lines.join("\n") + "\n";
198
193
  }
199
194
 
200
195
  // ─── Languages formatter ─────────────────────────────────────────────────────
@@ -204,16 +199,13 @@ export interface LanguageEntry {
204
199
  readonly locales: readonly string[];
205
200
  }
206
201
 
207
- export function formatLanguages(
208
- entries: readonly LanguageEntry[],
209
- format: OutputFormat,
210
- ): string {
211
- if (format === 'json') {
212
- return JSON.stringify(entries, null, 2) + '\n';
202
+ export function formatLanguages(entries: readonly LanguageEntry[], format: OutputFormat): string {
203
+ if (format === "json") {
204
+ return JSON.stringify(entries, null, 2) + "\n";
213
205
  }
214
206
 
215
207
  if (entries.length === 0) {
216
- return warning('No adapters configured.') + '\n';
208
+ return warning("No adapters configured.") + "\n";
217
209
  }
218
210
 
219
211
  const lines: string[] = [];
@@ -221,10 +213,10 @@ export function formatLanguages(
221
213
 
222
214
  for (const e of entries) {
223
215
  lines.push(` ${color(e.adapter, C.bold + C.blue)}`);
224
- lines.push(` ${color(`${g.arrow}`, C.dim)} ${e.locales.join(color(', ', C.dim))}`);
216
+ lines.push(` ${color(`${g.arrow}`, C.dim)} ${e.locales.join(color(", ", C.dim))}`);
225
217
  }
226
218
 
227
- return lines.join('\n') + '\n';
219
+ return lines.join("\n") + "\n";
228
220
  }
229
221
 
230
222
  // ─── Translate formatter ─────────────────────────────────────────────────────
@@ -239,26 +231,23 @@ export interface TranslateResult {
239
231
  };
240
232
  }
241
233
 
242
- export function formatTranslate(
243
- result: TranslateResult,
244
- format: OutputFormat,
245
- ): string {
246
- if (format === 'json') {
247
- return JSON.stringify(result, null, 2) + '\n';
234
+ export function formatTranslate(result: TranslateResult, format: OutputFormat): string {
235
+ if (format === "json") {
236
+ return JSON.stringify(result, null, 2) + "\n";
248
237
  }
249
238
 
250
239
  if (result.success) {
251
240
  const lines: string[] = [success(result.message)];
252
241
  if (result.stats) {
253
- lines.push('');
254
- lines.push(keyValue('Adapters:', result.stats.adaptersProcessed.toString()));
255
- lines.push(keyValue('Locales:', result.stats.localesTranslated.toString()));
256
- lines.push(keyValue('Keys:', result.stats.keysTranslated.toString()));
242
+ lines.push("");
243
+ lines.push(keyValue("Adapters:", result.stats.adaptersProcessed.toString()));
244
+ lines.push(keyValue("Locales:", result.stats.localesTranslated.toString()));
245
+ lines.push(keyValue("Keys:", result.stats.keysTranslated.toString()));
257
246
  }
258
- return lines.join('\n') + '\n';
247
+ return lines.join("\n") + "\n";
259
248
  }
260
249
 
261
- return failure(result.message) + '\n';
250
+ return failure(result.message) + "\n";
262
251
  }
263
252
 
264
253
  // ─── Add formatter ───────────────────────────────────────────────────────────
@@ -269,27 +258,24 @@ export interface AddResult {
269
258
  readonly addedResources?: readonly string[];
270
259
  }
271
260
 
272
- export function formatAdd(
273
- result: AddResult,
274
- format: OutputFormat,
275
- ): string {
276
- if (format === 'json') {
277
- return JSON.stringify(result, null, 2) + '\n';
261
+ export function formatAdd(result: AddResult, format: OutputFormat): string {
262
+ if (format === "json") {
263
+ return JSON.stringify(result, null, 2) + "\n";
278
264
  }
279
265
 
280
266
  if (result.success) {
281
267
  const lines: string[] = [success(result.message)];
282
268
  if (result.addedResources && result.addedResources.length > 0) {
283
- lines.push('');
284
- lines.push(color('Added to:', C.dim));
269
+ lines.push("");
270
+ lines.push(color("Added to:", C.dim));
285
271
  for (const r of result.addedResources) {
286
272
  lines.push(` ${color(glyphs().bullet, C.dim)} ${r}`);
287
273
  }
288
274
  }
289
- return lines.join('\n') + '\n';
275
+ return lines.join("\n") + "\n";
290
276
  }
291
277
 
292
- return failure(result.message) + '\n';
278
+ return failure(result.message) + "\n";
293
279
  }
294
280
 
295
281
  // ─── Benchmark formatter ─────────────────────────────────────────────────────
@@ -304,21 +290,18 @@ export interface BenchmarkEntry {
304
290
  readonly totalAttempts: number;
305
291
  }
306
292
 
307
- export function formatBenchmark(
308
- entries: readonly BenchmarkEntry[],
309
- format: OutputFormat,
310
- ): string {
311
- if (format === 'json') {
312
- return JSON.stringify(entries, null, 2) + '\n';
293
+ export function formatBenchmark(entries: readonly BenchmarkEntry[], format: OutputFormat): string {
294
+ if (format === "json") {
295
+ return JSON.stringify(entries, null, 2) + "\n";
313
296
  }
314
297
 
315
298
  if (entries.length === 0) {
316
- return warning('No benchmark data available.') + '\n';
299
+ return warning("No benchmark data available.") + "\n";
317
300
  }
318
301
 
319
302
  const lines: string[] = [];
320
303
 
321
- lines.push(banner('Benchmark Results'));
304
+ lines.push(banner("Benchmark Results"));
322
305
 
323
306
  const rows = entries.map((e) => [
324
307
  e.strategyName,
@@ -328,23 +311,17 @@ export function formatBenchmark(
328
311
  e.totalAttempts.toString(),
329
312
  ]);
330
313
 
331
- lines.push('');
332
- lines.push(drawTable(
333
- ['Strategy', 'Chunks', 'Total', 'Avg/Chunk', 'Attempts'],
334
- rows,
335
- ));
314
+ lines.push("");
315
+ lines.push(drawTable(["Strategy", "Chunks", "Total", "Avg/Chunk", "Attempts"], rows));
336
316
 
337
- return lines.join('\n') + '\n';
317
+ return lines.join("\n") + "\n";
338
318
  }
339
319
 
340
320
  // ─── Error formatter ─────────────────────────────────────────────────────────
341
321
 
342
- export function formatError(
343
- message: string,
344
- format: OutputFormat,
345
- ): string {
346
- if (format === 'json') {
347
- return JSON.stringify({ error: message }, null, 2) + '\n';
322
+ export function formatError(message: string, format: OutputFormat): string {
323
+ if (format === "json") {
324
+ return JSON.stringify({ error: message }, null, 2) + "\n";
348
325
  }
349
- return failure(message) + '\n';
326
+ return failure(message) + "\n";
350
327
  }
package/src/cli/main.ts CHANGED
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
- import { Command } from '@effect/cli';
3
- import { NodeContext, NodeRuntime } from '@effect/platform-node';
4
- import { Effect } from 'effect';
5
- import { translateCommand } from './commands/translate.js';
6
- import { validateCommand } from './commands/validate.js';
7
- import { addCommand } from './commands/add.js';
8
- import { missingCommand } from './commands/missing.js';
9
- import { unusedCommand } from './commands/unused.js';
10
- import { languagesCommand } from './commands/languages.js';
11
- import { benchmarkCommand } from './commands/benchmark.js';
2
+ import { Command } from "@effect/cli";
3
+ import { NodeContext, NodeRuntime } from "@effect/platform-node";
4
+ import { Effect } from "effect";
5
+ import { translateCommand } from "./commands/translate.js";
6
+ import { validateCommand } from "./commands/validate.js";
7
+ import { addCommand } from "./commands/add.js";
8
+ import { missingCommand } from "./commands/missing.js";
9
+ import { unusedCommand } from "./commands/unused.js";
10
+ import { languagesCommand } from "./commands/languages.js";
11
+ import { benchmarkCommand } from "./commands/benchmark.js";
12
12
 
13
- const rootCommand = Command.make('dialekt').pipe(
13
+ const rootCommand = Command.make("dialekt").pipe(
14
14
  Command.withSubcommands([
15
15
  translateCommand,
16
16
  validateCommand,
@@ -23,8 +23,8 @@ const rootCommand = Command.make('dialekt').pipe(
23
23
  );
24
24
 
25
25
  const cli = Command.run(rootCommand, {
26
- name: 'dialekt',
27
- version: '0.1.0',
26
+ name: "dialekt",
27
+ version: "0.1.0",
28
28
  });
29
29
 
30
30
  const program = Effect.provide(cli(process.argv), NodeContext.layer);
@@ -1,15 +1,15 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { defineConfig } from './define-config.js';
3
- import type { DialektConfig } from './types.js';
1
+ import { describe, expect, it } from "vitest";
2
+ import { defineConfig } from "./define-config.js";
3
+ import type { DialektConfig } from "./types.js";
4
4
 
5
- describe('defineConfig', () => {
6
- it('returns its input unchanged', () => {
5
+ describe("defineConfig", () => {
6
+ it("returns its input unchanged", () => {
7
7
  const config: DialektConfig = {
8
- sourceLocale: 'en',
9
- targetLocales: ['de'],
10
- strategy: 'one-shot',
11
- model: { provider: 'openai', modelId: 'gpt-4o' },
12
- fastModel: { provider: 'openai', modelId: 'gpt-4o-mini' },
8
+ sourceLocale: "en",
9
+ targetLocales: ["de"],
10
+ strategy: "one-shot",
11
+ model: { provider: "openai", modelId: "gpt-4o" },
12
+ fastModel: { provider: "openai", modelId: "gpt-4o-mini" },
13
13
  chunking: { maxTokens: 3000, charsPerToken: 3.0, concurrency: 3 },
14
14
  retry: { maxAttempts: 3, baseDelayMs: 1000 },
15
15
  adapters: [],
@@ -17,14 +17,29 @@ describe('defineConfig', () => {
17
17
  expect(defineConfig(config)).toBe(config);
18
18
  });
19
19
 
20
- it('accepts a config with adapters', () => {
21
- const adapter = { name: 'test', capabilities: { canCreateResource: true, unusedKeyDetection: false }, listLocales: () => { throw new Error(); }, listResources: () => { throw new Error(); }, readResource: () => { throw new Error(); }, writeResource: () => { throw new Error(); } } as unknown as DialektConfig['adapters'][number];
20
+ it("accepts a config with adapters", () => {
21
+ const adapter = {
22
+ name: "test",
23
+ capabilities: { canCreateResource: true, unusedKeyDetection: false },
24
+ listLocales: () => {
25
+ throw new Error();
26
+ },
27
+ listResources: () => {
28
+ throw new Error();
29
+ },
30
+ readResource: () => {
31
+ throw new Error();
32
+ },
33
+ writeResource: () => {
34
+ throw new Error();
35
+ },
36
+ } as unknown as DialektConfig["adapters"][number];
22
37
  const config: DialektConfig = {
23
- sourceLocale: 'en',
24
- targetLocales: ['de'],
25
- strategy: 'one-shot',
26
- model: { provider: 'openai', modelId: 'gpt-4o' },
27
- fastModel: { provider: 'openai', modelId: 'gpt-4o-mini' },
38
+ sourceLocale: "en",
39
+ targetLocales: ["de"],
40
+ strategy: "one-shot",
41
+ model: { provider: "openai", modelId: "gpt-4o" },
42
+ fastModel: { provider: "openai", modelId: "gpt-4o-mini" },
28
43
  chunking: { maxTokens: 3000, charsPerToken: 3.0, concurrency: 3 },
29
44
  retry: { maxAttempts: 3, baseDelayMs: 1000 },
30
45
  adapters: [adapter],
@@ -32,13 +47,13 @@ describe('defineConfig', () => {
32
47
  expect(defineConfig(config)).toBe(config);
33
48
  });
34
49
 
35
- it('accepts a config with tool-loop-agent strategy', () => {
50
+ it("accepts a config with tool-loop-agent strategy", () => {
36
51
  const config: DialektConfig = {
37
- sourceLocale: 'en',
38
- targetLocales: ['de'],
39
- strategy: 'tool-loop-agent',
40
- model: { provider: 'anthropic', modelId: 'claude-3-sonnet' },
41
- fastModel: { provider: 'anthropic', modelId: 'claude-3-haiku' },
52
+ sourceLocale: "en",
53
+ targetLocales: ["de"],
54
+ strategy: "tool-loop-agent",
55
+ model: { provider: "anthropic", modelId: "claude-3-sonnet" },
56
+ fastModel: { provider: "anthropic", modelId: "claude-3-haiku" },
42
57
  chunking: { maxTokens: 4000, charsPerToken: 3.5, concurrency: 5 },
43
58
  retry: { maxAttempts: 5, baseDelayMs: 500 },
44
59
  adapters: [],
@@ -46,15 +61,15 @@ describe('defineConfig', () => {
46
61
  expect(defineConfig(config)).toBe(config);
47
62
  });
48
63
 
49
- it('preserves reference identity for nested objects', () => {
50
- const model = { provider: 'openai', modelId: 'gpt-4o' };
64
+ it("preserves reference identity for nested objects", () => {
65
+ const model = { provider: "openai", modelId: "gpt-4o" };
51
66
  const chunking = { maxTokens: 3000, charsPerToken: 3.0, concurrency: 3 };
52
67
  const config: DialektConfig = {
53
- sourceLocale: 'en',
54
- targetLocales: ['de'],
55
- strategy: 'one-shot',
68
+ sourceLocale: "en",
69
+ targetLocales: ["de"],
70
+ strategy: "one-shot",
56
71
  model,
57
- fastModel: { provider: 'openai', modelId: 'gpt-4o-mini' },
72
+ fastModel: { provider: "openai", modelId: "gpt-4o-mini" },
58
73
  chunking,
59
74
  retry: { maxAttempts: 3, baseDelayMs: 1000 },
60
75
  adapters: [],
@@ -1,4 +1,4 @@
1
- import type { DialektConfig } from './types.js';
1
+ import type { DialektConfig } from "./types.js";
2
2
 
3
3
  export function defineConfig(config: DialektConfig): DialektConfig {
4
4
  return config;
@@ -1,35 +1,38 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { Effect, Either } from 'effect';
3
- import { loadConfig, ConfigLoadError } from './load-config.js';
4
- import { writeFileSync, mkdirSync, rmSync } from 'node:fs';
5
- import { join } from 'node:path';
6
- import { tmpdir } from 'node:os';
1
+ import { describe, expect, it } from "vitest";
2
+ import { Effect, Either } from "effect";
3
+ import { loadConfig, ConfigLoadError } from "./load-config.js";
4
+ import { writeFileSync, mkdirSync, rmSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import { tmpdir } from "node:os";
7
7
 
8
- describe('loadConfig', () => {
9
- it('loads a valid dialekt.config.ts', async () => {
8
+ describe("loadConfig", () => {
9
+ it("loads a valid dialekt.config.ts", async () => {
10
10
  const dir = join(tmpdir(), `dialekt-load-config-test-${Date.now()}`);
11
11
  mkdirSync(dir, { recursive: true });
12
- const configPath = join(dir, 'dialekt.config.ts');
12
+ const configPath = join(dir, "dialekt.config.ts");
13
13
  writeFileSync(
14
14
  configPath,
15
15
  `export default { sourceLocale: 'en', targetLocales: ['de'], strategy: 'one-shot', model: { provider: 'openai', modelId: 'gpt-4o' }, fastModel: { provider: 'openai', modelId: 'gpt-4o-mini' }, chunking: { maxTokens: 3000, charsPerToken: 3.0, concurrency: 3 }, retry: { maxAttempts: 3, baseDelayMs: 1000 }, adapters: [] };`,
16
16
  );
17
17
 
18
18
  const result = await Effect.runPromise(loadConfig(configPath));
19
- expect(result.sourceLocale).toBe('en');
20
- expect(result.targetLocales).toEqual(['de']);
19
+ expect(result.sourceLocale).toBe("en");
20
+ expect(result.targetLocales).toEqual(["de"]);
21
21
 
22
22
  rmSync(dir, { recursive: true, force: true });
23
23
  });
24
24
 
25
- it('returns ConfigLoadError for a nonexistent path', async () => {
26
- const program = loadConfig('/nonexistent/path/config.ts');
27
- const exit = await Effect.runPromise(Effect.either(program)) as Either.Either<unknown, ConfigLoadError>;
28
- if (exit._tag === 'Left') {
29
- expect(exit.left._tag).toBe('ConfigLoadError');
30
- expect(exit.left.path).toBe('/nonexistent/path/config.ts');
25
+ it("returns ConfigLoadError for a nonexistent path", async () => {
26
+ const program = loadConfig("/nonexistent/path/config.ts");
27
+ const exit = (await Effect.runPromise(Effect.either(program))) as Either.Either<
28
+ unknown,
29
+ ConfigLoadError
30
+ >;
31
+ if (exit._tag === "Left") {
32
+ expect(exit.left._tag).toBe("ConfigLoadError");
33
+ expect(exit.left.path).toBe("/nonexistent/path/config.ts");
31
34
  } else {
32
- throw new Error('Expected Left');
35
+ throw new Error("Expected Left");
33
36
  }
34
37
  });
35
38
  });
@@ -1,9 +1,9 @@
1
- import { createJiti } from 'jiti';
2
- import { Effect, Data } from 'effect';
3
- import { resolve } from 'node:path';
4
- import type { DialektConfig } from './types.js';
1
+ import { createJiti } from "jiti";
2
+ import { Effect, Data } from "effect";
3
+ import { resolve } from "node:path";
4
+ import type { DialektConfig } from "./types.js";
5
5
 
6
- export class ConfigLoadError extends Data.TaggedError('ConfigLoadError')<{
6
+ export class ConfigLoadError extends Data.TaggedError("ConfigLoadError")<{
7
7
  readonly path: string;
8
8
  readonly cause: unknown;
9
9
  }> {}