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.
- package/README.md +8 -10
- package/TESTING.md +29 -29
- package/dist/cli/main.d.mts +1 -1
- package/dist/cli/main.mjs +549 -362
- package/dist/formatters-De4Q-X1d.mjs +516 -435
- package/dist/index.d.mts +162 -25
- package/dist/index.mjs +119 -34
- package/package.json +3 -3
- package/pnpm-workspace.yaml +3 -3
- package/src/adapter/types.test.ts +57 -57
- package/src/adapter/types.ts +7 -4
- package/src/benchmark/metrics.test.ts +141 -69
- package/src/benchmark/metrics.ts +6 -6
- package/src/benchmark/report.test.ts +38 -38
- package/src/benchmark/report.ts +6 -6
- package/src/benchmark/runner.test.ts +70 -72
- package/src/benchmark/runner.ts +4 -4
- package/src/cli/commands/add.test.ts +90 -109
- package/src/cli/commands/add.ts +40 -28
- package/src/cli/commands/benchmark.test.ts +77 -64
- package/src/cli/commands/benchmark.ts +64 -41
- package/src/cli/commands/languages.test.ts +45 -42
- package/src/cli/commands/languages.ts +16 -12
- package/src/cli/commands/missing.test.ts +143 -92
- package/src/cli/commands/missing.ts +24 -17
- package/src/cli/commands/translate.test.ts +79 -79
- package/src/cli/commands/translate.ts +41 -31
- package/src/cli/commands/unused.test.ts +62 -51
- package/src/cli/commands/unused.ts +18 -14
- package/src/cli/commands/validate.test.ts +130 -72
- package/src/cli/commands/validate.ts +25 -20
- package/src/cli/config-resolution.test.ts +169 -49
- package/src/cli/config-resolution.ts +5 -7
- package/src/cli/format.test.ts +50 -50
- package/src/cli/format.ts +57 -60
- package/src/cli/formatters.test.ts +128 -106
- package/src/cli/formatters.ts +72 -95
- package/src/cli/main.ts +13 -13
- package/src/config/define-config.test.ts +44 -29
- package/src/config/define-config.ts +1 -1
- package/src/config/load-config.test.ts +21 -18
- package/src/config/load-config.ts +5 -5
- package/src/config/types.test.ts +50 -44
- package/src/config/types.ts +2 -2
- package/src/index.ts +22 -26
- package/src/keys/flatten.test.ts +52 -52
- package/src/keys/flatten.ts +7 -9
- package/src/sdk/file-io.test.ts +47 -59
- package/src/sdk/file-io.ts +2 -2
- package/src/sdk/node-layer.test.ts +18 -18
- package/src/sdk/node-layer.ts +2 -2
- package/src/sdk/php-array-reader.test.ts +49 -40
- package/src/sdk/php-array-reader.ts +5 -5
- package/src/translation/chunking.test.ts +52 -44
- package/src/translation/chunking.ts +1 -1
- package/src/translation/missing-keys.test.ts +86 -93
- package/src/translation/missing-keys.ts +4 -6
- package/src/translation/model-registry.test.ts +41 -32
- package/src/translation/model-registry.ts +9 -9
- package/src/translation/one-shot-strategy.test.ts +105 -86
- package/src/translation/one-shot-strategy.ts +10 -12
- package/src/translation/orchestrator.test.ts +90 -101
- package/src/translation/orchestrator.ts +26 -26
- package/src/translation/prompt.test.ts +76 -76
- package/src/translation/prompt.ts +2 -2
- package/src/translation/tool-loop-strategy.test.ts +134 -107
- package/src/translation/tool-loop-strategy.ts +14 -18
- package/src/translation/types.test.ts +22 -22
- package/src/translation/types.ts +3 -3
- package/tsdown.config.ts +3 -3
- package/vitest.config.ts +3 -3
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { describe, expect, it } from
|
|
2
|
-
import { Effect, Option } from
|
|
3
|
-
import { runUnused, unusedCommand } from
|
|
4
|
-
import type { DialektConfig } from
|
|
5
|
-
import type { TranslationAdapter, ResourceRef } from
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { Effect, Option } from "effect";
|
|
3
|
+
import { runUnused, unusedCommand } from "./unused.js";
|
|
4
|
+
import type { DialektConfig } from "../../config/types.js";
|
|
5
|
+
import type { TranslationAdapter, ResourceRef } from "../../adapter/types.js";
|
|
6
6
|
|
|
7
|
-
describe(
|
|
7
|
+
describe("runUnused", () => {
|
|
8
8
|
const baseConfig: DialektConfig = {
|
|
9
|
-
sourceLocale:
|
|
10
|
-
targetLocales: [
|
|
11
|
-
strategy:
|
|
12
|
-
model: { provider:
|
|
13
|
-
fastModel: { provider:
|
|
9
|
+
sourceLocale: "en",
|
|
10
|
+
targetLocales: ["de", "fr"],
|
|
11
|
+
strategy: "one-shot",
|
|
12
|
+
model: { provider: "openai", modelId: "gpt-4o" },
|
|
13
|
+
fastModel: { provider: "openai", modelId: "gpt-4o-mini" },
|
|
14
14
|
chunking: { maxTokens: 3000, charsPerToken: 3.0, concurrency: 3 },
|
|
15
15
|
retry: { maxAttempts: 3, baseDelayMs: 1000 },
|
|
16
16
|
adapters: [],
|
|
@@ -29,8 +29,9 @@ describe('runUnused', () => {
|
|
|
29
29
|
canCreateResource: true,
|
|
30
30
|
unusedKeyDetection: opts.hasUnusedDetection ?? true,
|
|
31
31
|
},
|
|
32
|
-
listLocales: () => Effect.succeed(opts.locales ?? [
|
|
33
|
-
listResources: () =>
|
|
32
|
+
listLocales: () => Effect.succeed(opts.locales ?? ["en", "de"]),
|
|
33
|
+
listResources: () =>
|
|
34
|
+
Effect.succeed(opts.resources ?? [{ key: "messages", label: "messages" }]),
|
|
34
35
|
readResource: () => Effect.succeed({}),
|
|
35
36
|
writeResource: () => Effect.void,
|
|
36
37
|
};
|
|
@@ -43,13 +44,13 @@ describe('runUnused', () => {
|
|
|
43
44
|
return base as TranslationAdapter;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
it(
|
|
47
|
+
it("logs unused keys for capable adapters", async () => {
|
|
47
48
|
const logs: string[] = [];
|
|
48
|
-
const adapter = makeAdapter({ name:
|
|
49
|
-
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig[
|
|
49
|
+
const adapter = makeAdapter({ name: "test", unused: ["old_key", "another"] });
|
|
50
|
+
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig["adapters"] };
|
|
50
51
|
|
|
51
52
|
const program = runUnused(
|
|
52
|
-
{ config:
|
|
53
|
+
{ config: "./config.ts", adapter: Option.none(), baseLanguage: Option.none() },
|
|
53
54
|
() => Effect.succeed(config),
|
|
54
55
|
(msg) => Effect.sync(() => logs.push(msg)),
|
|
55
56
|
() => Effect.void,
|
|
@@ -59,19 +60,19 @@ describe('runUnused', () => {
|
|
|
59
60
|
expect(logs).toHaveLength(1);
|
|
60
61
|
const parsed = JSON.parse(logs[0]!);
|
|
61
62
|
expect(parsed).toEqual([
|
|
62
|
-
{ adapter:
|
|
63
|
-
{ adapter:
|
|
63
|
+
{ adapter: "test", locale: "en", resource: "messages", key: "old_key" },
|
|
64
|
+
{ adapter: "test", locale: "en", resource: "messages", key: "another" },
|
|
64
65
|
]);
|
|
65
66
|
});
|
|
66
67
|
|
|
67
|
-
it(
|
|
68
|
+
it("skips adapters without unusedKeyDetection with a warning", async () => {
|
|
68
69
|
const logs: string[] = [];
|
|
69
70
|
const errors: string[] = [];
|
|
70
|
-
const legacy = makeAdapter({ name:
|
|
71
|
-
const config = { ...baseConfig, adapters: [legacy] as unknown as DialektConfig[
|
|
71
|
+
const legacy = makeAdapter({ name: "legacy", hasUnusedDetection: false });
|
|
72
|
+
const config = { ...baseConfig, adapters: [legacy] as unknown as DialektConfig["adapters"] };
|
|
72
73
|
|
|
73
74
|
const program = runUnused(
|
|
74
|
-
{ config:
|
|
75
|
+
{ config: "./config.ts", adapter: Option.none(), baseLanguage: Option.none() },
|
|
75
76
|
() => Effect.succeed(config),
|
|
76
77
|
(msg) => Effect.sync(() => logs.push(msg)),
|
|
77
78
|
(msg) => Effect.sync(() => errors.push(msg)),
|
|
@@ -86,20 +87,20 @@ describe('runUnused', () => {
|
|
|
86
87
|
expect(JSON.parse(logs[0]!)).toEqual([]);
|
|
87
88
|
});
|
|
88
89
|
|
|
89
|
-
it(
|
|
90
|
+
it("handles multiple resources", async () => {
|
|
90
91
|
const logs: string[] = [];
|
|
91
92
|
const adapter = makeAdapter({
|
|
92
|
-
name:
|
|
93
|
+
name: "multi",
|
|
93
94
|
resources: [
|
|
94
|
-
{ key:
|
|
95
|
-
{ key:
|
|
95
|
+
{ key: "auth", label: "auth" },
|
|
96
|
+
{ key: "validation", label: "validation" },
|
|
96
97
|
],
|
|
97
|
-
unused: [
|
|
98
|
+
unused: ["unused_auth"],
|
|
98
99
|
});
|
|
99
|
-
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig[
|
|
100
|
+
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig["adapters"] };
|
|
100
101
|
|
|
101
102
|
const program = runUnused(
|
|
102
|
-
{ config:
|
|
103
|
+
{ config: "./config.ts", adapter: Option.none(), baseLanguage: Option.none() },
|
|
103
104
|
() => Effect.succeed(config),
|
|
104
105
|
(msg) => Effect.sync(() => logs.push(msg)),
|
|
105
106
|
() => Effect.void,
|
|
@@ -108,15 +109,20 @@ describe('runUnused', () => {
|
|
|
108
109
|
await Effect.runPromise(program);
|
|
109
110
|
expect(logs).toHaveLength(1);
|
|
110
111
|
const parsed = JSON.parse(logs[0]!);
|
|
111
|
-
expect(parsed).toContainEqual({
|
|
112
|
+
expect(parsed).toContainEqual({
|
|
113
|
+
adapter: "multi",
|
|
114
|
+
locale: "en",
|
|
115
|
+
resource: "auth",
|
|
116
|
+
key: "unused_auth",
|
|
117
|
+
});
|
|
112
118
|
});
|
|
113
119
|
|
|
114
|
-
it(
|
|
120
|
+
it("handles empty adapter list", async () => {
|
|
115
121
|
const logs: string[] = [];
|
|
116
122
|
const config = { ...baseConfig, adapters: [] };
|
|
117
123
|
|
|
118
124
|
const program = runUnused(
|
|
119
|
-
{ config:
|
|
125
|
+
{ config: "./config.ts", adapter: Option.none(), baseLanguage: Option.none() },
|
|
120
126
|
() => Effect.succeed(config),
|
|
121
127
|
(msg) => Effect.sync(() => logs.push(msg)),
|
|
122
128
|
() => Effect.void,
|
|
@@ -127,13 +133,13 @@ describe('runUnused', () => {
|
|
|
127
133
|
expect(JSON.parse(logs[0]!)).toEqual([]);
|
|
128
134
|
});
|
|
129
135
|
|
|
130
|
-
it(
|
|
136
|
+
it("handles adapter with no resources", async () => {
|
|
131
137
|
const logs: string[] = [];
|
|
132
|
-
const adapter = makeAdapter({ name:
|
|
133
|
-
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig[
|
|
138
|
+
const adapter = makeAdapter({ name: "empty", resources: [] });
|
|
139
|
+
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig["adapters"] };
|
|
134
140
|
|
|
135
141
|
const program = runUnused(
|
|
136
|
-
{ config:
|
|
142
|
+
{ config: "./config.ts", adapter: Option.none(), baseLanguage: Option.none() },
|
|
137
143
|
() => Effect.succeed(config),
|
|
138
144
|
(msg) => Effect.sync(() => logs.push(msg)),
|
|
139
145
|
() => Effect.void,
|
|
@@ -144,13 +150,13 @@ describe('runUnused', () => {
|
|
|
144
150
|
expect(JSON.parse(logs[0]!)).toEqual([]);
|
|
145
151
|
});
|
|
146
152
|
|
|
147
|
-
it(
|
|
153
|
+
it("handles no unused keys gracefully", async () => {
|
|
148
154
|
const logs: string[] = [];
|
|
149
|
-
const adapter = makeAdapter({ name:
|
|
150
|
-
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig[
|
|
155
|
+
const adapter = makeAdapter({ name: "clean", unused: [] });
|
|
156
|
+
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig["adapters"] };
|
|
151
157
|
|
|
152
158
|
const program = runUnused(
|
|
153
|
-
{ config:
|
|
159
|
+
{ config: "./config.ts", adapter: Option.none(), baseLanguage: Option.none() },
|
|
154
160
|
() => Effect.succeed(config),
|
|
155
161
|
(msg) => Effect.sync(() => logs.push(msg)),
|
|
156
162
|
() => Effect.void,
|
|
@@ -161,24 +167,29 @@ describe('runUnused', () => {
|
|
|
161
167
|
expect(JSON.parse(logs[0]!)).toEqual([]);
|
|
162
168
|
});
|
|
163
169
|
|
|
164
|
-
it(
|
|
170
|
+
it("fails when configLoader fails", async () => {
|
|
165
171
|
const program = runUnused(
|
|
166
|
-
{ config:
|
|
167
|
-
() => Effect.fail(new Error(
|
|
172
|
+
{ config: "./missing.ts", adapter: Option.none(), baseLanguage: Option.none() },
|
|
173
|
+
() => Effect.fail(new Error("Config not found")),
|
|
168
174
|
() => Effect.void,
|
|
169
175
|
() => Effect.void,
|
|
170
176
|
);
|
|
171
177
|
|
|
172
|
-
await expect(Effect.runPromise(program)).rejects.toThrow(
|
|
178
|
+
await expect(Effect.runPromise(program)).rejects.toThrow("Config not found");
|
|
173
179
|
});
|
|
174
180
|
|
|
175
|
-
it(
|
|
181
|
+
it("outputs pretty when --format pretty is passed", async () => {
|
|
176
182
|
const logs: string[] = [];
|
|
177
|
-
const adapter = makeAdapter({ name:
|
|
178
|
-
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig[
|
|
183
|
+
const adapter = makeAdapter({ name: "test", unused: ["old_key"] });
|
|
184
|
+
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig["adapters"] };
|
|
179
185
|
|
|
180
186
|
const program = runUnused(
|
|
181
|
-
{
|
|
187
|
+
{
|
|
188
|
+
config: "./config.ts",
|
|
189
|
+
adapter: Option.none(),
|
|
190
|
+
baseLanguage: Option.none(),
|
|
191
|
+
format: Option.some("pretty"),
|
|
192
|
+
},
|
|
182
193
|
() => Effect.succeed(config),
|
|
183
194
|
(msg) => Effect.sync(() => logs.push(msg)),
|
|
184
195
|
() => Effect.void,
|
|
@@ -186,7 +197,7 @@ describe('runUnused', () => {
|
|
|
186
197
|
|
|
187
198
|
await Effect.runPromise(program);
|
|
188
199
|
expect(logs).toHaveLength(1);
|
|
189
|
-
expect(logs[0]).toContain(
|
|
190
|
-
expect(logs[0]).toContain(
|
|
200
|
+
expect(logs[0]).toContain("test");
|
|
201
|
+
expect(logs[0]).toContain("old_key");
|
|
191
202
|
});
|
|
192
203
|
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { Command, Options } from
|
|
2
|
-
import { Effect, Console, Option } from
|
|
3
|
-
import { loadConfig } from
|
|
4
|
-
import { resolveEffectiveConfig } from
|
|
5
|
-
import { detectFormat, type OutputFormat } from
|
|
6
|
-
import { formatUnusedKeys, formatError } from
|
|
7
|
-
import type { DialektConfig } from
|
|
8
|
-
import type { TranslationAdapter, ResourceRef } from
|
|
1
|
+
import { Command, Options } from "@effect/cli";
|
|
2
|
+
import { Effect, Console, Option } from "effect";
|
|
3
|
+
import { loadConfig } from "../../config/load-config.js";
|
|
4
|
+
import { resolveEffectiveConfig } from "../config-resolution.js";
|
|
5
|
+
import { detectFormat, type OutputFormat } from "../format.js";
|
|
6
|
+
import { formatUnusedKeys, formatError } from "../formatters.js";
|
|
7
|
+
import type { DialektConfig } from "../../config/types.js";
|
|
8
|
+
import type { TranslationAdapter, ResourceRef } from "../../adapter/types.js";
|
|
9
9
|
|
|
10
10
|
export interface UnusedFlags {
|
|
11
11
|
readonly config: string;
|
|
@@ -79,9 +79,13 @@ export function runUnused(
|
|
|
79
79
|
}).pipe(Effect.mapError((e) => e as never)) as Effect.Effect<void, never, never>;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
export const unusedCommand = Command.make(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
82
|
+
export const unusedCommand = Command.make(
|
|
83
|
+
"unused",
|
|
84
|
+
{
|
|
85
|
+
config: Options.text("config").pipe(Options.withDefault("./dialekt.config.ts")),
|
|
86
|
+
adapter: Options.optional(Options.text("adapter")),
|
|
87
|
+
baseLanguage: Options.optional(Options.text("base-language")),
|
|
88
|
+
format: Options.optional(Options.text("format")),
|
|
89
|
+
},
|
|
90
|
+
(flags) => runUnused(flags),
|
|
91
|
+
);
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { describe, expect, it } from
|
|
2
|
-
import { Effect, Option } from
|
|
3
|
-
import { runValidate, validateCommand } from
|
|
4
|
-
import type { DialektConfig } from
|
|
5
|
-
import type { TranslationAdapter, ResourceRef } from
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { Effect, Option } from "effect";
|
|
3
|
+
import { runValidate, validateCommand } from "./validate.js";
|
|
4
|
+
import type { DialektConfig } from "../../config/types.js";
|
|
5
|
+
import type { TranslationAdapter, ResourceRef } from "../../adapter/types.js";
|
|
6
6
|
|
|
7
|
-
describe(
|
|
7
|
+
describe("runValidate", () => {
|
|
8
8
|
const baseConfig: DialektConfig = {
|
|
9
|
-
sourceLocale:
|
|
10
|
-
targetLocales: [
|
|
11
|
-
strategy:
|
|
12
|
-
model: { provider:
|
|
13
|
-
fastModel: { provider:
|
|
9
|
+
sourceLocale: "en",
|
|
10
|
+
targetLocales: ["de", "fr"],
|
|
11
|
+
strategy: "one-shot",
|
|
12
|
+
model: { provider: "openai", modelId: "gpt-4o" },
|
|
13
|
+
fastModel: { provider: "openai", modelId: "gpt-4o-mini" },
|
|
14
14
|
chunking: { maxTokens: 3000, charsPerToken: 3.0, concurrency: 3 },
|
|
15
15
|
retry: { maxAttempts: 3, baseDelayMs: 1000 },
|
|
16
16
|
adapters: [],
|
|
@@ -24,20 +24,25 @@ describe('runValidate', () => {
|
|
|
24
24
|
return {
|
|
25
25
|
name: opts.name,
|
|
26
26
|
capabilities: { canCreateResource: true, unusedKeyDetection: false },
|
|
27
|
-
listLocales: () => Effect.succeed(opts.locales ?? [
|
|
28
|
-
listResources: () => Effect.succeed([{ key:
|
|
27
|
+
listLocales: () => Effect.succeed(opts.locales ?? ["en", "de"]),
|
|
28
|
+
listResources: () => Effect.succeed([{ key: "messages", label: "messages" }]),
|
|
29
29
|
readResource: () => Effect.succeed({}),
|
|
30
30
|
writeResource: () => Effect.void,
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
it(
|
|
34
|
+
it("passes when no keys are missing", async () => {
|
|
35
35
|
const logs: string[] = [];
|
|
36
|
-
const adapter = makeAdapter({ name:
|
|
37
|
-
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig[
|
|
36
|
+
const adapter = makeAdapter({ name: "test" });
|
|
37
|
+
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig["adapters"] };
|
|
38
38
|
|
|
39
39
|
const program = runValidate(
|
|
40
|
-
{
|
|
40
|
+
{
|
|
41
|
+
config: "./config.ts",
|
|
42
|
+
adapter: Option.none(),
|
|
43
|
+
baseLanguage: Option.none(),
|
|
44
|
+
language: Option.none(),
|
|
45
|
+
},
|
|
41
46
|
() => Effect.succeed(config),
|
|
42
47
|
() => Effect.succeed([]),
|
|
43
48
|
(msg) => Effect.sync(() => logs.push(msg)),
|
|
@@ -50,20 +55,22 @@ describe('runValidate', () => {
|
|
|
50
55
|
expect(parsed.entries).toEqual([]);
|
|
51
56
|
});
|
|
52
57
|
|
|
53
|
-
it(
|
|
58
|
+
it("fails and reports missing keys", async () => {
|
|
54
59
|
const logs: string[] = [];
|
|
55
|
-
const adapter = makeAdapter({ name:
|
|
56
|
-
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig[
|
|
57
|
-
const resource: ResourceRef = { key:
|
|
60
|
+
const adapter = makeAdapter({ name: "test" });
|
|
61
|
+
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig["adapters"] };
|
|
62
|
+
const resource: ResourceRef = { key: "messages", label: "messages" };
|
|
58
63
|
|
|
59
64
|
const originalExitCode = process.exitCode;
|
|
60
65
|
const program = runValidate(
|
|
61
|
-
{
|
|
66
|
+
{
|
|
67
|
+
config: "./config.ts",
|
|
68
|
+
adapter: Option.none(),
|
|
69
|
+
baseLanguage: Option.none(),
|
|
70
|
+
language: Option.none(),
|
|
71
|
+
},
|
|
62
72
|
() => Effect.succeed(config),
|
|
63
|
-
() =>
|
|
64
|
-
Effect.succeed([
|
|
65
|
-
{ adapter: 'test', locale: 'de', resource, missing: ['hello'] },
|
|
66
|
-
]),
|
|
73
|
+
() => Effect.succeed([{ adapter: "test", locale: "de", resource, missing: ["hello"] }]),
|
|
67
74
|
(msg) => Effect.sync(() => logs.push(msg)),
|
|
68
75
|
);
|
|
69
76
|
|
|
@@ -74,23 +81,33 @@ describe('runValidate', () => {
|
|
|
74
81
|
const parsed = JSON.parse(logs[0]!);
|
|
75
82
|
expect(parsed.passing).toBe(false);
|
|
76
83
|
expect(parsed.entries).toHaveLength(1);
|
|
77
|
-
expect(parsed.entries[0]).toMatchObject({
|
|
84
|
+
expect(parsed.entries[0]).toMatchObject({
|
|
85
|
+
adapter: "test",
|
|
86
|
+
locale: "de",
|
|
87
|
+
resource: "messages",
|
|
88
|
+
count: 1,
|
|
89
|
+
});
|
|
78
90
|
});
|
|
79
91
|
|
|
80
|
-
it(
|
|
92
|
+
it("reports missing keys for multiple adapters", async () => {
|
|
81
93
|
const logs: string[] = [];
|
|
82
|
-
const a1 = makeAdapter({ name:
|
|
83
|
-
const a2 = makeAdapter({ name:
|
|
84
|
-
const config = { ...baseConfig, adapters: [a1, a2] as unknown as DialektConfig[
|
|
85
|
-
const resource: ResourceRef = { key:
|
|
94
|
+
const a1 = makeAdapter({ name: "a1" });
|
|
95
|
+
const a2 = makeAdapter({ name: "a2", locales: ["en", "fr"] });
|
|
96
|
+
const config = { ...baseConfig, adapters: [a1, a2] as unknown as DialektConfig["adapters"] };
|
|
97
|
+
const resource: ResourceRef = { key: "messages", label: "messages" };
|
|
86
98
|
|
|
87
99
|
const originalExitCode = process.exitCode;
|
|
88
100
|
const program = runValidate(
|
|
89
|
-
{
|
|
101
|
+
{
|
|
102
|
+
config: "./config.ts",
|
|
103
|
+
adapter: Option.none(),
|
|
104
|
+
baseLanguage: Option.none(),
|
|
105
|
+
language: Option.none(),
|
|
106
|
+
},
|
|
90
107
|
() => Effect.succeed(config),
|
|
91
108
|
(a) =>
|
|
92
109
|
Effect.succeed([
|
|
93
|
-
{ adapter: a.name, locale: a.name ===
|
|
110
|
+
{ adapter: a.name, locale: a.name === "a1" ? "de" : "fr", resource, missing: ["k1"] },
|
|
94
111
|
]),
|
|
95
112
|
(msg) => Effect.sync(() => logs.push(msg)),
|
|
96
113
|
);
|
|
@@ -104,14 +121,19 @@ describe('runValidate', () => {
|
|
|
104
121
|
expect(parsed.entries).toHaveLength(2);
|
|
105
122
|
});
|
|
106
123
|
|
|
107
|
-
it(
|
|
124
|
+
it("filters by --adapter flag", async () => {
|
|
108
125
|
let queriedAdapter: string | undefined;
|
|
109
|
-
const a1 = makeAdapter({ name:
|
|
110
|
-
const a2 = makeAdapter({ name:
|
|
111
|
-
const config = { ...baseConfig, adapters: [a1, a2] as unknown as DialektConfig[
|
|
126
|
+
const a1 = makeAdapter({ name: "a1" });
|
|
127
|
+
const a2 = makeAdapter({ name: "a2" });
|
|
128
|
+
const config = { ...baseConfig, adapters: [a1, a2] as unknown as DialektConfig["adapters"] };
|
|
112
129
|
|
|
113
130
|
const program = runValidate(
|
|
114
|
-
{
|
|
131
|
+
{
|
|
132
|
+
config: "./config.ts",
|
|
133
|
+
adapter: Option.some("a2"),
|
|
134
|
+
baseLanguage: Option.none(),
|
|
135
|
+
language: Option.none(),
|
|
136
|
+
},
|
|
115
137
|
() => Effect.succeed(config),
|
|
116
138
|
(a) =>
|
|
117
139
|
Effect.sync(() => {
|
|
@@ -122,62 +144,82 @@ describe('runValidate', () => {
|
|
|
122
144
|
);
|
|
123
145
|
|
|
124
146
|
await Effect.runPromise(program);
|
|
125
|
-
expect(queriedAdapter).toBe(
|
|
147
|
+
expect(queriedAdapter).toBe("a2");
|
|
126
148
|
});
|
|
127
149
|
|
|
128
|
-
it(
|
|
150
|
+
it("fails when configLoader fails", async () => {
|
|
129
151
|
const program = runValidate(
|
|
130
|
-
{
|
|
131
|
-
|
|
152
|
+
{
|
|
153
|
+
config: "./missing.ts",
|
|
154
|
+
adapter: Option.none(),
|
|
155
|
+
baseLanguage: Option.none(),
|
|
156
|
+
language: Option.none(),
|
|
157
|
+
},
|
|
158
|
+
() => Effect.fail(new Error("Config not found")),
|
|
132
159
|
() => Effect.succeed([]),
|
|
133
160
|
() => Effect.void,
|
|
134
161
|
);
|
|
135
162
|
|
|
136
|
-
await expect(Effect.runPromise(program)).rejects.toThrow(
|
|
163
|
+
await expect(Effect.runPromise(program)).rejects.toThrow("Config not found");
|
|
137
164
|
});
|
|
138
165
|
|
|
139
|
-
it(
|
|
166
|
+
it("fails when listLocales fails", async () => {
|
|
140
167
|
const adapter: TranslationAdapter = {
|
|
141
|
-
name:
|
|
168
|
+
name: "broken",
|
|
142
169
|
capabilities: { canCreateResource: true, unusedKeyDetection: false },
|
|
143
|
-
listLocales: () => Effect.fail(new Error(
|
|
170
|
+
listLocales: () => Effect.fail(new Error("disk error") as never),
|
|
144
171
|
listResources: () => Effect.succeed([]),
|
|
145
172
|
readResource: () => Effect.succeed({}),
|
|
146
173
|
writeResource: () => Effect.void,
|
|
147
174
|
};
|
|
148
|
-
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig[
|
|
175
|
+
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig["adapters"] };
|
|
149
176
|
|
|
150
177
|
const program = runValidate(
|
|
151
|
-
{
|
|
178
|
+
{
|
|
179
|
+
config: "./config.ts",
|
|
180
|
+
adapter: Option.none(),
|
|
181
|
+
baseLanguage: Option.none(),
|
|
182
|
+
language: Option.none(),
|
|
183
|
+
},
|
|
152
184
|
() => Effect.succeed(config),
|
|
153
185
|
() => Effect.succeed([]),
|
|
154
186
|
() => Effect.void,
|
|
155
187
|
);
|
|
156
188
|
|
|
157
|
-
await expect(Effect.runPromise(program)).rejects.toThrow(
|
|
189
|
+
await expect(Effect.runPromise(program)).rejects.toThrow("disk error");
|
|
158
190
|
});
|
|
159
191
|
|
|
160
|
-
it(
|
|
161
|
-
const adapter = makeAdapter({ name:
|
|
162
|
-
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig[
|
|
192
|
+
it("fails when missingKeysComputer fails", async () => {
|
|
193
|
+
const adapter = makeAdapter({ name: "test" });
|
|
194
|
+
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig["adapters"] };
|
|
163
195
|
|
|
164
196
|
const program = runValidate(
|
|
165
|
-
{
|
|
197
|
+
{
|
|
198
|
+
config: "./config.ts",
|
|
199
|
+
adapter: Option.none(),
|
|
200
|
+
baseLanguage: Option.none(),
|
|
201
|
+
language: Option.none(),
|
|
202
|
+
},
|
|
166
203
|
() => Effect.succeed(config),
|
|
167
|
-
() => Effect.fail(new Error(
|
|
204
|
+
() => Effect.fail(new Error("read error")),
|
|
168
205
|
() => Effect.void,
|
|
169
206
|
);
|
|
170
207
|
|
|
171
|
-
await expect(Effect.runPromise(program)).rejects.toThrow(
|
|
208
|
+
await expect(Effect.runPromise(program)).rejects.toThrow("read error");
|
|
172
209
|
});
|
|
173
210
|
|
|
174
|
-
it(
|
|
211
|
+
it("filters by --language flag", async () => {
|
|
175
212
|
let checkedLocale: string | undefined;
|
|
176
|
-
const adapter = makeAdapter({ name:
|
|
177
|
-
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig[
|
|
213
|
+
const adapter = makeAdapter({ name: "test" });
|
|
214
|
+
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig["adapters"] };
|
|
178
215
|
|
|
179
216
|
const program = runValidate(
|
|
180
|
-
{
|
|
217
|
+
{
|
|
218
|
+
config: "./config.ts",
|
|
219
|
+
adapter: Option.none(),
|
|
220
|
+
baseLanguage: Option.none(),
|
|
221
|
+
language: Option.some("de"),
|
|
222
|
+
},
|
|
181
223
|
() => Effect.succeed(config),
|
|
182
224
|
(_a, _s, targets) =>
|
|
183
225
|
Effect.sync(() => {
|
|
@@ -188,16 +230,22 @@ describe('runValidate', () => {
|
|
|
188
230
|
);
|
|
189
231
|
|
|
190
232
|
await Effect.runPromise(program);
|
|
191
|
-
expect(checkedLocale).toBe(
|
|
233
|
+
expect(checkedLocale).toBe("de");
|
|
192
234
|
});
|
|
193
235
|
|
|
194
|
-
it(
|
|
236
|
+
it("outputs pretty when --format pretty is passed", async () => {
|
|
195
237
|
const logs: string[] = [];
|
|
196
|
-
const adapter = makeAdapter({ name:
|
|
197
|
-
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig[
|
|
238
|
+
const adapter = makeAdapter({ name: "test" });
|
|
239
|
+
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig["adapters"] };
|
|
198
240
|
|
|
199
241
|
const program = runValidate(
|
|
200
|
-
{
|
|
242
|
+
{
|
|
243
|
+
config: "./config.ts",
|
|
244
|
+
adapter: Option.none(),
|
|
245
|
+
baseLanguage: Option.none(),
|
|
246
|
+
language: Option.none(),
|
|
247
|
+
format: Option.some("pretty"),
|
|
248
|
+
},
|
|
201
249
|
() => Effect.succeed(config),
|
|
202
250
|
() => Effect.succeed([]),
|
|
203
251
|
(msg) => Effect.sync(() => logs.push(msg)),
|
|
@@ -205,15 +253,20 @@ describe('runValidate', () => {
|
|
|
205
253
|
|
|
206
254
|
await Effect.runPromise(program);
|
|
207
255
|
expect(logs).toHaveLength(1);
|
|
208
|
-
expect(logs[0]).toContain(
|
|
256
|
+
expect(logs[0]).toContain("up to date");
|
|
209
257
|
});
|
|
210
258
|
|
|
211
|
-
it(
|
|
259
|
+
it("handles empty adapter list", async () => {
|
|
212
260
|
const logs: string[] = [];
|
|
213
261
|
const config = { ...baseConfig, adapters: [] };
|
|
214
262
|
|
|
215
263
|
const program = runValidate(
|
|
216
|
-
{
|
|
264
|
+
{
|
|
265
|
+
config: "./config.ts",
|
|
266
|
+
adapter: Option.none(),
|
|
267
|
+
baseLanguage: Option.none(),
|
|
268
|
+
language: Option.none(),
|
|
269
|
+
},
|
|
217
270
|
() => Effect.succeed(config),
|
|
218
271
|
() => Effect.succeed([]),
|
|
219
272
|
(msg) => Effect.sync(() => logs.push(msg)),
|
|
@@ -225,13 +278,18 @@ describe('runValidate', () => {
|
|
|
225
278
|
expect(parsed.passing).toBe(true);
|
|
226
279
|
});
|
|
227
280
|
|
|
228
|
-
it(
|
|
281
|
+
it("handles adapter with only source locale (no targets)", async () => {
|
|
229
282
|
const logs: string[] = [];
|
|
230
|
-
const adapter = makeAdapter({ name:
|
|
231
|
-
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig[
|
|
283
|
+
const adapter = makeAdapter({ name: "mono", locales: ["en"] });
|
|
284
|
+
const config = { ...baseConfig, adapters: [adapter] as unknown as DialektConfig["adapters"] };
|
|
232
285
|
|
|
233
286
|
const program = runValidate(
|
|
234
|
-
{
|
|
287
|
+
{
|
|
288
|
+
config: "./config.ts",
|
|
289
|
+
adapter: Option.none(),
|
|
290
|
+
baseLanguage: Option.none(),
|
|
291
|
+
language: Option.none(),
|
|
292
|
+
},
|
|
235
293
|
() => Effect.succeed(config),
|
|
236
294
|
() => Effect.succeed([]),
|
|
237
295
|
(msg) => Effect.sync(() => logs.push(msg)),
|