@xndrjs/i18n 0.2.0-alpha.0 → 0.2.0-alpha.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 CHANGED
@@ -31,7 +31,7 @@ npm install zod
31
31
 
32
32
  ### Quick setup (single file)
33
33
 
34
- **1. Translation JSON** (`src/i18n/translations/translations.json`):
34
+ **1. Translation JSON** (`i18n/translations/translations.json`):
35
35
 
36
36
  ```json
37
37
  {
@@ -40,14 +40,14 @@ npm install zod
40
40
  }
41
41
  ```
42
42
 
43
- **2. Codegen config** (`i18n.codegen.json` at project root):
43
+ **2. Codegen config** (`i18n/i18n.codegen.json`):
44
44
 
45
45
  ```json
46
46
  {
47
- "dictionary": "src/i18n/translations/translations.json",
48
- "typesOutput": "src/i18n/generated/i18n-types.generated.ts",
49
- "dictionaryOutput": "src/i18n/generated/dictionary.generated.ts",
50
- "instanceOutput": "src/i18n/generated/instance.generated.ts",
47
+ "dictionary": "translations/translations.json",
48
+ "typesOutput": "generated/i18n-types.generated.ts",
49
+ "dictionaryOutput": "generated/dictionary.generated.ts",
50
+ "instanceOutput": "generated/instance.generated.ts",
51
51
  "paramsTypeName": "MyProjectParams",
52
52
  "schemaTypeName": "MyProjectSchema"
53
53
  }
@@ -58,7 +58,7 @@ npm install zod
58
58
  ```json
59
59
  {
60
60
  "scripts": {
61
- "i18n:codegen": "xndrjs-i18n-codegen --config i18n.codegen.json"
61
+ "i18n:codegen": "xndrjs-i18n-codegen --config i18n/i18n.codegen.json"
62
62
  }
63
63
  }
64
64
  ```
@@ -70,7 +70,7 @@ npm run i18n:codegen
70
70
  ```
71
71
 
72
72
  ```ts
73
- // src/i18n/index.ts
73
+ // i18n/index.ts
74
74
  import { createI18n } from "./generated/instance.generated.js";
75
75
 
76
76
  export * from "./generated/instance.generated.js";
@@ -95,11 +95,11 @@ xndrjs-i18n-setup single . --project MyApp
95
95
  xndrjs-i18n-setup multi apps/myapp --project MyApp
96
96
  ```
97
97
 
98
- This creates `i18n.codegen.json`, starter translation JSON, and `src/i18n/index.ts`. Edit the config for lazy loading, validation, locale fallback, and extra namespaces, then run codegen.
98
+ This creates `i18n/i18n.codegen.json`, starter translation JSON, and `i18n/index.ts` under the target directory. Pass `src` as the target directory if your project uses a `src/` layout (`src/i18n/`). Edit the config for lazy loading, validation, locale fallback, and extra namespaces, then run codegen.
99
99
 
100
100
  ### Quick setup (multi namespace)
101
101
 
