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
@@ -1,98 +1,98 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { AdapterReadError, AdapterWriteError } from './types.js';
1
+ import { describe, expect, it } from "vitest";
2
+ import { AdapterReadError, AdapterWriteError } from "./types.js";
3
3
 
4
- describe('AdapterReadError', () => {
5
- it('carries adapter/locale/resource/cause', () => {
4
+ describe("AdapterReadError", () => {
5
+ it("carries adapter/locale/resource/cause", () => {
6
6
  const err = new AdapterReadError({
7
- adapter: 'laravel',
8
- locale: 'en',
9
- resource: 'validation',
10
- cause: new Error('boom'),
7
+ adapter: "laravel",
8
+ locale: "en",
9
+ resource: "validation",
10
+ cause: new Error("boom"),
11
11
  });
12
- expect(err._tag).toBe('AdapterReadError');
13
- expect(err.adapter).toBe('laravel');
14
- expect(err.locale).toBe('en');
15
- expect(err.resource).toBe('validation');
12
+ expect(err._tag).toBe("AdapterReadError");
13
+ expect(err.adapter).toBe("laravel");
14
+ expect(err.locale).toBe("en");
15
+ expect(err.resource).toBe("validation");
16
16
  });
17
17
 
18
- it('carries string cause', () => {
18
+ it("carries string cause", () => {
19
19
  const err = new AdapterReadError({
20
- adapter: 'paraglide',
21
- locale: 'de',
22
- resource: 'messages',
23
- cause: 'file not found',
20
+ adapter: "paraglide",
21
+ locale: "de",
22
+ resource: "messages",
23
+ cause: "file not found",
24
24
  });
25
- expect(err._tag).toBe('AdapterReadError');
26
- expect(err.cause).toBe('file not found');
25
+ expect(err._tag).toBe("AdapterReadError");
26
+ expect(err.cause).toBe("file not found");
27
27
  });
28
28
 
29
- it('preserves Error cause identity', () => {
30
- const cause = new Error('disk full');
29
+ it("preserves Error cause identity", () => {
30
+ const cause = new Error("disk full");
31
31
  const err = new AdapterReadError({
32
- adapter: 'laravel',
33
- locale: 'fr',
34
- resource: 'auth',
32
+ adapter: "laravel",
33
+ locale: "fr",
34
+ resource: "auth",
35
35
  cause,
36
36
  });
37
37
  expect(err.cause).toBe(cause);
38
38
  });
39
39
 
40
- it('accepts empty locale and resource', () => {
40
+ it("accepts empty locale and resource", () => {
41
41
  const err = new AdapterReadError({
42
- adapter: 'test',
43
- locale: '',
44
- resource: '',
45
- cause: 'unknown',
42
+ adapter: "test",
43
+ locale: "",
44
+ resource: "",
45
+ cause: "unknown",
46
46
  });
47
- expect(err.locale).toBe('');
48
- expect(err.resource).toBe('');
47
+ expect(err.locale).toBe("");
48
+ expect(err.resource).toBe("");
49
49
  });
50
50
 
51
- it('accepts various adapter names', () => {
52
- for (const name of ['laravel', 'paraglide', 'symfony', 'custom']) {
51
+ it("accepts various adapter names", () => {
52
+ for (const name of ["laravel", "paraglide", "symfony", "custom"]) {
53
53
  const err = new AdapterReadError({
54
54
  adapter: name,
55
- locale: 'en',
56
- resource: 'x',
57
- cause: 'test',
55
+ locale: "en",
56
+ resource: "x",
57
+ cause: "test",
58
58
  });
59
59
  expect(err.adapter).toBe(name);
60
60
  }
61
61
  });
62
62
  });
63
63
 
64
- describe('AdapterWriteError', () => {
65
- it('carries adapter/locale/resource/cause', () => {
64
+ describe("AdapterWriteError", () => {
65
+ it("carries adapter/locale/resource/cause", () => {
66
66
  const err = new AdapterWriteError({
67
- adapter: 'paraglide',
68
- locale: 'de',
69
- resource: 'messages',
70
- cause: 'disk full',
67
+ adapter: "paraglide",
68
+ locale: "de",
69
+ resource: "messages",
70
+ cause: "disk full",
71
71
  });
72
- expect(err._tag).toBe('AdapterWriteError');
73
- expect(err.adapter).toBe('paraglide');
74
- expect(err.locale).toBe('de');
75
- expect(err.resource).toBe('messages');
72
+ expect(err._tag).toBe("AdapterWriteError");
73
+ expect(err.adapter).toBe("paraglide");
74
+ expect(err.locale).toBe("de");
75
+ expect(err.resource).toBe("messages");
76
76
  });
77
77
 
78
- it('carries Error cause', () => {
79
- const cause = new Error('permission denied');
78
+ it("carries Error cause", () => {
79
+ const cause = new Error("permission denied");
80
80
  const err = new AdapterWriteError({
81
- adapter: 'laravel',
82
- locale: 'en',
83
- resource: 'validation',
81
+ adapter: "laravel",
82
+ locale: "en",
83
+ resource: "validation",
84
84
  cause,
85
85
  });
86
86
  expect(err.cause).toBe(cause);
87
87
  });
88
88
 
89
- it('accepts empty strings', () => {
89
+ it("accepts empty strings", () => {
90
90
  const err = new AdapterWriteError({
91
- adapter: '',
92
- locale: '',
93
- resource: '',
94
- cause: '',
91
+ adapter: "",
92
+ locale: "",
93
+ resource: "",
94
+ cause: "",
95
95
  });
96
- expect(err.adapter).toBe('');
96
+ expect(err.adapter).toBe("");
97
97
  });
98
98
  });
@@ -1,4 +1,4 @@
1
- import { Data, Effect } from 'effect';
1
+ import { Data, Effect } from "effect";
2
2
 
3
3
  /** Opaque adapter-specific identifier for one resource within a locale. */
4
4
  export interface ResourceRef {
@@ -6,14 +6,14 @@ export interface ResourceRef {
6
6
  readonly label: string; // human-readable, for CLI output
7
7
  }
8
8
 
9
- export class AdapterReadError extends Data.TaggedError('AdapterReadError')<{
9
+ export class AdapterReadError extends Data.TaggedError("AdapterReadError")<{
10
10
  readonly adapter: string;
11
11
  readonly locale: string;
12
12
  readonly resource: string;
13
13
  readonly cause: unknown;
14
14
  }> {}
15
15
 
16
- export class AdapterWriteError extends Data.TaggedError('AdapterWriteError')<{
16
+ export class AdapterWriteError extends Data.TaggedError("AdapterWriteError")<{
17
17
  readonly adapter: string;
18
18
  readonly locale: string;
19
19
  readonly resource: string;
@@ -34,7 +34,10 @@ export interface TranslationAdapter {
34
34
  listResources(locale: string): Effect.Effect<readonly ResourceRef[], AdapterReadError>;
35
35
 
36
36
  /** Read one resource, flattened to dot-notation key → string value. Returns {} if the resource does not exist. */
37
- readResource(locale: string, resource: ResourceRef): Effect.Effect<Record<string, string>, AdapterReadError>;
37
+ readResource(
38
+ locale: string,
39
+ resource: ResourceRef,
40
+ ): Effect.Effect<Record<string, string>, AdapterReadError>;
38
41
 
39
42
  /** Write a full flattened key→value map back to a resource, unflattening as needed. Creates the resource if absent and `create` capability allows it. */
40
43
  writeResource(
@@ -1,16 +1,35 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { Effect } from 'effect';
3
- import { summarizeBenchmarkResults, runBenchmarkedChunk } from './metrics.js';
4
- import type { ChunkBenchmarkResult } from './metrics.js';
5
- import type { TranslationStrategy, TranslationContext } from '../translation/types.js';
6
- import { TranslationFailedError } from '../translation/types.js';
1
+ import { describe, expect, it } from "vitest";
2
+ import { Effect } from "effect";
3
+ import { summarizeBenchmarkResults, runBenchmarkedChunk } from "./metrics.js";
4
+ import type { ChunkBenchmarkResult } from "./metrics.js";
5
+ import type { TranslationStrategy, TranslationContext } from "../translation/types.js";
6
+ import { TranslationFailedError } from "../translation/types.js";
7
7
 
8
- describe('summarizeBenchmarkResults', () => {
9
- it('computes totals and averages correctly', () => {
8
+ describe("summarizeBenchmarkResults", () => {
9
+ it("computes totals and averages correctly", () => {
10
10
  const results = [
11
- { strategyName: 'one-shot' as const, chunkKeyCount: 2, durationMs: 100, attemptCount: 1, succeeded: true },
12
- { strategyName: 'one-shot' as const, chunkKeyCount: 2, durationMs: 200, attemptCount: 1, succeeded: true },
13
- { strategyName: 'one-shot' as const, chunkKeyCount: 1, durationMs: 300, attemptCount: 1, succeeded: false, errorMessage: 'oops' },
11
+ {
12
+ strategyName: "one-shot" as const,
13
+ chunkKeyCount: 2,
14
+ durationMs: 100,
15
+ attemptCount: 1,
16
+ succeeded: true,
17
+ },
18
+ {
19
+ strategyName: "one-shot" as const,
20
+ chunkKeyCount: 2,
21
+ durationMs: 200,
22
+ attemptCount: 1,
23
+ succeeded: true,
24
+ },
25
+ {
26
+ strategyName: "one-shot" as const,
27
+ chunkKeyCount: 1,
28
+ durationMs: 300,
29
+ attemptCount: 1,
30
+ succeeded: false,
31
+ errorMessage: "oops",
32
+ },
14
33
  ];
15
34
  const summary = summarizeBenchmarkResults(results);
16
35
  expect(summary.totalChunks).toBe(3);
@@ -21,7 +40,7 @@ describe('summarizeBenchmarkResults', () => {
21
40
  expect(summary.totalAttempts).toBe(3);
22
41
  });
23
42
 
24
- it('handles empty results', () => {
43
+ it("handles empty results", () => {
25
44
  const summary = summarizeBenchmarkResults([]);
26
45
  expect(summary.totalChunks).toBe(0);
27
46
  expect(summary.succeededChunks).toBe(0);
@@ -29,12 +48,18 @@ describe('summarizeBenchmarkResults', () => {
29
48
  expect(summary.totalDurationMs).toBe(0);
30
49
  expect(summary.averageDurationMsPerChunk).toBe(0);
31
50
  expect(summary.totalAttempts).toBe(0);
32
- expect(summary.strategyName).toBe('one-shot');
51
+ expect(summary.strategyName).toBe("one-shot");
33
52
  });
34
53
 
35
- it('handles single result', () => {
54
+ it("handles single result", () => {
36
55
  const results = [
37
- { strategyName: 'tool-loop-agent' as const, chunkKeyCount: 5, durationMs: 150, attemptCount: 2, succeeded: true },
56
+ {
57
+ strategyName: "tool-loop-agent" as const,
58
+ chunkKeyCount: 5,
59
+ durationMs: 150,
60
+ attemptCount: 2,
61
+ succeeded: true,
62
+ },
38
63
  ];
39
64
  const summary = summarizeBenchmarkResults(results);
40
65
  expect(summary.totalChunks).toBe(1);
@@ -44,10 +69,24 @@ describe('summarizeBenchmarkResults', () => {
44
69
  expect(summary.totalAttempts).toBe(2);
45
70
  });
46
71
 
47
- it('handles all failures', () => {
72
+ it("handles all failures", () => {
48
73
  const results = [
49
- { strategyName: 'one-shot' as const, chunkKeyCount: 1, durationMs: 50, attemptCount: 1, succeeded: false, errorMessage: 'a' },
50
- { strategyName: 'one-shot' as const, chunkKeyCount: 1, durationMs: 60, attemptCount: 1, succeeded: false, errorMessage: 'b' },
74
+ {
75
+ strategyName: "one-shot" as const,
76
+ chunkKeyCount: 1,
77
+ durationMs: 50,
78
+ attemptCount: 1,
79
+ succeeded: false,
80
+ errorMessage: "a",
81
+ },
82
+ {
83
+ strategyName: "one-shot" as const,
84
+ chunkKeyCount: 1,
85
+ durationMs: 60,
86
+ attemptCount: 1,
87
+ succeeded: false,
88
+ errorMessage: "b",
89
+ },
51
90
  ];
52
91
  const summary = summarizeBenchmarkResults(results);
53
92
  expect(summary.succeededChunks).toBe(0);
@@ -55,27 +94,51 @@ describe('summarizeBenchmarkResults', () => {
55
94
  expect(summary.totalDurationMs).toBe(110);
56
95
  });
57
96
 
58
- it('handles zero-duration results', () => {
97
+ it("handles zero-duration results", () => {
59
98
  const results = [
60
- { strategyName: 'one-shot' as const, chunkKeyCount: 1, durationMs: 0, attemptCount: 1, succeeded: true },
99
+ {
100
+ strategyName: "one-shot" as const,
101
+ chunkKeyCount: 1,
102
+ durationMs: 0,
103
+ attemptCount: 1,
104
+ succeeded: true,
105
+ },
61
106
  ];
62
107
  const summary = summarizeBenchmarkResults(results);
63
108
  expect(summary.totalDurationMs).toBe(0);
64
109
  expect(summary.averageDurationMsPerChunk).toBe(0);
65
110
  });
66
111
 
67
- it('preserves strategyName from first result', () => {
112
+ it("preserves strategyName from first result", () => {
68
113
  const results = [
69
- { strategyName: 'tool-loop-agent' as const, chunkKeyCount: 1, durationMs: 100, attemptCount: 1, succeeded: true },
114
+ {
115
+ strategyName: "tool-loop-agent" as const,
116
+ chunkKeyCount: 1,
117
+ durationMs: 100,
118
+ attemptCount: 1,
119
+ succeeded: true,
120
+ },
70
121
  ];
71
122
  const summary = summarizeBenchmarkResults(results);
72
- expect(summary.strategyName).toBe('tool-loop-agent');
123
+ expect(summary.strategyName).toBe("tool-loop-agent");
73
124
  });
74
125
 
75
- it('handles very large durations without overflow', () => {
126
+ it("handles very large durations without overflow", () => {
76
127
  const results = [
77
- { strategyName: 'one-shot' as const, chunkKeyCount: 1, durationMs: 1_000_000, attemptCount: 1, succeeded: true },
78
- { strategyName: 'one-shot' as const, chunkKeyCount: 1, durationMs: 2_000_000, attemptCount: 1, succeeded: true },
128
+ {
129
+ strategyName: "one-shot" as const,
130
+ chunkKeyCount: 1,
131
+ durationMs: 1_000_000,
132
+ attemptCount: 1,
133
+ succeeded: true,
134
+ },
135
+ {
136
+ strategyName: "one-shot" as const,
137
+ chunkKeyCount: 1,
138
+ durationMs: 2_000_000,
139
+ attemptCount: 1,
140
+ succeeded: true,
141
+ },
79
142
  ];
80
143
  const summary = summarizeBenchmarkResults(results);
81
144
  expect(summary.totalDurationMs).toBe(3_000_000);
@@ -83,98 +146,107 @@ describe('summarizeBenchmarkResults', () => {
83
146
  });
84
147
  });
85
148
 
86
- describe('runBenchmarkedChunk', () => {
87
- it('measures duration and returns success', async () => {
149
+ describe("runBenchmarkedChunk", () => {
150
+ it("measures duration and returns success", async () => {
88
151
  const strategy: TranslationStrategy = {
89
- name: 'one-shot',
90
- translateChunk: () => Effect.succeed({ hello: 'Hallo' }),
152
+ name: "one-shot",
153
+ translateChunk: () => Effect.succeed({ hello: "Hallo" }),
91
154
  };
92
155
  const ctx: TranslationContext = {
93
- sourceLocale: 'en',
94
- targetLocale: 'de',
95
- sourceMap: { hello: 'Hello' },
156
+ sourceLocale: "en",
157
+ targetLocale: "de",
158
+ sourceMap: { hello: "Hello" },
96
159
  targetMap: {},
97
- keys: ['hello'],
160
+ keys: ["hello"],
98
161
  };
99
- const result = await Effect.runPromise(runBenchmarkedChunk(strategy, ctx)) as ChunkBenchmarkResult;
162
+ const result = (await Effect.runPromise(
163
+ runBenchmarkedChunk(strategy, ctx),
164
+ )) as ChunkBenchmarkResult;
100
165
  expect(result.succeeded).toBe(true);
101
166
  expect(result.chunkKeyCount).toBe(1);
102
167
  expect(result.durationMs).toBeGreaterThanOrEqual(0);
103
- expect(result.strategyName).toBe('one-shot');
168
+ expect(result.strategyName).toBe("one-shot");
104
169
  });
105
170
 
106
- it('records failure without propagating', async () => {
171
+ it("records failure without propagating", async () => {
107
172
  const strategy: TranslationStrategy = {
108
- name: 'tool-loop-agent',
109
- translateChunk: () =>
110
- Effect.fail(new TranslationFailedError({ keys: ['a'], cause: 'boom' })),
173
+ name: "tool-loop-agent",
174
+ translateChunk: () => Effect.fail(new TranslationFailedError({ keys: ["a"], cause: "boom" })),
111
175
  };
112
176
  const ctx: TranslationContext = {
113
- sourceLocale: 'en',
114
- targetLocale: 'de',
115
- sourceMap: { a: 'A' },
177
+ sourceLocale: "en",
178
+ targetLocale: "de",
179
+ sourceMap: { a: "A" },
116
180
  targetMap: {},
117
- keys: ['a'],
181
+ keys: ["a"],
118
182
  };
119
- const result = await Effect.runPromise(runBenchmarkedChunk(strategy, ctx)) as ChunkBenchmarkResult;
183
+ const result = (await Effect.runPromise(
184
+ runBenchmarkedChunk(strategy, ctx),
185
+ )) as ChunkBenchmarkResult;
120
186
  expect(result.succeeded).toBe(false);
121
- expect(result.errorMessage).toBe('boom');
187
+ expect(result.errorMessage).toBe("boom");
122
188
  expect(result.chunkKeyCount).toBe(1);
123
189
  });
124
190
 
125
- it('handles empty key list', async () => {
191
+ it("handles empty key list", async () => {
126
192
  const strategy: TranslationStrategy = {
127
- name: 'one-shot',
193
+ name: "one-shot",
128
194
  translateChunk: () => Effect.succeed({}),
129
195
  };
130
196
  const ctx: TranslationContext = {
131
- sourceLocale: 'en',
132
- targetLocale: 'de',
197
+ sourceLocale: "en",
198
+ targetLocale: "de",
133
199
  sourceMap: {},
134
200
  targetMap: {},
135
201
  keys: [],
136
202
  };
137
- const result = await Effect.runPromise(runBenchmarkedChunk(strategy, ctx)) as ChunkBenchmarkResult;
203
+ const result = (await Effect.runPromise(
204
+ runBenchmarkedChunk(strategy, ctx),
205
+ )) as ChunkBenchmarkResult;
138
206
  expect(result.succeeded).toBe(true);
139
207
  expect(result.chunkKeyCount).toBe(0);
140
208
  });
141
209
 
142
- it('measures duration for slow strategies', async () => {
210
+ it("measures duration for slow strategies", async () => {
143
211
  const strategy: TranslationStrategy = {
144
- name: 'tool-loop-agent',
212
+ name: "tool-loop-agent",
145
213
  translateChunk: () =>
146
214
  Effect.gen(function* () {
147
- yield* Effect.sleep('50 millis');
148
- return { k: 'v' };
215
+ yield* Effect.sleep("50 millis");
216
+ return { k: "v" };
149
217
  }),
150
218
  };
151
219
  const ctx: TranslationContext = {
152
- sourceLocale: 'en',
153
- targetLocale: 'de',
154
- sourceMap: { k: 'K' },
220
+ sourceLocale: "en",
221
+ targetLocale: "de",
222
+ sourceMap: { k: "K" },
155
223
  targetMap: {},
156
- keys: ['k'],
224
+ keys: ["k"],
157
225
  };
158
- const result = await Effect.runPromise(runBenchmarkedChunk(strategy, ctx)) as ChunkBenchmarkResult;
226
+ const result = (await Effect.runPromise(
227
+ runBenchmarkedChunk(strategy, ctx),
228
+ )) as ChunkBenchmarkResult;
159
229
  expect(result.succeeded).toBe(true);
160
230
  expect(result.durationMs).toBeGreaterThanOrEqual(30);
161
231
  });
162
232
 
163
- it('captures Error cause in errorMessage', async () => {
233
+ it("captures Error cause in errorMessage", async () => {
164
234
  const strategy: TranslationStrategy = {
165
- name: 'one-shot',
235
+ name: "one-shot",
166
236
  translateChunk: () =>
167
- Effect.fail(new TranslationFailedError({ keys: ['x'], cause: new Error('deep error') })),
237
+ Effect.fail(new TranslationFailedError({ keys: ["x"], cause: new Error("deep error") })),
168
238
  };
169
239
  const ctx: TranslationContext = {
170
- sourceLocale: 'en',
171
- targetLocale: 'de',
172
- sourceMap: { x: 'X' },
240
+ sourceLocale: "en",
241
+ targetLocale: "de",
242
+ sourceMap: { x: "X" },
173
243
  targetMap: {},
174
- keys: ['x'],
244
+ keys: ["x"],
175
245
  };
176
- const result = await Effect.runPromise(runBenchmarkedChunk(strategy, ctx)) as ChunkBenchmarkResult;
246
+ const result = (await Effect.runPromise(
247
+ runBenchmarkedChunk(strategy, ctx),
248
+ )) as ChunkBenchmarkResult;
177
249
  expect(result.succeeded).toBe(false);
178
- expect(result.errorMessage).toContain('deep error');
250
+ expect(result.errorMessage).toContain("deep error");
179
251
  });
180
252
  });
@@ -1,8 +1,8 @@
1
- import { Effect } from 'effect';
2
- import type { TranslationStrategy, TranslationContext } from '../translation/types.js';
1
+ import { Effect } from "effect";
2
+ import type { TranslationStrategy, TranslationContext } from "../translation/types.js";
3
3
 
4
4
  export interface ChunkBenchmarkResult {
5
- readonly strategyName: 'one-shot' | 'tool-loop-agent';
5
+ readonly strategyName: "one-shot" | "tool-loop-agent";
6
6
  readonly chunkKeyCount: number;
7
7
  readonly durationMs: number;
8
8
  readonly attemptCount: number;
@@ -11,7 +11,7 @@ export interface ChunkBenchmarkResult {
11
11
  }
12
12
 
13
13
  export interface StrategyBenchmarkSummary {
14
- readonly strategyName: 'one-shot' | 'tool-loop-agent';
14
+ readonly strategyName: "one-shot" | "tool-loop-agent";
15
15
  readonly totalChunks: number;
16
16
  readonly succeededChunks: number;
17
17
  readonly failedChunks: number;
@@ -29,7 +29,7 @@ export function summarizeBenchmarkResults(
29
29
  const totalDurationMs = results.reduce((sum, r) => sum + r.durationMs, 0);
30
30
  const totalAttempts = results.reduce((sum, r) => sum + r.attemptCount, 0);
31
31
  return {
32
- strategyName: results[0]?.strategyName ?? 'one-shot',
32
+ strategyName: results[0]?.strategyName ?? "one-shot",
33
33
  totalChunks,
34
34
  succeededChunks,
35
35
  failedChunks,
@@ -47,7 +47,7 @@ export function runBenchmarkedChunk(
47
47
  const start = Date.now();
48
48
  const result = yield* Effect.either(strategy.translateChunk(ctx));
49
49
  const durationMs = Date.now() - start;
50
- if (result._tag === 'Right') {
50
+ if (result._tag === "Right") {
51
51
  return {
52
52
  strategyName: strategy.name,
53
53
  chunkKeyCount: ctx.keys.length,