102
- Use `namespaces` instead of `dictionary` in `i18n.codegen.json`. See [Configuration](#configuration-i18ncodegenjson) and the [multi-namespace example](#multi-namespace-example) below.
102
+ Use `namespaces` instead of `dictionary` in `i18n/i18n.codegen.json`. See [Configuration](#configuration-i18ncodegenjson) and the [multi-namespace example](#multi-namespace-example) below.
103
103
 
104
104
  For lazy loading, add `loadOnInit`, `dictionarySchemaOutput`, and `namespaceLoadersOutput` — see [Lazy namespace loading](#lazy-namespace-loading-multi-mode). Lazy mode requires `zod` (validation runs before a namespace is registered).
105
105
 
@@ -122,7 +122,7 @@ xndrjs-toolkit/
122
122
  │ └── generate-i18n-types.ts
123
123
  └── apps/
124
124
  └── i18n-demo/ # @xndrjs/i18n-demo — workshop app
125
- ├── single/ # single-file example
125
+ ├── single/ # single-file example (config at sub-project root)
126
126
  │ ├── i18n.codegen.json
127
127
  │ └── src/i18n/
128
128
  └── multi/ # multi-namespace example
@@ -130,36 +130,35 @@ xndrjs-toolkit/
130
130
  └── src/i18n/
131
131
  ```
132
132
 
133
+ A typical consumer app scaffolded with `xndrjs-i18n-setup single .` colocates everything under `i18n/`:
134
+
135
+ ```
136
+ my-app/
137
+ └── i18n/
138
+ ├── i18n.codegen.json
139
+ ├── index.ts
140
+ ├── generated/
141
+ └── translations/
142
+ ```
143
+
144
+ For a `src/` layout, run `xndrjs-i18n-setup single src` instead:
145
+
146
+ ```
147
+ my-app/
148
+ └── src/
149
+ └── i18n/
150
+ ├── i18n.codegen.json
151
+ ├── index.ts
152
+ ├── generated/
153
+ └── translations/
154
+ ```
155
+
133
156
  ### Library vs. consumer
134
157
 
135
158
  `@xndrjs/i18n` is **generic** and never imports project-specific types. It exposes two provider classes parametrized by `Schema` and `Params` generics, plus the codegen CLI.
136
159
 
137
160
  The consumer app owns its ICU JSON, its codegen config, and the generated files that bind the generic providers to concrete types.
138
161
 
139
- ## How it works
140
-
141
- ```mermaid
142
- flowchart TB
143
- config[i18n.codegen.json]
144
- json["translations/*.json (ICU strings)"]
145
- codegen["xndrjs-i18n-codegen"]
146
- types["i18n-types.generated.ts (Params + Schema)"]
147
- dict["dictionary.generated.ts"]
148
- inst["instance.generated.ts (factory)"]
149
- provider["IcuTranslationProvider (Single | Multi)"]
150
- external["External runtime override (API, file, DB, CMS, ...)"]
151
-
152
- config --> codegen
153
- json --> codegen
154
- codegen --> types
155
- codegen --> dict
156
- codegen --> inst
157
- types --> provider
158
- dict --> inst
159
- inst --> provider
160
- external -->|"setAll / setNamespace"| provider
161
- ```
162
-
163
162
  ### 1. Source JSON
164
163
 
165
164
  Each translation key maps locale codes to ICU strings. Structure is identical in both modes: `key -> locale -> ICU string`.
@@ -177,7 +176,7 @@ Each translation key maps locale codes to ICU strings. Structure is identical in
177
176
 
178
177
  ### 2. Codegen (build-time)
179
178
 
180
- `xndrjs-i18n-codegen` reads `i18n.codegen.json`, parses every ICU string with `@formatjs/icu-messageformat-parser`, and infers parameter types:
179
+ `xndrjs-i18n-codegen` reads `i18n.codegen.json` (by default `i18n/i18n.codegen.json`), parses every ICU string with `@formatjs/icu-messageformat-parser`, and infers parameter types:
181
180
 
182
181
  | ICU construct | Inferred type |
183
182
  | ----------------------------------------- | ------------- |
@@ -297,22 +296,22 @@ const localeFallback = {
297
296
  const i18n = new IcuTranslationProviderMulti(schema, { localeFallback });
298
297
  ```
299
298
 
300
- ## Configuration (`i18n.codegen.json`)
299
+ ## Configuration (`i18n/i18n.codegen.json`)
301
300
 
302
- Specify **exactly one** of `dictionary` (single-file) or `namespaces` (multi-file).
301
+ Specify **exactly one** of `dictionary` (single-file) or `namespaces` (multi-file). Paths in the config are relative to the directory containing `i18n.codegen.json` (the `i18n/` folder created by setup).
303
302
 
304
303
  ### Multi-namespace
305
304
 
306
305
  ```json
307
306
  {
308
307
  "namespaces": {
309
- "default": "src/i18n/translations/default.json",
310
- "user": "src/i18n/translations/user.json",
311
- "billing": "src/i18n/translations/billing.json"
308
+ "default": "translations/default.json",
309
+ "user": "translations/user.json",
310
+ "billing": "translations/billing.json"
312
311
  },
313
- "typesOutput": "src/i18n/i18n-types.generated.ts",
314
- "dictionaryOutput": "src/i18n/dictionary.generated.ts",
315
- "instanceOutput": "src/i18n/instance.generated.ts",
312
+ "typesOutput": "generated/i18n-types.generated.ts",
313
+ "dictionaryOutput": "generated/dictionary.generated.ts",
314
+ "instanceOutput": "generated/instance.generated.ts",
316
315
  "paramsTypeName": "MyProjectParams",
317
316
  "schemaTypeName": "MyProjectSchema",
318
317
  "localeTypeName": "MyProjectLocale",
@@ -330,11 +329,11 @@ Specify **exactly one** of `dictionary` (single-file) or `namespaces` (multi-fil
330
329
 
331
330
  ```json
332
331
  {
333
- "dictionary": "src/i18n/translations/translations.json",
332
+ "dictionary": "translations/translations.json",
334
333
  "defaultNamespace": "default",
335
- "typesOutput": "src/i18n/i18n-types.generated.ts",
336
- "dictionaryOutput": "src/i18n/dictionary.generated.ts",
337
- "instanceOutput": "src/i18n/instance.generated.ts",
334
+ "typesOutput": "generated/i18n-types.generated.ts",
335
+ "dictionaryOutput": "generated/dictionary.generated.ts",
336
+ "instanceOutput": "generated/instance.generated.ts",
338
337
  "paramsTypeName": "MyProjectParams",
339
338
  "schemaTypeName": "MyProjectSchema",
340
339
  "localeTypeName": "MyProjectLocale",
@@ -365,7 +364,7 @@ Specify **exactly one** of `dictionary` (single-file) or `namespaces` (multi-fil
365
364
  | `loadOnInit` | Multi mode only. Namespaces to include in the initial bundle via static imports. When omitted, all namespaces are eager (default). |
366
365
  | `namespaceLoadersOutput` | Output path for generated lazy loaders and `ensureNamespacesLoaded()`. Defaults to `{dirname(instanceOutput)}/namespace-loaders.generated.ts`. Required when lazy namespaces exist. |
367
366
 
368
- > Paths are resolved relative to the directory containing `i18n.codegen.json` (i.e. the consumer app root).
367
+ > Paths are resolved relative to the directory containing `i18n.codegen.json` (e.g. `i18n/` when using `xndrjs-i18n-setup .`).
369
368
 
370
369
  ## Usage
371
370
 
@@ -421,12 +420,12 @@ Split namespaces across chunks by listing only the namespaces you need at startu
421
420
  ```json
422
421
  {
423
422
  "namespaces": {
424
- "default": "src/i18n/translations/default.json",
425
- "billing": "src/i18n/translations/billing.json"
423
+ "default": "translations/default.json",
424
+ "billing": "translations/billing.json"
426
425
  },
427
426
  "loadOnInit": ["default"],
428
- "dictionarySchemaOutput": "src/i18n/generated/dictionary-schema.generated.ts",
429
- "namespaceLoadersOutput": "src/i18n/generated/namespace-loaders.generated.ts"
427
+ "dictionarySchemaOutput": "generated/dictionary-schema.generated.ts",
428
+ "namespaceLoadersOutput": "generated/namespace-loaders.generated.ts"
430
429
  }
431
430
  ```
432
431
 
@@ -454,11 +453,11 @@ When `loadOnInit` is omitted, behavior is unchanged: all namespaces are statical
454
453
 
455
454
  When translations arrive from an external source (i.e. a CMS), validate the `unknown` input before calling `setAll()` or `setNamespace()`.
456
455
 
457
- Enable validation by adding `dictionarySchemaOutput` to `i18n.codegen.json`:
456
+ Enable validation by adding `dictionarySchemaOutput` to `i18n/i18n.codegen.json`:
458
457
 
459
458
  ```json
460
459
  {
461
- "dictionarySchemaOutput": "src/i18n/generated/dictionary-schema.generated.ts"
460
+ "dictionarySchemaOutput": "generated/dictionary-schema.generated.ts"
462
461
  }
463
462
  ```
464
463
 
@@ -553,7 +552,7 @@ pnpm run demo:multi # tsx multi/src/index.ts
553
552
  ## Adding a namespace
554
553
 
555
554
  1. Create a new JSON file (any name/path).
556
- 2. Add it to `namespaces` in `i18n.codegen.json`.
555
+ 2. Add it to `namespaces` in `i18n/i18n.codegen.json`.
557
556
  3. Re-run codegen. `dictionary.generated.ts` wires the import automatically.
558
557
 
559
558
  ## Migrating single-file to multi-namespace
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/icu/extract-variables.ts","../../src/icu/parse-template.ts","../../src/validation/normalize.ts","../../src/validation/to-dictionary.ts","../../src/validation/create-args-schema.ts","../../src/validation/create-normalized-schema.ts","../../src/validation/validate-normalized.ts","../../src/validation/errors.ts","../../src/validation/index.ts"],"names":["dictionary","z","key"],"mappings":"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","file":"index.js","sourcesContent":["import type { parse } from \"@formatjs/icu-messageformat-parser\";\n\nexport type VariableType = \"string\" | \"number\" | \"date\";\nexport type VariableSpec = Record<string, VariableType>;\n\ntype IcuAst = ReturnType<typeof parse>;\ntype IcuNode = IcuAst[number];\n\nfunction isNumericIcuNode(node: IcuNode): boolean {\n if (node.type === 2) {\n return true;\n }\n\n if (node.type === 6 && \"pluralType\" in node && node.pluralType) {\n return true;\n }\n\n return false;\n}\n\nfunction hasVariableName(node: IcuNode): node is Extract<IcuNode, { value: string }> {\n return \"value\" in node && typeof node.value === \"string\";\n}\n\nexport function extractVariables(nodes: IcuAst): VariableSpec {\n const variables: VariableSpec = {};\n\n const walk = (walkNodes: IcuAst) => {\n for (const node of walkNodes) {\n if (node.type === 1) {\n variables[node.value] = variables[node.value] ?? \"string\";\n } else if (isNumericIcuNode(node) && hasVariableName(node)) {\n variables[node.value] = \"number\";\n } else if ((node.type === 3 || node.type === 4) && hasVariableName(node)) {\n variables[node.value] = \"date\";\n } else if (node.type === 5 && hasVariableName(node)) {\n variables[node.value] = variables[node.value] ?? \"string\";\n } else if (node.type === 6 && hasVariableName(node)) {\n variables[node.value] = variables[node.value] ?? \"string\";\n }\n\n if (\"options\" in node && node.options) {\n for (const option of Object.values(node.options)) {\n walk(option.value);\n }\n }\n\n if (\"children\" in node && Array.isArray(node.children)) {\n walk(node.children);\n }\n }\n };\n\n walk(nodes);\n return variables;\n}\n\nexport function mergeVariableSpecs(target: VariableSpec, source: VariableSpec): VariableSpec {\n const merged = { ...target };\n\n for (const [varName, varType] of Object.entries(source)) {\n const existing = merged[varName];\n if (existing && existing !== varType) {\n merged[varName] = \"number\";\n } else {\n merged[varName] = varType;\n }\n }\n\n return merged;\n}\n\nexport function variableSpecsEqual(a: VariableSpec, b: VariableSpec): boolean {\n const aKeys = Object.keys(a).sort();\n const bKeys = Object.keys(b).sort();\n\n if (aKeys.length !== bKeys.length) {\n return false;\n }\n\n return aKeys.every((key, index) => {\n if (key !== bKeys[index]) {\n return false;\n }\n return a[key] === b[key];\n });\n}\n","import { parse } from \"@formatjs/icu-messageformat-parser\";\nimport { extractVariables, type VariableSpec } from \"./extract-variables.js\";\n\nexport type ParseTemplateSuccess = {\n readonly ok: true;\n readonly args: VariableSpec;\n};\n\nexport type ParseTemplateFailure = {\n readonly ok: false;\n readonly message: string;\n};\n\nexport type ParseTemplateResult = ParseTemplateSuccess | ParseTemplateFailure;\n\nexport function parseTemplate(template: string): ParseTemplateResult {\n try {\n const ast = parse(template);\n return { ok: true, args: extractVariables(ast) };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { ok: false, message };\n }\n}\n","import { variableSpecsEqual } from \"../icu/extract-variables.js\";\nimport { parseTemplate } from \"../icu/parse-template.js\";\nimport type {\n DictionarySpec,\n NormalizedDictionary,\n NormalizedKeyDictionary,\n ParsedKeyEntry,\n ValidationIssue,\n ValidationResult,\n} from \"./types.js\";\n\nfunction failure(issues: ValidationIssue[]): ValidationResult<NormalizedDictionary> {\n return { ok: false, issues };\n}\n\nfunction success(data: NormalizedDictionary): ValidationResult<NormalizedDictionary> {\n return { ok: true, data };\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction normalizeKeyDictionary(\n input: Record<string, unknown>,\n requiredKeys: readonly string[],\n keyPathPrefix: readonly string[]\n): ValidationResult<NormalizedKeyDictionary> {\n const issues: ValidationIssue[] = [];\n const keys: Record<string, ParsedKeyEntry> = {};\n\n for (const key of requiredKeys) {\n if (!(key in input)) {\n issues.push({ kind: \"missing_key\", path: [...keyPathPrefix, key] });\n continue;\n }\n\n const keyValue = input[key];\n if (!isPlainObject(keyValue)) {\n issues.push({\n kind: \"invalid_input\",\n message: `Expected object for key \"${key}\", got ${typeof keyValue}`,\n });\n continue;\n }\n\n const locales: Record<string, ParsedKeyEntry[\"locales\"][string]> = {};\n let mergedArgs: ParsedKeyEntry[\"mergedArgs\"] = {};\n let hasLocaleArgs = false;\n\n for (const [locale, template] of Object.entries(keyValue)) {\n const localePath = [...keyPathPrefix, key, locale];\n\n if (typeof template !== \"string\") {\n issues.push({\n kind: \"invalid_locale_value\",\n path: localePath,\n message: `expected string, got ${typeof template}`,\n });\n continue;\n }\n\n const parsed = parseTemplate(template);\n if (!parsed.ok) {\n issues.push({\n kind: \"icu_syntax_error\",\n path: localePath,\n message: parsed.message,\n });\n continue;\n }\n\n locales[locale] = { template, args: parsed.args };\n\n if (!hasLocaleArgs) {\n mergedArgs = { ...parsed.args };\n hasLocaleArgs = true;\n } else if (!variableSpecsEqual(mergedArgs, parsed.args)) {\n const localeArgs: Record<string, ParsedKeyEntry[\"mergedArgs\"]> = {};\n for (const [loc, entry] of Object.entries(locales)) {\n localeArgs[loc] = entry.args;\n }\n issues.push({\n kind: \"locale_args_mismatch\",\n path: [...keyPathPrefix, key],\n locales: localeArgs,\n message: `Inconsistent ICU variables across locales for key \"${key}\"`,\n });\n break;\n }\n }\n\n keys[key] = { locales, mergedArgs };\n }\n\n if (issues.length > 0) {\n return { ok: false, issues };\n }\n\n return { ok: true, data: keys };\n}\n\nexport function normalizeDictionary(\n input: unknown,\n spec: DictionarySpec\n): ValidationResult<NormalizedDictionary> {\n if (!isPlainObject(input)) {\n return failure([\n {\n kind: \"invalid_input\",\n message: `Expected object, got ${input === null ? \"null\" : typeof input}`,\n },\n ]);\n }\n\n if (spec.mode === \"single\") {\n const result = normalizeKeyDictionary(input, spec.requiredKeys, []);\n if (!result.ok) {\n return result;\n }\n\n return success({ mode: \"single\", keys: result.data });\n }\n\n const issues: ValidationIssue[] = [];\n const namespaces: Record<string, NormalizedKeyDictionary> = {};\n\n for (const [namespace, requiredKeys] of Object.entries(spec.requiredKeys)) {\n if (!(namespace in input)) {\n for (const key of requiredKeys) {\n issues.push({ kind: \"missing_key\", path: [namespace, key] });\n }\n continue;\n }\n\n const namespaceValue = input[namespace];\n if (!isPlainObject(namespaceValue)) {\n issues.push({\n kind: \"invalid_input\",\n message: `Expected object for namespace \"${namespace}\", got ${typeof namespaceValue}`,\n });\n continue;\n }\n\n const result = normalizeKeyDictionary(namespaceValue, requiredKeys, [namespace]);\n if (!result.ok) {\n issues.push(...result.issues);\n } else {\n namespaces[namespace] = result.data;\n }\n }\n\n if (issues.length > 0) {\n return failure(issues);\n }\n\n return success({ mode: \"multi\", namespaces });\n}\n","import type { NormalizedDictionary } from \"./types.js\";\n\ntype LocaleDictionary = Record<string, string>;\ntype KeyDictionary = Record<string, LocaleDictionary>;\ntype MultiDictionary = Record<string, KeyDictionary>;\n\nexport function toDictionary(normalized: NormalizedDictionary): KeyDictionary | MultiDictionary {\n if (normalized.mode === \"single\") {\n const dictionary: KeyDictionary = {};\n\n for (const [key, entry] of Object.entries(normalized.keys)) {\n const locales: LocaleDictionary = {};\n for (const [locale, localeEntry] of Object.entries(entry.locales)) {\n locales[locale] = localeEntry.template;\n }\n dictionary[key] = locales;\n }\n\n return dictionary;\n }\n\n const dictionary: MultiDictionary = {};\n\n for (const [namespace, keys] of Object.entries(normalized.namespaces)) {\n const namespaceDictionary: KeyDictionary = {};\n\n for (const [key, entry] of Object.entries(keys)) {\n const locales: LocaleDictionary = {};\n for (const [locale, localeEntry] of Object.entries(entry.locales)) {\n locales[locale] = localeEntry.template;\n }\n namespaceDictionary[key] = locales;\n }\n\n dictionary[namespace] = namespaceDictionary;\n }\n\n return dictionary;\n}\n\nexport function toNamespaceDictionary(\n normalized: NormalizedDictionary,\n namespace: string\n): KeyDictionary {\n if (normalized.mode !== \"multi\") {\n throw new Error(\n `[i18n] toNamespaceDictionary requires multi-mode normalized dictionary, got \"${normalized.mode}\"`\n );\n }\n\n const keys = normalized.namespaces[namespace];\n if (!keys) {\n return {};\n }\n\n const dictionary: KeyDictionary = {};\n\n for (const [key, entry] of Object.entries(keys)) {\n const locales: LocaleDictionary = {};\n for (const [locale, localeEntry] of Object.entries(entry.locales)) {\n locales[locale] = localeEntry.template;\n }\n dictionary[key] = locales;\n }\n\n return dictionary;\n}\n","import { z } from \"zod\";\nimport type { VariableSpec, VariableType } from \"../icu/extract-variables.js\";\n\nexport const variableTypeSchema = z.enum([\"string\", \"number\", \"date\"]);\n\nfunction formatVariableMismatch(expected: VariableSpec, found: VariableSpec): string {\n const expectedKeys = Object.keys(expected).sort();\n const foundKeys = Object.keys(found).sort();\n return `Expected variables [${expectedKeys.join(\", \")}], found [${foundKeys.join(\", \")}]`;\n}\n\nexport function createArgsSchema(expected: VariableSpec): z.ZodType<VariableSpec> {\n return z.record(z.string(), variableTypeSchema).superRefine((found, ctx) => {\n const expectedKeys = Object.keys(expected).sort();\n const foundKeys = Object.keys(found).sort();\n\n if (expectedKeys.join() !== foundKeys.join()) {\n ctx.addIssue({\n code: \"custom\",\n message: formatVariableMismatch(expected, found),\n });\n return;\n }\n\n for (const [name, type] of Object.entries(expected)) {\n if (found[name] !== type) {\n ctx.addIssue({\n code: \"custom\",\n message: `Variable \"${name}\": expected ${type}, found ${found[name]}`,\n });\n }\n }\n });\n}\n\nexport function mapArgsSchemaError(\n expected: VariableSpec,\n found: VariableSpec,\n message: string,\n path: readonly string[]\n) {\n const expectedKeys = Object.keys(expected).sort();\n const foundKeys = Object.keys(found).sort();\n\n if (expectedKeys.join() !== foundKeys.join()) {\n return {\n kind: \"variable_mismatch\" as const,\n path,\n expected,\n found,\n message,\n };\n }\n\n for (const [name, type] of Object.entries(expected)) {\n const foundType = found[name];\n if (foundType !== undefined && foundType !== type) {\n return {\n kind: \"variable_type_mismatch\" as const,\n path,\n variable: name,\n expected: type,\n found: foundType as VariableType,\n message,\n };\n }\n }\n\n return {\n kind: \"variable_mismatch\" as const,\n path,\n expected,\n found,\n message,\n };\n}\n","import { z } from \"zod\";\nimport type { VariableSpec } from \"../icu/extract-variables.js\";\nimport { createArgsSchema, variableTypeSchema } from \"./create-args-schema.js\";\nimport type { DictionarySpec, NormalizedDictionary, ParsedKeyEntry } from \"./types.js\";\n\nconst parsedLocaleEntrySchema = z.object({\n template: z.string(),\n args: z.record(z.string(), variableTypeSchema),\n});\n\nconst parsedKeyEntrySchema = z.object({\n locales: z.record(z.string(), parsedLocaleEntrySchema),\n mergedArgs: z.record(z.string(), variableTypeSchema),\n});\n\nfunction createKeyDictionarySchema(\n argsByKey: Readonly<Record<string, VariableSpec>>\n): z.ZodType<Record<string, ParsedKeyEntry>> {\n const keySchemas = Object.fromEntries(\n Object.entries(argsByKey).map(([key, expectedArgs]) => [\n key,\n parsedKeyEntrySchema.extend({\n mergedArgs: createArgsSchema(expectedArgs),\n }),\n ])\n );\n\n return z.object(keySchemas);\n}\n\nexport function createNormalizedDictionarySchema(\n spec: DictionarySpec\n): z.ZodType<NormalizedDictionary> {\n if (spec.mode === \"single\") {\n return z.object({\n mode: z.literal(\"single\"),\n keys: createKeyDictionarySchema(spec.argsByKey),\n }) as z.ZodType<NormalizedDictionary>;\n }\n\n const namespaceSchemas = Object.fromEntries(\n Object.entries(spec.argsByKey).map(([namespace, argsByKey]) => [\n namespace,\n createKeyDictionarySchema(argsByKey),\n ])\n );\n\n return z.object({\n mode: z.literal(\"multi\"),\n namespaces: z.object(namespaceSchemas),\n }) as z.ZodType<NormalizedDictionary>;\n}\n","import type { ZodError } from \"zod\";\nimport { mapArgsSchemaError } from \"./create-args-schema.js\";\nimport { createNormalizedDictionarySchema } from \"./create-normalized-schema.js\";\nimport type {\n DictionarySpec,\n NormalizedDictionary,\n ValidationIssue,\n ValidationResult,\n VariableSpec,\n} from \"./types.js\";\n\nfunction getExpectedArgs(spec: DictionarySpec, path: readonly string[]): VariableSpec | undefined {\n if (spec.mode === \"single\") {\n const key = path[path.length - 1];\n if (typeof key !== \"string\") {\n return undefined;\n }\n return spec.argsByKey[key];\n }\n\n const namespace = path[0];\n const key = path[path.length - 1];\n if (typeof namespace !== \"string\" || typeof key !== \"string\") {\n return undefined;\n }\n\n return spec.argsByKey[namespace]?.[key];\n}\n\nfunction getFoundArgs(\n normalized: NormalizedDictionary,\n path: readonly string[]\n): VariableSpec | undefined {\n if (normalized.mode === \"single\") {\n const key = path[path.length - 1];\n if (typeof key !== \"string\") {\n return undefined;\n }\n return normalized.keys[key]?.mergedArgs;\n }\n\n const namespace = path[0];\n const key = path[path.length - 1];\n if (typeof namespace !== \"string\" || typeof key !== \"string\") {\n return undefined;\n }\n\n return normalized.namespaces[namespace]?.[key]?.mergedArgs;\n}\n\nfunction mapZodError(\n error: ZodError,\n spec: DictionarySpec,\n normalized: NormalizedDictionary\n): ValidationIssue[] {\n return error.issues.map((issue) => {\n const path = issue.path.map(String);\n\n if (path.includes(\"mergedArgs\")) {\n const keyPath = path.slice(0, path.indexOf(\"mergedArgs\"));\n const expected = getExpectedArgs(spec, keyPath);\n const found = getFoundArgs(normalized, keyPath);\n\n if (expected && found) {\n return mapArgsSchemaError(expected, found, issue.message, keyPath);\n }\n }\n\n return {\n kind: \"invalid_input\" as const,\n message: path.length > 0 ? `${path.join(\".\")}: ${issue.message}` : issue.message,\n };\n });\n}\n\nexport function validateNormalizedDictionary(\n normalized: NormalizedDictionary,\n spec: DictionarySpec\n): ValidationResult<NormalizedDictionary> {\n const schema = createNormalizedDictionarySchema(spec);\n const result = schema.safeParse(normalized);\n\n if (result.success) {\n return { ok: true, data: result.data };\n }\n\n return {\n ok: false,\n issues: mapZodError(result.error, spec, normalized),\n };\n}\n","import type { ValidationIssue, ValidationResult } from \"./types.js\";\n\nfunction issueMessage(issue: ValidationIssue): string {\n switch (issue.kind) {\n case \"missing_key\":\n return `Missing required key at ${issue.path.join(\".\")}`;\n case \"invalid_input\":\n case \"invalid_locale_value\":\n case \"icu_syntax_error\":\n case \"locale_args_mismatch\":\n case \"variable_mismatch\":\n case \"variable_type_mismatch\":\n return issue.message;\n }\n}\n\nexport function formatIssues(issues: readonly ValidationIssue[]): string {\n return issues\n .map((issue) => {\n if (\"path\" in issue && issue.path.length > 0) {\n return `[${issue.path.join(\".\")}] ${issue.kind}: ${issueMessage(issue)}`;\n }\n return `${issue.kind}: ${issueMessage(issue)}`;\n })\n .join(\"\\n\");\n}\n\nexport class DictionaryValidationError extends Error {\n constructor(public readonly issues: readonly ValidationIssue[]) {\n super(formatIssues(issues));\n this.name = \"DictionaryValidationError\";\n }\n}\n\nexport function assertValidDictionary<T>(\n result: ValidationResult<T>\n): asserts result is { ok: true; data: T } {\n if (!result.ok) {\n throw new DictionaryValidationError(result.issues);\n }\n}\n","import { normalizeDictionary } from \"./normalize.js\";\nimport { toDictionary, toNamespaceDictionary } from \"./to-dictionary.js\";\nimport type { DictionarySpec, NormalizedDictionary, ValidationResult } from \"./types.js\";\nimport { validateNormalizedDictionary } from \"./validate-normalized.js\";\n\nexport function validateExternalDictionary<TSchema>(\n input: unknown,\n spec: DictionarySpec\n): ValidationResult<TSchema> {\n const step1 = normalizeDictionary(input, spec);\n if (!step1.ok) {\n return step1;\n }\n\n const step2 = validateNormalizedDictionary(step1.data, spec);\n if (!step2.ok) {\n return step2;\n }\n\n return { ok: true, data: toDictionary(step2.data) as TSchema };\n}\n\nexport function validateExternalNamespace<TNamespaceSchema>(\n namespace: string,\n input: unknown,\n spec: DictionarySpec\n): ValidationResult<TNamespaceSchema> {\n if (spec.mode !== \"multi\") {\n return {\n ok: false,\n issues: [\n {\n kind: \"invalid_input\",\n message: \"validateExternalNamespace requires multi-mode dictionary spec\",\n },\n ],\n };\n }\n\n const wrapped = { [namespace]: input };\n const namespaceSpec: DictionarySpec = {\n mode: \"multi\",\n requiredKeys: {\n [namespace]: spec.requiredKeys[namespace] ?? [],\n },\n argsByKey: {\n [namespace]: spec.argsByKey[namespace] ?? {},\n },\n };\n\n const step1 = normalizeDictionary(wrapped, namespaceSpec);\n if (!step1.ok) {\n return step1;\n }\n\n const step2 = validateNormalizedDictionary(step1.data, namespaceSpec);\n if (!step2.ok) {\n return step2;\n }\n\n return {\n ok: true,\n data: toNamespaceDictionary(step2.data, namespace) as TNamespaceSchema,\n };\n}\n\nexport { normalizeDictionary, validateNormalizedDictionary, toDictionary, toNamespaceDictionary };\nexport { createArgsSchema } from \"./create-args-schema.js\";\nexport { createNormalizedDictionarySchema } from \"./create-normalized-schema.js\";\nexport { DictionaryValidationError, assertValidDictionary, formatIssues } from \"./errors.js\";\nexport type {\n DictionarySpec,\n NormalizedDictionary,\n NormalizedKeyDictionary,\n NormalizedMultiDictionary,\n ParsedKeyEntry,\n ParsedLocaleEntry,\n ValidationIssue,\n ValidationResult,\n VariableSpec,\n VariableType,\n} from \"./types.js\";\n\nexport type { ParseTemplateResult } from \"../icu/parse-template.js\";\nexport { parseTemplate } from \"../icu/parse-template.js\";\nexport {\n extractVariables,\n mergeVariableSpecs,\n variableSpecsEqual,\n} from \"../icu/extract-variables.js\";\n"]}
1
+ {"version":3,"sources":["../../src/icu/extract-variables.ts","../../src/icu/parse-template.ts","../../src/validation/normalize.ts","../../src/validation/to-dictionary.ts","../../src/validation/create-args-schema.ts","../../src/validation/create-normalized-schema.ts","../../src/validation/validate-normalized.ts","../../src/validation/errors.ts","../../src/validation/index.ts"],"names":["dictionary","z","key"],"mappings":"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","file":"index.js","sourcesContent":["import type { parse } from \"@formatjs/icu-messageformat-parser\";\n\nexport type VariableType = \"string\" | \"number\" | \"date\";\nexport type VariableSpec = Record<string, VariableType>;\n\ntype IcuAst = ReturnType<typeof parse>;\ntype IcuNode = IcuAst[number];\n\nfunction isNumericIcuNode(node: IcuNode): boolean {\n if (node.type === 2) {\n return true;\n }\n\n if (node.type === 6 && \"pluralType\" in node && node.pluralType) {\n return true;\n }\n\n return false;\n}\n\nfunction hasVariableName(node: IcuNode): node is Extract<IcuNode, { value: string }> {\n return \"value\" in node && typeof node.value === \"string\";\n}\n\nexport function extractVariables(nodes: IcuAst): VariableSpec {\n const variables: VariableSpec = {};\n\n const walk = (walkNodes: IcuAst) => {\n for (const node of walkNodes) {\n if (node.type === 1) {\n variables[node.value] = variables[node.value] ?? \"string\";\n } else if (isNumericIcuNode(node) && hasVariableName(node)) {\n variables[node.value] = \"number\";\n } else if ((node.type === 3 || node.type === 4) && hasVariableName(node)) {\n variables[node.value] = \"date\";\n } else if (node.type === 5 && hasVariableName(node)) {\n variables[node.value] = variables[node.value] ?? \"string\";\n } else if (node.type === 6 && hasVariableName(node)) {\n variables[node.value] = variables[node.value] ?? \"string\";\n }\n\n if (\"options\" in node && node.options) {\n for (const option of Object.values(node.options)) {\n walk(option.value);\n }\n }\n\n if (\"children\" in node && Array.isArray(node.children)) {\n walk(node.children);\n }\n }\n };\n\n walk(nodes);\n return variables;\n}\n\nexport function mergeVariableSpecs(target: VariableSpec, source: VariableSpec): VariableSpec {\n const merged = { ...target };\n\n for (const [varName, varType] of Object.entries(source)) {\n const existing = merged[varName];\n if (existing && existing !== varType) {\n merged[varName] = \"number\";\n } else {\n merged[varName] = varType;\n }\n }\n\n return merged;\n}\n\nexport function variableSpecsEqual(a: VariableSpec, b: VariableSpec): boolean {\n const aKeys = Object.keys(a).sort();\n const bKeys = Object.keys(b).sort();\n\n if (aKeys.length !== bKeys.length) {\n return false;\n }\n\n return aKeys.every((key, index) => {\n if (key !== bKeys[index]) {\n return false;\n }\n return a[key] === b[key];\n });\n}\n","import { parse } from \"@formatjs/icu-messageformat-parser\";\nimport { extractVariables, type VariableSpec } from \"./extract-variables.js\";\n\nexport type ParseTemplateSuccess = {\n readonly ok: true;\n readonly args: VariableSpec;\n};\n\nexport type ParseTemplateFailure = {\n readonly ok: false;\n readonly message: string;\n};\n\nexport type ParseTemplateResult = ParseTemplateSuccess | ParseTemplateFailure;\n\nexport function parseTemplate(template: string): ParseTemplateResult {\n try {\n const ast = parse(template);\n return { ok: true, args: extractVariables(ast) };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { ok: false, message };\n }\n}\n","import { variableSpecsEqual } from \"../icu/extract-variables.js\";\nimport { parseTemplate } from \"../icu/parse-template.js\";\nimport type {\n DictionarySpec,\n NormalizedDictionary,\n NormalizedKeyDictionary,\n ParsedKeyEntry,\n ValidationIssue,\n ValidationResult,\n} from \"./types.js\";\n\nfunction failure(issues: ValidationIssue[]): ValidationResult<NormalizedDictionary> {\n return { ok: false, issues };\n}\n\nfunction success(data: NormalizedDictionary): ValidationResult<NormalizedDictionary> {\n return { ok: true, data };\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction normalizeKeyDictionary(\n input: Record<string, unknown>,\n requiredKeys: readonly string[],\n keyPathPrefix: readonly string[]\n): ValidationResult<NormalizedKeyDictionary> {\n const issues: ValidationIssue[] = [];\n const keys: Record<string, ParsedKeyEntry> = {};\n\n for (const key of requiredKeys) {\n if (!(key in input)) {\n issues.push({ kind: \"missing_key\", path: [...keyPathPrefix, key] });\n continue;\n }\n\n const keyValue = input[key];\n if (!isPlainObject(keyValue)) {\n issues.push({\n kind: \"invalid_input\",\n message: `Expected object for key \"${key}\", got ${typeof keyValue}`,\n });\n continue;\n }\n\n const locales: Record<string, ParsedKeyEntry[\"locales\"][string]> = {};\n let mergedArgs: ParsedKeyEntry[\"mergedArgs\"] = {};\n let hasLocaleArgs = false;\n\n for (const [locale, template] of Object.entries(keyValue)) {\n const localePath = [...keyPathPrefix, key, locale];\n\n if (typeof template !== \"string\") {\n issues.push({\n kind: \"invalid_locale_value\",\n path: localePath,\n message: `expected string, got ${typeof template}`,\n });\n continue;\n }\n\n const parsed = parseTemplate(template);\n if (!parsed.ok) {\n issues.push({\n kind: \"icu_syntax_error\",\n path: localePath,\n message: parsed.message,\n });\n continue;\n }\n\n locales[locale] = { template, args: parsed.args };\n\n if (!hasLocaleArgs) {\n mergedArgs = { ...parsed.args };\n hasLocaleArgs = true;\n } else if (!variableSpecsEqual(mergedArgs, parsed.args)) {\n const localeArgs: Record<string, ParsedKeyEntry[\"mergedArgs\"]> = {};\n for (const [loc, entry] of Object.entries(locales)) {\n localeArgs[loc] = entry.args;\n }\n issues.push({\n kind: \"locale_args_mismatch\",\n path: [...keyPathPrefix, key],\n locales: localeArgs,\n message: `Inconsistent ICU variables across locales for key \"${key}\"`,\n });\n break;\n }\n }\n\n keys[key] = { locales, mergedArgs };\n }\n\n if (issues.length > 0) {\n return { ok: false, issues };\n }\n\n return { ok: true, data: keys };\n}\n\nexport function normalizeDictionary(\n input: unknown,\n spec: DictionarySpec\n): ValidationResult<NormalizedDictionary> {\n if (!isPlainObject(input)) {\n return failure([\n {\n kind: \"invalid_input\",\n message: `Expected object, got ${input === null ? \"null\" : typeof input}`,\n },\n ]);\n }\n\n if (spec.mode === \"single\") {\n const result = normalizeKeyDictionary(input, spec.requiredKeys, []);\n if (!result.ok) {\n return result;\n }\n\n return success({ mode: \"single\", keys: result.data });\n }\n\n const issues: ValidationIssue[] = [];\n const namespaces: Record<string, NormalizedKeyDictionary> = {};\n\n for (const [namespace, requiredKeys] of Object.entries(spec.requiredKeys)) {\n if (!(namespace in input)) {\n for (const key of requiredKeys) {\n issues.push({ kind: \"missing_key\", path: [namespace, key] });\n }\n continue;\n }\n\n const namespaceValue = input[namespace];\n if (!isPlainObject(namespaceValue)) {\n issues.push({\n kind: \"invalid_input\",\n message: `Expected object for namespace \"${namespace}\", got ${typeof namespaceValue}`,\n });\n continue;\n }\n\n const result = normalizeKeyDictionary(namespaceValue, requiredKeys, [namespace]);\n if (!result.ok) {\n issues.push(...result.issues);\n } else {\n namespaces[namespace] = result.data;\n }\n }\n\n if (issues.length > 0) {\n return failure(issues);\n }\n\n return success({ mode: \"multi\", namespaces });\n}\n","import type { NormalizedDictionary } from \"./types.js\";\n\ntype LocaleDictionary = Record<string, string>;\ntype KeyDictionary = Record<string, LocaleDictionary>;\ntype MultiDictionary = Record<string, KeyDictionary>;\n\nexport function toDictionary(normalized: NormalizedDictionary): KeyDictionary | MultiDictionary {\n if (normalized.mode === \"single\") {\n const dictionary: KeyDictionary = {};\n\n for (const [key, entry] of Object.entries(normalized.keys)) {\n const locales: LocaleDictionary = {};\n for (const [locale, localeEntry] of Object.entries(entry.locales)) {\n locales[locale] = localeEntry.template;\n }\n dictionary[key] = locales;\n }\n\n return dictionary;\n }\n\n const dictionary: MultiDictionary = {};\n\n for (const [namespace, keys] of Object.entries(normalized.namespaces)) {\n const namespaceDictionary: KeyDictionary = {};\n\n for (const [key, entry] of Object.entries(keys)) {\n const locales: LocaleDictionary = {};\n for (const [locale, localeEntry] of Object.entries(entry.locales)) {\n locales[locale] = localeEntry.template;\n }\n namespaceDictionary[key] = locales;\n }\n\n dictionary[namespace] = namespaceDictionary;\n }\n\n return dictionary;\n}\n\nexport function toNamespaceDictionary(\n normalized: NormalizedDictionary,\n namespace: string\n): KeyDictionary {\n if (normalized.mode !== \"multi\") {\n throw new Error(\n `[i18n] toNamespaceDictionary requires multi-mode normalized dictionary, got \"${normalized.mode}\"`\n );\n }\n\n const keys = normalized.namespaces[namespace];\n if (!keys) {\n return {};\n }\n\n const dictionary: KeyDictionary = {};\n\n for (const [key, entry] of Object.entries(keys)) {\n const locales: LocaleDictionary = {};\n for (const [locale, localeEntry] of Object.entries(entry.locales)) {\n locales[locale] = localeEntry.template;\n }\n dictionary[key] = locales;\n }\n\n return dictionary;\n}\n","import { z } from \"zod\";\nimport type { VariableSpec, VariableType } from \"../icu/extract-variables.js\";\n\nexport const variableTypeSchema = z.enum([\"string\", \"number\", \"date\"]);\n\nfunction formatVariableMismatch(expected: VariableSpec, found: VariableSpec): string {\n const expectedKeys = Object.keys(expected).sort();\n const foundKeys = Object.keys(found).sort();\n return `Expected variables [${expectedKeys.join(\", \")}], found [${foundKeys.join(\", \")}]`;\n}\n\nexport function createArgsSchema(expected: VariableSpec): z.ZodType<VariableSpec> {\n return z.record(z.string(), variableTypeSchema).superRefine((found, ctx) => {\n const expectedKeys = Object.keys(expected).sort();\n const foundKeys = Object.keys(found).sort();\n\n if (expectedKeys.join() !== foundKeys.join()) {\n ctx.addIssue({\n code: \"custom\",\n message: formatVariableMismatch(expected, found),\n });\n return;\n }\n\n for (const [name, type] of Object.entries(expected)) {\n if (found[name] !== type) {\n ctx.addIssue({\n code: \"custom\",\n message: `Variable \"${name}\": expected ${type}, found ${found[name]}`,\n });\n }\n }\n });\n}\n\nexport function mapArgsSchemaError(\n expected: VariableSpec,\n found: VariableSpec,\n message: string,\n path: readonly string[]\n) {\n const expectedKeys = Object.keys(expected).sort();\n const foundKeys = Object.keys(found).sort();\n\n if (expectedKeys.join() !== foundKeys.join()) {\n return {\n kind: \"variable_mismatch\" as const,\n path,\n expected,\n found,\n message,\n };\n }\n\n for (const [name, type] of Object.entries(expected)) {\n const foundType = found[name];\n if (foundType !== undefined && foundType !== type) {\n return {\n kind: \"variable_type_mismatch\" as const,\n path,\n variable: name,\n expected: type,\n found: foundType as VariableType,\n message,\n };\n }\n }\n\n return {\n kind: \"variable_mismatch\" as const,\n path,\n expected,\n found,\n message,\n };\n}\n","import { z } from \"zod\";\nimport type { VariableSpec } from \"../icu/extract-variables.js\";\nimport { createArgsSchema, variableTypeSchema } from \"./create-args-schema.js\";\nimport type { DictionarySpec, NormalizedDictionary, ParsedKeyEntry } from \"./types.js\";\n\nconst parsedLocaleEntrySchema = z.object({\n template: z.string(),\n args: z.record(z.string(), variableTypeSchema),\n});\n\nconst parsedKeyEntrySchema = z.object({\n locales: z.record(z.string(), parsedLocaleEntrySchema),\n mergedArgs: z.record(z.string(), variableTypeSchema),\n});\n\nfunction createKeyDictionarySchema(\n argsByKey: Readonly<Record<string, VariableSpec>>\n): z.ZodType<Record<string, ParsedKeyEntry>> {\n const keySchemas = Object.fromEntries(\n Object.entries(argsByKey).map(([key, expectedArgs]) => [\n key,\n parsedKeyEntrySchema.extend({\n mergedArgs: createArgsSchema(expectedArgs),\n }),\n ])\n );\n\n return z.object(keySchemas);\n}\n\nexport function createNormalizedDictionarySchema(\n spec: DictionarySpec\n): z.ZodType<NormalizedDictionary> {\n if (spec.mode === \"single\") {\n return z.object({\n mode: z.literal(\"single\"),\n keys: createKeyDictionarySchema(spec.argsByKey),\n }) as z.ZodType<NormalizedDictionary>;\n }\n\n const namespaceSchemas = Object.fromEntries(\n Object.entries(spec.argsByKey).map(([namespace, argsByKey]) => [\n namespace,\n createKeyDictionarySchema(argsByKey),\n ])\n );\n\n return z.object({\n mode: z.literal(\"multi\"),\n namespaces: z.object(namespaceSchemas),\n }) as z.ZodType<NormalizedDictionary>;\n}\n","import type { ZodError } from \"zod\";\nimport { mapArgsSchemaError } from \"./create-args-schema.js\";\nimport { createNormalizedDictionarySchema } from \"./create-normalized-schema.js\";\nimport type {\n DictionarySpec,\n NormalizedDictionary,\n ValidationIssue,\n ValidationResult,\n VariableSpec,\n} from \"./types.js\";\n\nfunction getExpectedArgs(spec: DictionarySpec, path: readonly string[]): VariableSpec | undefined {\n if (spec.mode === \"single\") {\n const key = path[path.length - 1];\n if (typeof key !== \"string\") {\n return undefined;\n }\n return spec.argsByKey[key];\n }\n\n const namespace = path[0];\n const key = path[path.length - 1];\n if (typeof namespace !== \"string\" || typeof key !== \"string\") {\n return undefined;\n }\n\n return spec.argsByKey[namespace]?.[key];\n}\n\nfunction getFoundArgs(\n normalized: NormalizedDictionary,\n path: readonly string[]\n): VariableSpec | undefined {\n if (normalized.mode === \"single\") {\n const key = path[path.length - 1];\n if (typeof key !== \"string\") {\n return undefined;\n }\n return normalized.keys[key]?.mergedArgs;\n }\n\n const namespace = path[0];\n const key = path[path.length - 1];\n if (typeof namespace !== \"string\" || typeof key !== \"string\") {\n return undefined;\n }\n\n return normalized.namespaces[namespace]?.[key]?.mergedArgs;\n}\n\nfunction mapZodError(\n error: ZodError,\n spec: DictionarySpec,\n normalized: NormalizedDictionary\n): ValidationIssue[] {\n return error.issues.map((issue) => {\n const path = issue.path.map(String);\n\n if (path.includes(\"mergedArgs\")) {\n const keyPath = path.slice(0, path.indexOf(\"mergedArgs\"));\n const expected = getExpectedArgs(spec, keyPath);\n const found = getFoundArgs(normalized, keyPath);\n\n if (expected && found) {\n return mapArgsSchemaError(expected, found, issue.message, keyPath);\n }\n }\n\n return {\n kind: \"invalid_input\" as const,\n message: path.length > 0 ? `${path.join(\".\")}: ${issue.message}` : issue.message,\n };\n });\n}\n\nexport function validateNormalizedDictionary(\n normalized: NormalizedDictionary,\n spec: DictionarySpec\n): ValidationResult<NormalizedDictionary> {\n const schema = createNormalizedDictionarySchema(spec);\n const result = schema.safeParse(normalized);\n\n if (result.success) {\n return { ok: true, data: result.data };\n }\n\n return {\n ok: false,\n issues: mapZodError(result.error, spec, normalized),\n };\n}\n","import type { ValidationIssue, ValidationResult } from \"./types.js\";\n\nfunction issueMessage(issue: ValidationIssue): string {\n switch (issue.kind) {\n case \"missing_key\":\n return `Missing required key at ${issue.path.join(\".\")}`;\n case \"invalid_input\":\n case \"invalid_locale_value\":\n case \"icu_syntax_error\":\n case \"locale_args_mismatch\":\n case \"variable_mismatch\":\n case \"variable_type_mismatch\":\n return issue.message;\n }\n}\n\nexport function formatIssues(issues: readonly ValidationIssue[]): string {\n return issues\n .map((issue) => {\n if (\"path\" in issue && issue.path.length > 0) {\n return `[${issue.path.join(\".\")}] ${issue.kind}: ${issueMessage(issue)}`;\n }\n return `${issue.kind}: ${issueMessage(issue)}`;\n })\n .join(\"\\n\");\n}\n\nexport class DictionaryValidationError extends Error {\n constructor(public readonly issues: readonly ValidationIssue[]) {\n super(formatIssues(issues));\n this.name = \"DictionaryValidationError\";\n }\n}\n\nexport function assertValidDictionary<T>(\n result: ValidationResult<T>\n): asserts result is { ok: true; data: T } {\n if (!result.ok) {\n throw new DictionaryValidationError(result.issues);\n }\n}\n","import { normalizeDictionary } from \"./normalize.js\";\nimport { toDictionary, toNamespaceDictionary } from \"./to-dictionary.js\";\nimport type { DictionarySpec, ValidationResult } from \"./types.js\";\nimport { validateNormalizedDictionary } from \"./validate-normalized.js\";\n\nexport function validateExternalDictionary<TSchema>(\n input: unknown,\n spec: DictionarySpec\n): ValidationResult<TSchema> {\n const step1 = normalizeDictionary(input, spec);\n if (!step1.ok) {\n return step1;\n }\n\n const step2 = validateNormalizedDictionary(step1.data, spec);\n if (!step2.ok) {\n return step2;\n }\n\n return { ok: true, data: toDictionary(step2.data) as TSchema };\n}\n\nexport function validateExternalNamespace<TNamespaceSchema>(\n namespace: string,\n input: unknown,\n spec: DictionarySpec\n): ValidationResult<TNamespaceSchema> {\n if (spec.mode !== \"multi\") {\n return {\n ok: false,\n issues: [\n {\n kind: \"invalid_input\",\n message: \"validateExternalNamespace requires multi-mode dictionary spec\",\n },\n ],\n };\n }\n\n const wrapped = { [namespace]: input };\n const namespaceSpec: DictionarySpec = {\n mode: \"multi\",\n requiredKeys: {\n [namespace]: spec.requiredKeys[namespace] ?? [],\n },\n argsByKey: {\n [namespace]: spec.argsByKey[namespace] ?? {},\n },\n };\n\n const step1 = normalizeDictionary(wrapped, namespaceSpec);\n if (!step1.ok) {\n return step1;\n }\n\n const step2 = validateNormalizedDictionary(step1.data, namespaceSpec);\n if (!step2.ok) {\n return step2;\n }\n\n return {\n ok: true,\n data: toNamespaceDictionary(step2.data, namespace) as TNamespaceSchema,\n };\n}\n\nexport { normalizeDictionary, validateNormalizedDictionary, toDictionary, toNamespaceDictionary };\nexport { createArgsSchema } from \"./create-args-schema.js\";\nexport { createNormalizedDictionarySchema } from \"./create-normalized-schema.js\";\nexport { DictionaryValidationError, assertValidDictionary, formatIssues } from \"./errors.js\";\nexport type {\n DictionarySpec,\n NormalizedDictionary,\n NormalizedKeyDictionary,\n NormalizedMultiDictionary,\n ParsedKeyEntry,\n ParsedLocaleEntry,\n ValidationIssue,\n ValidationResult,\n VariableSpec,\n VariableType,\n} from \"./types.js\";\n\nexport type { ParseTemplateResult } from \"../icu/parse-template.js\";\nexport { parseTemplate } from \"../icu/parse-template.js\";\nexport {\n extractVariables,\n mergeVariableSpecs,\n variableSpecsEqual,\n} from \"../icu/extract-variables.js\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xndrjs/i18n",
3
- "version": "0.2.0-alpha.0",
3
+ "version": "0.2.0-alpha.1",
4
4
  "description": "Compiler-first, type-safe ICU MessageFormat i18n with runtime dictionary override from external sources.",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -17,7 +17,7 @@ function main() {
17
17
  const configArgIndex = process.argv.indexOf("--config");
18
18
  const configPath = path.resolve(
19
19
  process.cwd(),
20
- configArgIndex >= 0 ? process.argv[configArgIndex + 1]! : "i18n.codegen.json"
20
+ configArgIndex >= 0 ? process.argv[configArgIndex + 1]! : "i18n/i18n.codegen.json"
21
21
  );
22
22
  const projectRoot = path.dirname(configPath);
23
23
 
@@ -49,25 +49,35 @@ describe("setup-i18n", () => {
49
49
  tempDir = mkdtempSync(join(tmpdir(), "xndrjs-i18n-setup-"));
50
50
  const result = runSetup({ mode: "single", targetDir: tempDir, project: "MyApp" });
51
51
 
52
- const config = JSON.parse(readFileSync(join(tempDir, "i18n.codegen.json"), "utf8"));
53
- expect(config.dictionary).toBe("src/i18n/translations/translations.json");
52
+ const config = JSON.parse(readFileSync(join(tempDir, "i18n/i18n.codegen.json"), "utf8"));
53
+ expect(config.dictionary).toBe("translations/translations.json");
54
54
  expect(config.paramsTypeName).toBe("MyAppParams");
55
55
  expect(config.schemaTypeName).toBe("MyAppSchema");
56
56
  expect(config.localeTypeName).toBe("MyAppLocale");
57
- expect(existsSync(join(tempDir, "src/i18n/translations/translations.json"))).toBe(true);
58
- expect(existsSync(join(tempDir, "src/i18n/index.ts"))).toBe(true);
59
- expect(result.created).toContain("i18n.codegen.json");
57
+ expect(existsSync(join(tempDir, "i18n/translations/translations.json"))).toBe(true);
58
+ expect(existsSync(join(tempDir, "i18n/index.ts"))).toBe(true);
59
+ expect(existsSync(join(tempDir, "src"))).toBe(false);
60
+ expect(result.created).toContain("i18n/i18n.codegen.json");
60
61
  });
61
62
 
62
63
  it("scaffolds multi mode with default namespace only", () => {
63
64
  tempDir = mkdtempSync(join(tmpdir(), "xndrjs-i18n-setup-"));
64
65
  runSetup({ mode: "multi", targetDir: tempDir, project: "MyApp" });
65
66
 
66
- const config = JSON.parse(readFileSync(join(tempDir, "i18n.codegen.json"), "utf8"));
67
+ const config = JSON.parse(readFileSync(join(tempDir, "i18n/i18n.codegen.json"), "utf8"));
67
68
  expect(config.namespaces).toEqual({
68
- default: "src/i18n/translations/default.json",
69
+ default: "translations/default.json",
69
70
  });
70
- expect(existsSync(join(tempDir, "src/i18n/translations/default.json"))).toBe(true);
71
+ expect(existsSync(join(tempDir, "i18n/translations/default.json"))).toBe(true);
72
+ });
73
+
74
+ it("scaffolds under src/i18n when targetDir is src", () => {
75
+ tempDir = mkdtempSync(join(tmpdir(), "xndrjs-i18n-setup-"));
76
+ const srcDir = join(tempDir, "src");
77
+ runSetup({ mode: "single", targetDir: srcDir, project: "MyApp" });
78
+
79
+ expect(existsSync(join(srcDir, "i18n/i18n.codegen.json"))).toBe(true);
80
+ expect(existsSync(join(tempDir, "i18n"))).toBe(false);
71
81
  });
72
82
 
73
83
  it("refuses to overwrite an existing config without --force", () => {
@@ -18,9 +18,11 @@ export interface SetupResult {
18
18
  created: string[];
19
19
  }
20
20
 
21
- const I18N_ROOT = "src/i18n";
22
- const GENERATED_DIR = `${I18N_ROOT}/generated`;
23
- const TRANSLATIONS_DIR = `${I18N_ROOT}/translations`;
21
+ const I18N_ROOT = "i18n";
22
+ const CONFIG_FILE = `${I18N_ROOT}/i18n.codegen.json`;
23
+ /** Paths in i18n.codegen.json are relative to the i18n/ folder */
24
+ const GENERATED_DIR = "generated";
25
+ const TRANSLATIONS_DIR = "translations";
24
26
 
25
27
  const DEFAULT_STARTER = {
26
28
  welcome: { en: "Welcome {name}!" },
@@ -85,7 +87,7 @@ export function runSetup(options: SetupOptions): SetupResult {
85
87
  );
86
88
  }
87
89
 
88
- const configPath = path.join(targetDir, "i18n.codegen.json");
90
+ const configPath = path.join(targetDir, CONFIG_FILE);
89
91
  if (fs.existsSync(configPath) && !options.force) {
90
92
  throw new Error(
91
93
  `[Setup Error] ${relative(process.cwd(), configPath)} already exists. Use --force to overwrite.`
@@ -98,11 +100,11 @@ export function runSetup(options: SetupOptions): SetupResult {
98
100
  created.push(relative(targetDir, configPath));
99
101
 
100
102
  if (options.mode === "single") {
101
- const translationsPath = path.join(targetDir, TRANSLATIONS_DIR, "translations.json");
103
+ const translationsPath = path.join(targetDir, I18N_ROOT, TRANSLATIONS_DIR, "translations.json");
102
104
  writeJson(translationsPath, DEFAULT_STARTER);
103
105
  created.push(relative(targetDir, translationsPath));
104
106
  } else {
105
- const defaultPath = path.join(targetDir, TRANSLATIONS_DIR, "default.json");
107
+ const defaultPath = path.join(targetDir, I18N_ROOT, TRANSLATIONS_DIR, "default.json");
106
108
  writeJson(defaultPath, DEFAULT_STARTER);
107
109
  created.push(relative(targetDir, defaultPath));
108
110
  }
@@ -111,7 +113,7 @@ export function runSetup(options: SetupOptions): SetupResult {
111
113
  writeText(indexPath, INDEX_TS);
112
114
  created.push(relative(targetDir, indexPath));
113
115
 
114
- fs.mkdirSync(path.join(targetDir, GENERATED_DIR), { recursive: true });
116
+ fs.mkdirSync(path.join(targetDir, I18N_ROOT, GENERATED_DIR), { recursive: true });
115
117
 
116
118
  return { targetDir, project, created };
117
119
  }
@@ -160,13 +162,13 @@ function main() {
160
162
  ` Project types: ${result.project}Params, ${result.project}Schema, ${result.project}Locale`
161
163
  );
162
164
  console.log(` Created: ${result.created.join(", ")}`);
165
+ const targetLabel = path.relative(process.cwd(), result.targetDir) || ".";
166
+
163
167
  console.log("");
164
- console.log("Next:");
165
- console.log(` cd ${path.relative(process.cwd(), result.targetDir) || "."}`);
166
- console.log(
167
- ' npm pkg set scripts.i18n:codegen="xndrjs-i18n-codegen --config i18n.codegen.json"'
168
- );
169
- console.log(" npm run i18n:codegen");
168
+ console.log(`Add to package.json scripts (from ${targetLabel}):`);
169
+ console.log(` "i18n:codegen": "xndrjs-i18n-codegen --config ${CONFIG_FILE}"`);
170
+ console.log("");
171
+ console.log("Then run your package manager's run script (pnpm/npm/yarn).");
170
172
  } catch (error) {
171
173
  const message = error instanceof Error ? error.message : String(error);
172
174
  console.error(message);
@@ -1,6 +1,6 @@
1
1
  import { normalizeDictionary } from "./normalize.js";
2
2
  import { toDictionary, toNamespaceDictionary } from "./to-dictionary.js";
3
- import type { DictionarySpec, NormalizedDictionary, ValidationResult } from "./types.js";
3
+ import type { DictionarySpec, ValidationResult } from "./types.js";
4
4
  import { validateNormalizedDictionary } from "./validate-normalized.js";
5
5
 
6
6
  export function validateExternalDictionary<TSchema>(