@x18n/core 0.0.2 → 0.0.5

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.
@@ -0,0 +1,1316 @@
1
+ import * as v from "valibot";
2
+ //#region src/errors.d.ts
3
+ /**
4
+ * Every coded error. Groups: 0xxx config, 1xxx plugin, 2xxx discovery and parse,
5
+ * 3xxx scanning, 4xxx edits, 5xxx reviews.
6
+ */
7
+ type ErrorCode = "X18N0001" | "X18N0002" | "X18N0003" | "X18N1001" | "X18N1002" | "X18N1003" | "X18N1004" | "X18N2001" | "X18N2002" | "X18N2003" | "X18N2004" | "X18N3001" | "X18N4001" | "X18N4002" | "X18N4003" | "X18N4004" | "X18N4005" | "X18N4006" | "X18N4007" | "X18N4008";
8
+ export declare const errorCodes: { readonly [C in ErrorCode]: {
9
+ readonly message: string;
10
+ readonly hint: string;
11
+ }; };
12
+ interface ErrorInfo {
13
+ readonly code: ErrorCode;
14
+ readonly message: string;
15
+ readonly hint: string;
16
+ readonly docs: string;
17
+ }
18
+ export declare class X18nError extends Error {
19
+ readonly code: ErrorCode;
20
+ readonly hint: string;
21
+ readonly docs: string;
22
+ readonly details: readonly string[];
23
+ constructor(code: ErrorCode, detail?: string, details?: readonly string[]);
24
+ toJSON(): ErrorInfo;
25
+ }
26
+ export declare function isX18nError(error: unknown): error is X18nError;
27
+ //#endregion
28
+ //#region src/types/model.d.ts
29
+ /** A locale code exactly as written in paths and files: `en`, `zh_CN`, `pt-BR`. Never normalized. */
30
+ type LocaleCode = string;
31
+ /** Canonical key string: `ns:a.b.c`, or `a.b.c` without namespace. */
32
+ type KeyString = string;
33
+ /** Resource id: the resource path, plus `#<block index>` for embedded resources. */
34
+ type ResourceId = string;
35
+ type MessageLeaf = string | number | boolean | null;
36
+ interface MessageTree {
37
+ readonly [segment: string]: MessageLeaf | MessageTree;
38
+ }
39
+ /** UTF-16 offsets, the same as JS strings. */
40
+ interface TextRange {
41
+ readonly start: number;
42
+ readonly end: number;
43
+ }
44
+ interface TextEdit {
45
+ readonly range: TextRange;
46
+ readonly text: string;
47
+ }
48
+ /** Ranges of a key and its value (or object) in the resource text. */
49
+ interface NodeRange {
50
+ readonly key: TextRange;
51
+ readonly value: TextRange;
52
+ }
53
+ interface KeyId {
54
+ readonly namespace: string | undefined;
55
+ readonly path: readonly string[];
56
+ }
57
+ /** Display data from a lenient parse of a code. Never changes the code itself. */
58
+ interface LocaleInfo {
59
+ readonly code: LocaleCode;
60
+ readonly language: string | undefined;
61
+ readonly region: string | undefined;
62
+ readonly displayName: string | undefined;
63
+ readonly flag: string | undefined;
64
+ readonly pluralCategories: readonly Intl.LDMLPluralRule[];
65
+ }
66
+ /** Embedded resource inside a file, for example a Vue `<i18n>` block. */
67
+ interface ResourceBlock {
68
+ readonly index: number;
69
+ /** Range of the block content in the file. */
70
+ readonly range: TextRange;
71
+ readonly lang: string | undefined;
72
+ }
73
+ interface Resource {
74
+ readonly id: ResourceId;
75
+ /** Posix path relative to the project root. */
76
+ readonly path: string;
77
+ readonly locale: LocaleCode;
78
+ readonly namespace: string | undefined;
79
+ readonly format: string;
80
+ readonly block: ResourceBlock | undefined;
81
+ /** True for read-only formats and for resources loaded with `execute: true`. */
82
+ readonly readonly: boolean;
83
+ /** Id of the locale finder that found the resource. */
84
+ readonly finder: string;
85
+ }
86
+ /** One stored value of one key in one locale. */
87
+ interface Message {
88
+ readonly key: KeyString;
89
+ readonly locale: LocaleCode;
90
+ readonly value: MessageLeaf;
91
+ readonly resource: ResourceId;
92
+ /** Property path as stored in the resource (`['a.b']` in a flat file, `['a', 'b']` nested). */
93
+ readonly storedPath: readonly string[];
94
+ /** Ranges in the resource file text (block offsets already added). */
95
+ readonly range: NodeRange | undefined;
96
+ }
97
+ type UsageKind = "call" | "selector" | "accessor" | "constant" | "marker";
98
+ interface Usage {
99
+ /** Undefined when the key is fully dynamic. */
100
+ readonly key: KeyString | undefined;
101
+ /** The key text as written in code. */
102
+ readonly raw: string;
103
+ readonly path: string;
104
+ /** Range of the key text only (inside the quotes): the range rename rewrites. */
105
+ readonly range: TextRange;
106
+ readonly scanner: string;
107
+ readonly kind: UsageKind;
108
+ /** `t(`pages.${id}.title`)` gives 'prefix' with key `pages`. */
109
+ readonly dynamic: false | "prefix" | "unknown";
110
+ readonly locale: LocaleCode | undefined;
111
+ /** Namespace that came from a scope or a factory, not from the raw text. */
112
+ readonly scopeNamespace: string | undefined;
113
+ /** Key prefix that came from a scope or factory (`keyPrefix`), not from the raw text. */
114
+ readonly scopePrefix: string | undefined;
115
+ }
116
+ type Severity = "error" | "warning" | "info" | "hint";
117
+ type EditOp = {
118
+ readonly type: "set";
119
+ readonly key: KeyString;
120
+ readonly locale: LocaleCode;
121
+ readonly value: MessageLeaf;
122
+ } | {
123
+ readonly type: "rename";
124
+ readonly from: KeyString;
125
+ readonly to: KeyString;
126
+ readonly usages?: boolean;
127
+ } | {
128
+ readonly type: "rename-prefix";
129
+ readonly from: KeyString;
130
+ readonly to: KeyString;
131
+ readonly usages?: boolean;
132
+ } | {
133
+ readonly type: "delete";
134
+ readonly key: KeyString;
135
+ readonly locales?: "all" | readonly LocaleCode[];
136
+ } | {
137
+ readonly type: "extract";
138
+ readonly items: readonly ExtractItem[];
139
+ } | {
140
+ readonly type: "format";
141
+ readonly paths?: readonly string[];
142
+ };
143
+ interface ExtractItem {
144
+ readonly path: string;
145
+ /** Range of the hard string in the source file, quotes included. */
146
+ readonly range: TextRange;
147
+ readonly key: KeyString;
148
+ readonly value: string;
149
+ /** Replacement text for the range. */
150
+ readonly replacement: string;
151
+ /** Lines to add once per file when missing, for example an import. */
152
+ readonly imports?: readonly string[];
153
+ }
154
+ interface Fix {
155
+ readonly title: string;
156
+ readonly ops: readonly EditOp[];
157
+ }
158
+ interface Location {
159
+ readonly path: string;
160
+ readonly range: TextRange;
161
+ }
162
+ interface Diagnostic {
163
+ /** Check id, for example 'missing-translation'. */
164
+ readonly code: string;
165
+ readonly severity: Severity;
166
+ readonly message: string;
167
+ readonly key: KeyString | undefined;
168
+ readonly locale: LocaleCode | undefined;
169
+ readonly location: Location | undefined;
170
+ readonly fixes: readonly Fix[];
171
+ }
172
+ interface Placeholder {
173
+ readonly syntax: string;
174
+ /** Text as written, for example `{name}`. */
175
+ readonly text: string;
176
+ /** Name used for comparison across locales, for example `name`. */
177
+ readonly name: string;
178
+ readonly range: TextRange;
179
+ }
180
+ type JsonPrimitive = string | number | boolean | null;
181
+ type JsonValue = JsonPrimitive | readonly JsonValue[] | JsonObject;
182
+ interface JsonObject {
183
+ readonly [key: string]: JsonValue;
184
+ }
185
+ //#endregion
186
+ //#region src/contracts.d.ts
187
+ /** Version of every JSON contract (CLI `--json`, LSP `x18n/*`, RPC, MCP). Bumped on breaking changes to any `data` shape. */
188
+ export declare const contractVersion = 1;
189
+ interface WireRange {
190
+ /** 1-based. */
191
+ readonly line: number;
192
+ /** 1-based, UTF-16 code units. */
193
+ readonly column: number;
194
+ readonly endLine: number;
195
+ readonly endColumn: number;
196
+ /** 0-based UTF-16 offsets. */
197
+ readonly start: number;
198
+ readonly end: number;
199
+ }
200
+ interface WireDiagnostic {
201
+ readonly project: string;
202
+ readonly code: string;
203
+ readonly severity: Severity;
204
+ readonly message: string;
205
+ readonly key: KeyString | undefined;
206
+ readonly locale: LocaleCode | undefined;
207
+ /** Path relative to the project root. */
208
+ readonly file: string | undefined;
209
+ readonly range: WireRange | undefined;
210
+ readonly fixes: readonly Fix[];
211
+ }
212
+ interface Envelope<T> {
213
+ readonly x18n: number;
214
+ readonly command: string;
215
+ readonly data: T;
216
+ readonly diagnostics: readonly WireDiagnostic[];
217
+ readonly errors: readonly ErrorInfo[];
218
+ }
219
+ /** Line and column form of an offset range in a text. */
220
+ export declare function toWireRange(text: string | undefined, start: number, end: number): WireRange;
221
+ export declare function toWireDiagnostic(project: string, diagnostic: Diagnostic, text: (path: string) => string | undefined): WireDiagnostic;
222
+ export declare function envelope<T>(command: string, data: T, diagnostics?: readonly WireDiagnostic[], errors?: readonly ErrorInfo[]): Envelope<T>;
223
+ //#endregion
224
+ //#region src/types/host.d.ts
225
+ interface Disposable {
226
+ readonly dispose: () => void;
227
+ }
228
+ interface GlobOptions {
229
+ readonly ignore?: readonly string[] | undefined;
230
+ /** Honour the project's `.gitignore` files. */
231
+ readonly gitignore?: boolean | undefined;
232
+ }
233
+ interface FileEvent {
234
+ readonly type: "create" | "change" | "delete";
235
+ /** Posix path relative to the host root. */
236
+ readonly path: string;
237
+ }
238
+ /** Persistent key-value store. Values are JSON text. */
239
+ interface CacheStore {
240
+ readonly get: (key: string) => Promise<string | undefined>;
241
+ readonly set: (key: string, value: string) => Promise<void>;
242
+ }
243
+ interface Logger {
244
+ readonly info: (message: string) => void;
245
+ readonly warn: (message: string) => void;
246
+ readonly error: (message: string) => void;
247
+ }
248
+ /** Gives a project file access, globbing, watching and caching. All paths are posix and relative to `root`. */
249
+ interface Host {
250
+ readonly root: string;
251
+ readonly readFile: (path: string) => Promise<string | undefined>;
252
+ readonly writeFile: (path: string, content: string) => Promise<void>;
253
+ readonly deleteFile: (path: string) => Promise<void>;
254
+ readonly glob: (patterns: readonly string[], options?: GlobOptions) => Promise<string[]>;
255
+ readonly watch?: ((patterns: readonly string[], onChange: (events: readonly FileEvent[]) => void) => Disposable) | undefined;
256
+ readonly cache?: CacheStore | undefined;
257
+ readonly logger?: Logger | undefined;
258
+ }
259
+ //#endregion
260
+ //#region src/types/plugin.d.ts
261
+ interface ConfigContext {
262
+ readonly host: Host;
263
+ /** The user config as written, before presets ran. */
264
+ readonly user: SerializableConfig;
265
+ }
266
+ interface ManifestReader {
267
+ readonly id: string;
268
+ /** File name relative to the project root, for example 'package.json'. */
269
+ readonly file: string;
270
+ /** Dependency names listed in the manifest. */
271
+ readonly read: (text: string) => readonly string[];
272
+ }
273
+ interface DetectContext {
274
+ readonly host: Host;
275
+ readonly dependencies: ReadonlySet<string>;
276
+ readonly hasDependency: (name: string) => boolean;
277
+ readonly hasAnyDependency: (names: readonly string[]) => boolean;
278
+ readonly fileExists: (pattern: string) => Promise<boolean>;
279
+ }
280
+ interface ResourceCandidate {
281
+ readonly path: string;
282
+ readonly locale: LocaleCode;
283
+ readonly namespace: string | undefined;
284
+ /** Format id hint; otherwise picked by extension. */
285
+ readonly format?: string | undefined;
286
+ readonly block?: ResourceBlock | undefined;
287
+ readonly readonly?: boolean | undefined;
288
+ }
289
+ interface FinderContext {
290
+ readonly host: Host;
291
+ readonly config: ResolvedConfig;
292
+ /** Extensions of every registered format. */
293
+ readonly extensions: readonly string[];
294
+ }
295
+ interface LocaleFinder {
296
+ readonly id: string;
297
+ readonly override?: boolean | undefined;
298
+ readonly find: (ctx: FinderContext) => Promise<readonly ResourceCandidate[]>;
299
+ /** Where a new resource for (locale, namespace) should go. Used by edits that create files. */
300
+ readonly resolveNew?: ((target: {
301
+ readonly locale: LocaleCode;
302
+ readonly namespace: string | undefined;
303
+ }, ctx: FinderContext) => string | undefined) | undefined;
304
+ }
305
+ interface FormatContext {
306
+ readonly path: string;
307
+ readonly locale: LocaleCode;
308
+ readonly namespace: string | undefined;
309
+ readonly indent: number | "tab" | undefined;
310
+ }
311
+ interface ParseResult {
312
+ readonly tree: MessageTree;
313
+ /** Ranges of keys and values (leaves and objects), keyed by `pathId(storedPath)`. */
314
+ readonly ranges?: ReadonlyMap<string, NodeRange> | undefined;
315
+ }
316
+ type MessageOp = {
317
+ readonly type: "set";
318
+ readonly path: readonly string[];
319
+ readonly value: MessageLeaf;
320
+ } | {
321
+ readonly type: "delete";
322
+ readonly path: readonly string[];
323
+ };
324
+ interface Format {
325
+ readonly id: string;
326
+ /** File extensions without the dot. */
327
+ readonly extensions: readonly string[];
328
+ readonly parse: (text: string, ctx: FormatContext) => ParseResult;
329
+ /** Edits text in place. Preferred; keeps comments and layout. Ops run in order. */
330
+ readonly edit?: ((text: string, ops: readonly MessageOp[], ctx: FormatContext) => readonly TextEdit[]) | undefined;
331
+ /** Full serialization. Used to create files, and when `edit` is missing. */
332
+ readonly serialize?: ((tree: MessageTree, ctx: FormatContext) => string) | undefined;
333
+ }
334
+ interface SourceFile {
335
+ readonly path: string;
336
+ readonly text: string;
337
+ /** Extension without the dot. */
338
+ readonly extension: string;
339
+ }
340
+ interface ScanContext {
341
+ readonly config: ResolvedConfig;
342
+ /** Call specs after `usage.ignoreCallees`. */
343
+ readonly calls: readonly CallSpec[];
344
+ }
345
+ interface UsageCandidate {
346
+ readonly raw: string;
347
+ readonly range: TextRange;
348
+ readonly kind: UsageKind;
349
+ readonly dynamic: false | "prefix" | "unknown";
350
+ readonly namespace?: string | undefined;
351
+ readonly keyPrefix?: string | undefined;
352
+ readonly locale?: LocaleCode | undefined;
353
+ }
354
+ /** A region of code with a default namespace or key prefix. */
355
+ interface Scope {
356
+ readonly range: TextRange;
357
+ readonly namespace?: string | undefined;
358
+ readonly keyPrefix?: string | undefined;
359
+ }
360
+ interface HardString {
361
+ readonly text: string;
362
+ /** Range of the whole literal, quotes included: what a replacement rewrites. */
363
+ readonly range: TextRange;
364
+ readonly kind: string;
365
+ /** Template arguments: `${name}` becomes `{name}` in the message, the expression is passed to the call. */
366
+ readonly args?: readonly {
367
+ readonly name: string;
368
+ readonly expression: string;
369
+ }[] | undefined;
370
+ /** Attribute name for attribute kinds. */
371
+ readonly attribute?: string | undefined;
372
+ }
373
+ interface ScanResult {
374
+ readonly usages: readonly UsageCandidate[];
375
+ readonly scopes?: readonly Scope[] | undefined;
376
+ /** Positions where completion of a key makes sense. */
377
+ readonly keySlots?: readonly TextRange[] | undefined;
378
+ /** Hard strings found while walking the same AST, for extraction. */
379
+ readonly hardStrings?: readonly HardString[] | undefined;
380
+ }
381
+ interface Scanner {
382
+ readonly id: string;
383
+ /** File extensions without dot. `*` matches every file. */
384
+ readonly extensions: readonly string[];
385
+ readonly runtime?: "any" | "node" | undefined;
386
+ readonly scan: (file: SourceFile, ctx: ScanContext) => ScanResult | Promise<ScanResult>;
387
+ }
388
+ interface Extractor {
389
+ readonly id: string;
390
+ /** Replacement templates per hard-string kind for this library. */
391
+ readonly templates: readonly ExtractTemplate[];
392
+ }
393
+ interface DiagnosticInput {
394
+ readonly message: string;
395
+ readonly key?: KeyString | undefined;
396
+ readonly locale?: LocaleCode | undefined;
397
+ /** Defaults to the message range of `key` in `locale` (or the source locale). */
398
+ readonly location?: Location | undefined;
399
+ readonly severity?: Severity | undefined;
400
+ readonly fixes?: readonly Fix[] | undefined;
401
+ }
402
+ interface LocaleCoverage {
403
+ readonly locale: LocaleCode;
404
+ readonly total: number;
405
+ readonly translated: number;
406
+ readonly missing: readonly KeyString[];
407
+ readonly empty: readonly KeyString[];
408
+ /** Translated keys whose message last changed before the source message. */
409
+ readonly outdated: readonly KeyString[];
410
+ }
411
+ /** When a message last changed, as a history provider knows it. */
412
+ interface MessageChange {
413
+ /** Milliseconds since the epoch. `Infinity` for a change not yet known to the provider. */
414
+ readonly updatedAt: number;
415
+ /** A provider revision, such as a commit sha. */
416
+ readonly revision?: string | undefined;
417
+ readonly author?: string | undefined;
418
+ /** The value the provider knows. A different current value is a local change. */
419
+ readonly value?: MessageLeaf | undefined;
420
+ }
421
+ interface MessageHistory {
422
+ readonly changes: ReadonlyMap<KeyString, ReadonlyMap<LocaleCode, MessageChange>>;
423
+ /** The value a message had at a time, for translate prompts of stale messages. */
424
+ readonly valueAt?: ((key: KeyString, locale: LocaleCode, at: number) => MessageLeaf | undefined) | undefined;
425
+ }
426
+ interface HistoryContext {
427
+ readonly host: Host;
428
+ readonly config: ResolvedConfig;
429
+ readonly resources: readonly Resource[];
430
+ /** Messages of a resource in another version of its file, read like the current file. Undefined for embedded resources and parse errors. */
431
+ readonly messagesIn: (resource: Resource, text: string) => ReadonlyMap<KeyString, MessageLeaf> | undefined;
432
+ }
433
+ interface HistoryProvider {
434
+ readonly id: string;
435
+ /** Reads when each message last changed. Undefined when the provider has nothing for this project. */
436
+ readonly load: (ctx: HistoryContext) => Promise<MessageHistory | undefined>;
437
+ /** Calls `onChange` when the history changes outside resource files, for example on a commit. */
438
+ readonly watch?: ((ctx: HistoryContext, onChange: () => void) => Disposable) | undefined;
439
+ }
440
+ interface CheckContext {
441
+ readonly config: ResolvedConfig;
442
+ readonly sourceLocale: LocaleCode;
443
+ readonly locales: readonly LocaleCode[];
444
+ readonly resources: readonly Resource[];
445
+ /** Options from `[severity, options]` in config. */
446
+ readonly options: JsonObject;
447
+ /** True when at least one scanner is registered. */
448
+ readonly hasScanners: boolean;
449
+ readonly keys: () => readonly KeyString[];
450
+ readonly messages: (locale?: LocaleCode) => Iterable<Message>;
451
+ readonly message: (key: KeyString, locale: LocaleCode) => Message | undefined;
452
+ /** Every resource message of a key in a locale, more than one when duplicated across files. */
453
+ readonly duplicates: (key: KeyString, locale: LocaleCode) => readonly Message[];
454
+ readonly usages: () => Iterable<Usage>;
455
+ readonly coverage: () => readonly LocaleCoverage[];
456
+ readonly unused: () => readonly KeyString[];
457
+ /** Usages whose key is not defined in the source locale. */
458
+ readonly undefinedUsages: () => readonly Usage[];
459
+ readonly placeholders: (value: string) => readonly Placeholder[];
460
+ readonly placeholderSyntaxes: readonly PlaceholderSyntax[];
461
+ /** Errors reported by the `validate` of every placeholder syntax. */
462
+ readonly syntaxErrors: (value: string) => readonly string[];
463
+ readonly localeInfo: (code: LocaleCode) => LocaleInfo;
464
+ readonly text: (path: string) => string | undefined;
465
+ readonly hardStrings: () => Iterable<HardString & {
466
+ readonly path: string;
467
+ }>;
468
+ /** When a message last changed, from the history providers. Undefined until history is loaded. */
469
+ readonly history: (key: KeyString, locale: LocaleCode) => MessageChange | undefined;
470
+ }
471
+ interface Check {
472
+ readonly id: string;
473
+ readonly defaultSeverity: Severity | "off";
474
+ readonly description?: string | undefined;
475
+ readonly docs?: string | undefined;
476
+ readonly override?: boolean | undefined;
477
+ readonly run: (ctx: CheckContext) => Iterable<DiagnosticInput>;
478
+ }
479
+ interface ReportSummary {
480
+ readonly errors: number;
481
+ readonly warnings: number;
482
+ readonly infos: number;
483
+ readonly files: number;
484
+ }
485
+ interface ReportInput {
486
+ readonly project: string;
487
+ /** File text, for code frames and line numbers. */
488
+ readonly text: (path: string) => string | undefined;
489
+ readonly diagnostics: readonly Diagnostic[];
490
+ readonly coverage: readonly LocaleCoverage[];
491
+ readonly summary: ReportSummary;
492
+ }
493
+ interface ReporterContext {
494
+ /** Turns a project path into the path to print (relative to the cwd). */
495
+ readonly displayPath: (path: string, project: string) => string;
496
+ readonly color: boolean;
497
+ }
498
+ interface Reporter {
499
+ readonly id: string;
500
+ readonly override?: boolean | undefined;
501
+ readonly report: (inputs: readonly ReportInput[], ctx: ReporterContext) => string | Promise<string>;
502
+ }
503
+ interface PlaceholderSyntax {
504
+ readonly id: string;
505
+ readonly find: (value: string) => readonly Placeholder[];
506
+ /** Syntax errors in a value, for the `invalid-syntax` check. */
507
+ readonly validate?: ((value: string) => readonly string[]) | undefined;
508
+ /** Text used in prompts, for example `{name}`. */
509
+ readonly example?: string | undefined;
510
+ /** The placeholder name is another key (vue-i18n `@:key`, i18next `$t(key)`), which then counts as used. */
511
+ readonly reference?: boolean | undefined;
512
+ /** Names the library always passes, which a translation may leave out or add (vue-i18n `n` and `count`). */
513
+ readonly implicit?: readonly string[] | undefined;
514
+ }
515
+ interface KeyContext {
516
+ readonly path: string;
517
+ }
518
+ interface ResourceTransformContext {
519
+ readonly locale: LocaleCode;
520
+ readonly namespace: string | undefined;
521
+ readonly path: string;
522
+ }
523
+ /**
524
+ * Changes how a resource's tree maps to keys, for example Rails' top-level locale key
525
+ * or Chrome's `{ "name": { "message": "..." } }`. Edits go to the stored paths.
526
+ */
527
+ interface ResourceTransform {
528
+ /** Whether the transform applies to a resource. Default: every resource. */
529
+ readonly applies?: ((ctx: ResourceTransformContext) => boolean) | undefined;
530
+ readonly read: (tree: MessageTree, ctx: ResourceTransformContext) => MessageTree;
531
+ /** The path in the file of a key path of the transformed tree. */
532
+ readonly toStored: (path: readonly string[], ctx: ResourceTransformContext) => string[];
533
+ }
534
+ interface PromptDraft {
535
+ readonly rules: string[];
536
+ readonly notes: string[];
537
+ }
538
+ interface PromptContext {
539
+ readonly sourceLocale: LocaleCode;
540
+ readonly targetLocale: LocaleCode;
541
+ readonly localeInfo: LocaleInfo;
542
+ }
543
+ interface Plugin {
544
+ /** Unique, kebab-case. Built-ins use the `x18n:` prefix. */
545
+ readonly name: string;
546
+ readonly enforce?: "pre" | "post" | undefined;
547
+ /** Where the plugin can run. Default 'any'. */
548
+ readonly runtime?: "any" | "node" | undefined;
549
+ /** Change the config before it is final. Presets use this to set defaults. */
550
+ readonly config?: ((config: ConfigDraft, ctx: ConfigContext) => void | Promise<void>) | undefined;
551
+ readonly configResolved?: ((config: ResolvedConfig) => void) | undefined;
552
+ readonly manifests?: readonly ManifestReader[] | undefined;
553
+ readonly localeFinders?: readonly LocaleFinder[] | undefined;
554
+ readonly formats?: readonly Format[] | undefined;
555
+ readonly scanners?: readonly Scanner[] | undefined;
556
+ readonly extractors?: readonly Extractor[] | undefined;
557
+ readonly checks?: readonly Check[] | undefined;
558
+ readonly reporters?: readonly Reporter[] | undefined;
559
+ readonly placeholders?: readonly PlaceholderSyntax[] | undefined;
560
+ readonly histories?: readonly HistoryProvider[] | undefined;
561
+ /** Turns raw key text into canonical form. The first plugin that returns a value wins. */
562
+ readonly normalizeKey?: ((raw: string, ctx: KeyContext) => string | undefined) | undefined;
563
+ readonly derivedKeys?: readonly string[] | undefined;
564
+ readonly transformResource?: ResourceTransform | undefined;
565
+ readonly translatePrompt?: ((draft: PromptDraft, ctx: PromptContext) => void) | undefined;
566
+ /** Display data for a locale code. The first plugin that returns a value wins. */
567
+ readonly localeInfo?: ((code: LocaleCode) => Partial<LocaleInfo> | undefined) | undefined;
568
+ }
569
+ interface Preset {
570
+ readonly name: string;
571
+ /** Decides if the preset applies. Without `detect`, the preset applies only when listed in config. */
572
+ readonly detect?: ((ctx: DetectContext) => boolean | Promise<boolean>) | undefined;
573
+ /** When true and detected, presets that come after it are not applied. */
574
+ readonly exclusive?: boolean | undefined;
575
+ readonly plugins: readonly (Plugin | Preset)[];
576
+ }
577
+ /** A preset factory as referenced by name from YAML and JSON configs. */
578
+ type PresetFactory = (options?: JsonObject) => Preset;
579
+ //#endregion
580
+ //#region src/types/config.d.ts
581
+ /** Where a value comes from: an argument, or a property of an object argument. */
582
+ interface ArgSource {
583
+ readonly arg: number;
584
+ readonly property?: string | undefined;
585
+ }
586
+ /** Data that drives the AST scanners: which calls are translate calls and where the key is. */
587
+ interface CallSpec {
588
+ /** Function or member path: 't', '$t', 'i18n.t', 'intl.formatMessage'. */
589
+ readonly callee: string | readonly string[];
590
+ /** 'call' (default): the key is an argument. 'selector': the argument is `$ => $.a.b`. 'accessor': member chain on a root. */
591
+ readonly kind?: "call" | "selector" | "accessor" | undefined;
592
+ /** Which argument holds the key. Default 0. */
593
+ readonly key?: number | ArgSource | undefined;
594
+ /** Where the namespace comes from (call option, or factory argument when `factory` is true). */
595
+ readonly namespace?: ArgSource | undefined;
596
+ /** Where a key prefix comes from (`keyPrefix` option, or next-intl `useTranslations('a.b')`). */
597
+ readonly keyPrefix?: ArgSource | undefined;
598
+ /** The callee is a factory that returns the translate function, for example `useI18n()` returning `{ t }`. */
599
+ readonly factory?: boolean | undefined;
600
+ /** For factories: the names of the returned translate functions. Default `['t']`. */
601
+ readonly returns?: readonly string[] | undefined;
602
+ /** Type names that mark a parameter or prop as a translate function: ['TFunction']. */
603
+ readonly types?: readonly string[] | undefined;
604
+ }
605
+ interface RegexScannerSpec {
606
+ /** File extensions, without dot. */
607
+ readonly extensions: readonly string[];
608
+ /** Patterns with a `{key}` placeholder (i18n-ally `usageMatchRegex`), or a regex whose first group is the key. */
609
+ readonly patterns: readonly string[];
610
+ }
611
+ interface ResourceSpec {
612
+ /** Path pattern with `{locale}`, `{locale?}`, `{namespace}`, `{namespaces}` and `{ext}` tokens and globs. */
613
+ readonly pattern: string;
614
+ readonly format?: string | undefined;
615
+ /** Fixed namespace for every matching file. */
616
+ readonly namespace?: string | undefined;
617
+ /** Fixed locale for every matching file, for patterns without `{locale}` (`package.nls.json`). */
618
+ readonly locale?: string | undefined;
619
+ /** Run matching JS/TS files in Node instead of reading them statically. Makes them read-only. */
620
+ readonly execute?: boolean | undefined;
621
+ }
622
+ type CheckLevel = Severity | "off";
623
+ type CheckSetting = CheckLevel | readonly [CheckLevel, JsonObject];
624
+ interface GlossaryEntry {
625
+ readonly term: string;
626
+ /** Translation per locale. */
627
+ readonly translations?: {
628
+ readonly [locale: string]: string;
629
+ } | undefined;
630
+ readonly note?: string | undefined;
631
+ readonly doNotTranslate?: boolean | undefined;
632
+ }
633
+ interface ExtractTemplate {
634
+ readonly template: string;
635
+ /** Hard-string kinds the template applies to, for example `jsx-text`. */
636
+ readonly kinds?: readonly string[] | undefined;
637
+ /** File globs the template applies to. */
638
+ readonly files?: readonly string[] | undefined;
639
+ /** Lines added once per file when missing, for example an import. */
640
+ readonly imports?: readonly string[] | undefined;
641
+ }
642
+ interface ExtractOptions {
643
+ /** Report hard strings as `hard-string` diagnostics. */
644
+ readonly autoDetect?: boolean | undefined;
645
+ readonly keygen?: "slug" | "source" | "random" | "empty" | undefined;
646
+ readonly keyCase?: "camel" | "snake" | "kebab" | "dot" | undefined;
647
+ /** Template with `{fileName}`, `{dirName}` or `{component}`. */
648
+ readonly keyPrefix?: string | undefined;
649
+ readonly keyMaxLength?: number | undefined;
650
+ /** Reuse a key when the same text exists as a source value. Default true. */
651
+ readonly reuseExisting?: boolean | undefined;
652
+ /** Strings or `/regex/` never extracted. */
653
+ readonly ignore?: readonly string[] | undefined;
654
+ /** Ignored strings per file glob. */
655
+ readonly ignoreByFile?: {
656
+ readonly [glob: string]: readonly string[];
657
+ } | undefined;
658
+ readonly ignoreAttributes?: readonly string[] | undefined;
659
+ readonly ignoreCallees?: readonly string[] | undefined;
660
+ readonly templates?: readonly (string | ExtractTemplate)[] | undefined;
661
+ }
662
+ interface UsageOptions {
663
+ readonly include?: readonly string[] | undefined;
664
+ readonly exclude?: readonly string[] | undefined;
665
+ readonly calls?: readonly CallSpec[] | undefined;
666
+ readonly regex?: readonly RegexScannerSpec[] | undefined;
667
+ /** Callee names never counted as translate calls. */
668
+ readonly ignoreCallees?: readonly string[] | undefined;
669
+ /** Keys (globs) that count as used, for example keys built at runtime. */
670
+ readonly keysInUse?: readonly string[] | undefined;
671
+ /** Rules like `{key}_plural`: when `{key}` is used the derived keys count as used. */
672
+ readonly derivedKeys?: readonly string[] | undefined;
673
+ }
674
+ interface WriteOptions {
675
+ readonly sort?: false | "binary" | "locale" | undefined;
676
+ readonly indent?: number | "tab" | undefined;
677
+ /** i18n-ally `keepFulfilled`: `set` in one locale adds the key with an empty value to the others. */
678
+ readonly keepFilled?: boolean | undefined;
679
+ }
680
+ interface NamespaceOptions {
681
+ /** Separator between namespace and key in code. `.` merges the namespace into the key path. Default `.`. */
682
+ readonly separator?: string | undefined;
683
+ /** Namespace of keys written without one. */
684
+ readonly default?: string | undefined;
685
+ /** How `{namespaces}` folders name a namespace: `dot` makes `pages/home` into `pages.home`, `slash` keeps `pages/home`, `camel` makes `todos-page` into `todosPage`. Default `dot`. */
686
+ readonly fromPath?: "dot" | "slash" | "camel" | undefined;
687
+ }
688
+ type NamespaceFromPath = NonNullable<NamespaceOptions["fromPath"]>;
689
+ type PluginSpecifier = string | readonly [string, JsonObject];
690
+ /** The part of the config that YAML and JSON files can hold. Validated by `ConfigSchema`. */
691
+ interface SerializableConfig {
692
+ readonly $schema?: string | undefined;
693
+ /** Project root, relative to the config file. */
694
+ readonly root?: string | undefined;
695
+ /** Project name in a monorepo. Default: the directory name. */
696
+ readonly name?: string | undefined;
697
+ readonly sourceLocale?: string | undefined;
698
+ /** Locale codes as written in paths. Filters the found locales. */
699
+ readonly locales?: readonly string[] | undefined;
700
+ readonly ignoreLocales?: readonly string[] | undefined;
701
+ /** `'auto'` detects built-in presets from the project's dependencies. */
702
+ readonly presets?: "auto" | readonly PluginSpecifier[] | undefined;
703
+ readonly plugins?: readonly PluginSpecifier[] | undefined;
704
+ readonly resources?: readonly ResourceSpec[] | undefined;
705
+ /** Explicit format id per file extension (without dot). */
706
+ readonly formats?: {
707
+ readonly [extension: string]: string;
708
+ } | undefined;
709
+ readonly keyStyle?: "auto" | "nested" | "flat" | undefined;
710
+ readonly namespace?: NamespaceOptions | undefined;
711
+ readonly usage?: UsageOptions | undefined;
712
+ readonly write?: WriteOptions | undefined;
713
+ readonly extract?: ExtractOptions | undefined;
714
+ /** Overrides on top of the `recommended` check set. */
715
+ readonly checks?: {
716
+ readonly [checkId: string]: CheckSetting;
717
+ } | undefined;
718
+ /** Turn every warning into an error. */
719
+ readonly strict?: boolean | undefined;
720
+ /** Keys (globs) excluded from all checks. */
721
+ readonly ignoreKeys?: readonly string[] | undefined;
722
+ readonly glossary?: readonly GlossaryEntry[] | undefined;
723
+ /** History providers for stale translations. `false` turns every provider off. Options of a provider sit under its key, such as `git: { maxDepth, since }` (or `git: false`). */
724
+ readonly history?: boolean | HistoryOptions | undefined;
725
+ /** Monorepo: directories (globs) that are projects inheriting this config. */
726
+ readonly projects?: readonly string[] | undefined;
727
+ }
728
+ /** Check ids of known plugins, for autocompletion. Plugins add theirs through declaration merging. */
729
+ interface CheckIds {}
730
+ /** Options of plugins under their own config key. Plugins add theirs through declaration merging. */
731
+ interface PluginConfigs {}
732
+ /** Options of history providers under their own key, such as `git`. Providers add theirs through declaration merging. */
733
+ interface HistoryConfigs {}
734
+ type HistoryOptions = Partial<HistoryConfigs>;
735
+ interface HistorySettings extends HistoryOptions {
736
+ /** Providers asked before those of plugins. */
737
+ readonly providers: readonly HistoryProvider[];
738
+ }
739
+ type PresetOption = Preset | PluginSpecifier | false | undefined;
740
+ type PluginOption = Plugin | Preset | PluginSpecifier | false | undefined;
741
+ /** The config accepted by `defineConfig`: the serializable part plus plugin objects. */
742
+ interface UserConfig extends Omit<SerializableConfig, "presets" | "plugins" | "checks" | "history"> {
743
+ readonly presets?: "auto" | readonly PresetOption[] | undefined;
744
+ /** History providers for stale translations: `false` turns them off; provider options such as `git` sit under their key; `providers` adds providers asked first. */
745
+ readonly history?: boolean | (HistoryOptions & {
746
+ readonly providers?: readonly HistoryProvider[] | undefined;
747
+ }) | undefined;
748
+ readonly plugins?: readonly PluginOption[] | undefined;
749
+ readonly checks?: { readonly [K in keyof CheckIds]?: CheckSetting; } & {
750
+ readonly [checkId: string]: CheckSetting;
751
+ } | undefined;
752
+ readonly pluginConfigs?: Partial<PluginConfigs> | undefined;
753
+ }
754
+ type ConfigOrigin = "default" | "user" | "parent" | `plugin:${string}`;
755
+ /** The final config of one project. Every field is set. */
756
+ interface ResolvedConfig {
757
+ readonly name: string;
758
+ readonly sourceLocale: string;
759
+ readonly locales: readonly string[] | undefined;
760
+ readonly ignoreLocales: readonly string[];
761
+ readonly resources: readonly ResourceSpec[];
762
+ readonly formats: {
763
+ readonly [extension: string]: string;
764
+ };
765
+ readonly keyStyle: "auto" | "nested" | "flat";
766
+ readonly namespace: {
767
+ readonly separator: string;
768
+ readonly default: string | undefined;
769
+ readonly fromPath: NamespaceFromPath;
770
+ };
771
+ readonly usage: {
772
+ readonly include: readonly string[];
773
+ readonly exclude: readonly string[];
774
+ readonly calls: readonly CallSpec[];
775
+ readonly regex: readonly RegexScannerSpec[];
776
+ readonly ignoreCallees: readonly string[];
777
+ readonly keysInUse: readonly string[];
778
+ readonly derivedKeys: readonly string[];
779
+ };
780
+ readonly write: {
781
+ readonly sort: false | "binary" | "locale";
782
+ readonly indent: number | "tab" | undefined;
783
+ readonly keepFilled: boolean;
784
+ };
785
+ readonly extract: ExtractOptions;
786
+ readonly checks: {
787
+ readonly [checkId: string]: CheckSetting;
788
+ };
789
+ readonly strict: boolean;
790
+ readonly ignoreKeys: readonly string[];
791
+ readonly glossary: readonly GlossaryEntry[];
792
+ readonly history: false | HistorySettings;
793
+ readonly pluginConfigs: Partial<PluginConfigs>;
794
+ /** Origin of each top-level value, for `explain()`. */
795
+ readonly origins: {
796
+ readonly [key: string]: ConfigOrigin;
797
+ };
798
+ }
799
+ /** A mutable view of the config that `config` hooks change. */
800
+ type ConfigDraft = { -readonly [K in keyof Omit<ResolvedConfig, "origins" | "name">]: ResolvedConfig[K]; };
801
+ //#endregion
802
+ //#region src/define.d.ts
803
+ export declare function definePlugin<const T extends Plugin>(plugin: T): T;
804
+ export declare function definePlugin<O, const T extends Plugin>(factory: (options: O) => T): (options: O) => T;
805
+ export declare function definePreset<const T extends Preset>(preset: T): T;
806
+ export declare function defineConfig(config: UserConfig & { readonly [K in keyof PluginConfigs]?: PluginConfigs[K]; }): UserConfig;
807
+ //#endregion
808
+ //#region src/keys.d.ts
809
+ /** Canonical string form of a key: `ns:a.b.c`, or `a.b.c` without namespace. */
810
+ export declare function joinKey(namespace: string | undefined, path: readonly string[]): KeyString;
811
+ /** Splits a key string. `namespaced` is false for projects without namespaces, where `:` is part of the key. */
812
+ export declare function splitKey(key: KeyString, namespaced?: boolean): KeyId;
813
+ /** True when `key` is `prefix` itself or lies under it (`a.b` is under `a`). */
814
+ export declare function isKeyUnder(key: KeyString, prefix: KeyString): boolean;
815
+ /** Replaces the `from` prefix of `key` with `to`. */
816
+ export declare function replaceKeyPrefix(key: KeyString, from: KeyString, to: KeyString): KeyString;
817
+ /**
818
+ * Glob over paths. `**` spans separators, `*` and `?` stay inside a segment,
819
+ * `{a,b}` alternates, `[...]` is a character class.
820
+ */
821
+ export declare function globToRegExp(glob: string, separator?: string): RegExp;
822
+ /** Matcher over key globs: `*` stays inside a segment, `**` spans segments. */
823
+ export declare function keyMatcher(globs: readonly string[]): (key: KeyString) => boolean;
824
+ /** Matcher over posix file paths. */
825
+ export declare function pathMatcher(globs: readonly string[]): (path: string) => boolean;
826
+ //#endregion
827
+ //#region src/locale.d.ts
828
+ /** Lenient display parse of a locale code (`zh_CN`, `pt-BR`, `sr-Latn-RS`). Never changes the code. */
829
+ export declare function parseLocaleInfo(code: LocaleCode): LocaleInfo;
830
+ /** Codes that differ only in spelling (`zh_CN` and `zh-cn`), the same after a lenient normalization. */
831
+ export declare function localeSpellingKey(code: LocaleCode): string;
832
+ //#endregion
833
+ //#region src/memory-host.d.ts
834
+ interface MemoryHost extends Host {
835
+ readonly files: Map<string, string>;
836
+ }
837
+ /** A host over in-memory files, for tests, demos and agents that pass content directly. */
838
+ export declare function createMemoryHost(initial?: Readonly<Record<string, string>>, root?: string): MemoryHost;
839
+ //#endregion
840
+ //#region src/message-tree.d.ts
841
+ export declare function isMessageLeaf(value: unknown): value is MessageLeaf;
842
+ /** Checks parsed data (for example from `JSON.parse`) before it enters the project. */
843
+ export declare function isMessageTree(value: unknown): value is MessageTree;
844
+ /** Stable id of a stored property path, the key of `ParseResult.ranges`. */
845
+ export declare function pathId(path: readonly string[]): string;
846
+ interface TreeLeaf {
847
+ readonly path: readonly string[];
848
+ readonly value: MessageLeaf;
849
+ }
850
+ export declare function walkLeaves(tree: MessageTree, prefix?: readonly string[]): Generator<TreeLeaf>;
851
+ /** Applies ops to a copy of the tree. Parent objects left empty are removed. */
852
+ export declare function applyMessageOps(tree: MessageTree, ops: readonly MessageOp[]): MessageTree;
853
+ /** Sorts keys at every level. */
854
+ export declare function sortTree(tree: MessageTree, compare: (a: string, b: string) => number): MessageTree;
855
+ /** Builds a nested or flat tree from leaves. */
856
+ export declare function buildTree(leaves: Iterable<TreeLeaf>): MessageTree;
857
+ //#endregion
858
+ //#region src/overlay-host.d.ts
859
+ interface OverlayHost extends Host {
860
+ /** Shadows the file content, for example with an unsaved editor buffer. */
861
+ readonly setOverlay: (path: string, content: string) => void;
862
+ readonly clearOverlay: (path: string) => void;
863
+ readonly hasOverlay: (path: string) => boolean;
864
+ }
865
+ /** Wraps a host so open editor buffers shadow the content on disk. */
866
+ export declare function createOverlayHost(base: Host): OverlayHost;
867
+ //#endregion
868
+ //#region src/plugins.d.ts
869
+ export declare function isPreset(value: Plugin | Preset): value is Preset;
870
+ interface CapabilityConflict {
871
+ readonly capability: "format" | "scanner";
872
+ readonly extension: string;
873
+ readonly winner: string;
874
+ readonly loser: string;
875
+ }
876
+ /** The capabilities of the final plugin list, indexed for the project engine. */
877
+ interface PluginRegistry {
878
+ readonly plugins: readonly Plugin[];
879
+ readonly formats: readonly Format[];
880
+ readonly finders: readonly LocaleFinder[];
881
+ readonly scanners: readonly Scanner[];
882
+ readonly checks: ReadonlyMap<string, Check>;
883
+ readonly reporters: ReadonlyMap<string, Reporter>;
884
+ readonly placeholders: readonly PlaceholderSyntax[];
885
+ readonly manifests: readonly ManifestReader[];
886
+ readonly extractors: readonly Extractor[];
887
+ readonly histories: readonly HistoryProvider[];
888
+ readonly conflicts: readonly CapabilityConflict[];
889
+ /** Format for a file path: config `formats` first, then the first format that claims the extension. */
890
+ readonly formatFor: (path: string, hint?: string) => Format | undefined;
891
+ readonly formatById: (id: string) => Format | undefined;
892
+ readonly scannersFor: (path: string) => readonly Scanner[];
893
+ }
894
+ export declare function extensionOf(path: string): string;
895
+ export declare function createRegistry(input: readonly Plugin[], config: Pick<ResolvedConfig, "formats">): PluginRegistry;
896
+ //#endregion
897
+ //#region src/project/prompt.d.ts
898
+ interface PromptOptions {
899
+ /** Key glob, or a list of keys. */
900
+ readonly keys?: string | readonly KeyString[] | undefined;
901
+ readonly namespace?: string | undefined;
902
+ /** Items per prompt. Default 50. */
903
+ readonly limit?: number | undefined;
904
+ /** Offset from `nextCursor` of the previous prompt. */
905
+ readonly cursor?: string | undefined;
906
+ /** Include code around usages. Default true. */
907
+ readonly context?: boolean | undefined;
908
+ /** Translate prompts: add stale translations (load history first). */
909
+ readonly stale?: boolean | undefined;
910
+ }
911
+ interface UsageContext {
912
+ readonly path: string;
913
+ readonly line: number;
914
+ readonly snippet: string;
915
+ }
916
+ interface PromptItem {
917
+ readonly key: KeyString;
918
+ readonly source: string;
919
+ readonly placeholders: readonly string[];
920
+ /** The current value in the target locale, when there is one. */
921
+ readonly existing: string | undefined;
922
+ /** For a stale translation: the source value when the translation last changed, when known. */
923
+ readonly previousSource?: string | undefined;
924
+ readonly context: readonly UsageContext[];
925
+ }
926
+ interface PromptData {
927
+ readonly kind: "translate" | "review";
928
+ readonly project: string;
929
+ readonly from: LocaleCode;
930
+ readonly to: LocaleCode;
931
+ readonly targetName: string | undefined;
932
+ readonly total: number;
933
+ readonly remaining: number;
934
+ readonly nextCursor: string | undefined;
935
+ readonly rules: readonly string[];
936
+ readonly notes: readonly string[];
937
+ readonly glossary: readonly {
938
+ readonly term: string;
939
+ readonly translation: string | undefined;
940
+ readonly note: string | undefined;
941
+ readonly doNotTranslate: boolean;
942
+ }[];
943
+ readonly examples: readonly {
944
+ readonly key: KeyString;
945
+ readonly source: string;
946
+ readonly target: string;
947
+ }[];
948
+ readonly items: readonly PromptItem[];
949
+ readonly instructions: readonly string[];
950
+ }
951
+ /** Plain markdown, with no provider-specific syntax. */
952
+ export declare function renderPrompt(data: PromptData): string;
953
+ //#endregion
954
+ //#region src/resolve.d.ts
955
+ /** Plugins that are always on, and presets that `'auto'` and names refer to. Passed in by the caller. */
956
+ interface Builtins {
957
+ readonly plugins: readonly Plugin[];
958
+ readonly presets: {
959
+ readonly [name: string]: PresetFactory;
960
+ };
961
+ }
962
+ interface ResolveConfigOptions {
963
+ readonly host: Host;
964
+ readonly config: UserConfig;
965
+ /** Root config of a monorepo, inherited by this project. */
966
+ readonly parent?: UserConfig | undefined;
967
+ readonly builtins: Builtins;
968
+ /** Default project name. */
969
+ readonly name?: string | undefined;
970
+ /** Loads string plugin specifiers. Without it, string plugins are a config error. */
971
+ readonly loadPlugin?: ((specifier: string, options: JsonObject | undefined) => Promise<Plugin | Preset>) | undefined;
972
+ readonly runtime?: "node" | "browser" | undefined;
973
+ /** Extra directories (relative to the host root) whose manifests count for detection, such as the workspace root. */
974
+ readonly manifestRoots?: readonly string[] | undefined;
975
+ }
976
+ interface PresetExplanation {
977
+ readonly name: string;
978
+ readonly reason: "listed" | "detected" | "not-detected" | "after-exclusive";
979
+ }
980
+ interface Setup {
981
+ readonly config: ResolvedConfig;
982
+ readonly registry: PluginRegistry;
983
+ readonly presets: readonly PresetExplanation[];
984
+ /** Plugins skipped because they cannot run in this runtime. */
985
+ readonly skipped: readonly {
986
+ readonly name: string;
987
+ readonly reason: string;
988
+ }[];
989
+ }
990
+ export declare function resolveConfig(options: ResolveConfigOptions): Promise<Setup>;
991
+ //#endregion
992
+ //#region src/types/project.d.ts
993
+ interface KeyQuery {
994
+ /** Key glob: `*` inside a segment, `**` across segments. */
995
+ readonly glob?: string | undefined;
996
+ readonly namespace?: string | undefined;
997
+ /** Only keys missing (or empty) in this locale. */
998
+ readonly missing?: LocaleCode | undefined;
999
+ /** Only keys without usages. */
1000
+ readonly unused?: boolean | undefined;
1001
+ }
1002
+ interface UsageMatch {
1003
+ readonly usage: Usage;
1004
+ /** True for prefix usages that may refer to the key. */
1005
+ readonly possible: boolean;
1006
+ }
1007
+ interface UsageQuery {
1008
+ readonly key?: KeyString | undefined;
1009
+ /** Every usage of a key under this prefix (subtree). */
1010
+ readonly prefix?: KeyString | undefined;
1011
+ readonly path?: string | undefined;
1012
+ }
1013
+ interface KeyInfo {
1014
+ readonly key: KeyString;
1015
+ readonly namespace: string | undefined;
1016
+ readonly path: readonly string[];
1017
+ /** One message per locale that has the key, source locale first. */
1018
+ readonly messages: readonly Message[];
1019
+ readonly missing: readonly LocaleCode[];
1020
+ readonly usages: readonly UsageMatch[];
1021
+ readonly diagnostics: readonly Diagnostic[];
1022
+ }
1023
+ /** The key, or the resource node, under a position. */
1024
+ type KeyTarget = {
1025
+ readonly type: "key";
1026
+ readonly key: KeyString;
1027
+ readonly range: TextRange;
1028
+ readonly source: "usage" | "resource";
1029
+ readonly usage?: Usage | undefined;
1030
+ } | {
1031
+ readonly type: "subtree";
1032
+ readonly key: KeyString;
1033
+ readonly range: TextRange;
1034
+ readonly source: "resource";
1035
+ };
1036
+ /** A key or parent node in a resource file, with its ranges. */
1037
+ interface ResourceNode {
1038
+ readonly key: KeyString;
1039
+ readonly range: NodeRange;
1040
+ /** False for parent objects. */
1041
+ readonly leaf: boolean;
1042
+ readonly locale: LocaleCode;
1043
+ readonly path: string;
1044
+ }
1045
+ interface Analysis {
1046
+ readonly revision: number;
1047
+ readonly diagnostics: readonly Diagnostic[];
1048
+ readonly coverage: readonly LocaleCoverage[];
1049
+ readonly unused: readonly KeyString[];
1050
+ /** Usages whose key is not defined in the source locale. */
1051
+ readonly undefinedUsages: readonly Usage[];
1052
+ }
1053
+ interface ProjectExplanation {
1054
+ readonly name: string;
1055
+ readonly root: string;
1056
+ readonly presets: readonly PresetExplanation[];
1057
+ readonly plugins: readonly string[];
1058
+ readonly skipped: readonly {
1059
+ readonly name: string;
1060
+ readonly reason: string;
1061
+ }[];
1062
+ readonly finders: readonly {
1063
+ readonly id: string;
1064
+ readonly resources: readonly string[];
1065
+ }[];
1066
+ /** Candidates dropped because an earlier finder already returned the same resource. */
1067
+ readonly duplicates: readonly {
1068
+ readonly path: string;
1069
+ readonly finder: string;
1070
+ readonly keptFrom: string;
1071
+ }[];
1072
+ readonly formats: readonly {
1073
+ readonly id: string;
1074
+ readonly extensions: readonly string[];
1075
+ readonly resources: number;
1076
+ }[];
1077
+ readonly scanners: readonly {
1078
+ readonly id: string;
1079
+ readonly extensions: readonly string[];
1080
+ readonly files: number;
1081
+ }[];
1082
+ readonly conflicts: readonly CapabilityConflict[];
1083
+ readonly errors: readonly (ErrorInfo & {
1084
+ readonly path?: string | undefined;
1085
+ })[];
1086
+ readonly config: ResolvedConfig;
1087
+ }
1088
+ type FileChange = {
1089
+ readonly type: "edit";
1090
+ readonly path: string;
1091
+ readonly edits: readonly TextEdit[];
1092
+ } | {
1093
+ readonly type: "create";
1094
+ readonly path: string;
1095
+ readonly content: string;
1096
+ } | {
1097
+ readonly type: "delete";
1098
+ readonly path: string;
1099
+ };
1100
+ interface DecisionOption {
1101
+ readonly id: string;
1102
+ readonly label: string;
1103
+ }
1104
+ /** A question in a plan that a surface must answer before apply. */
1105
+ interface Decision {
1106
+ readonly id: string;
1107
+ readonly message: string;
1108
+ readonly options: readonly DecisionOption[];
1109
+ /** The option picked by `--yes`. */
1110
+ readonly default: string;
1111
+ }
1112
+ interface Plan {
1113
+ readonly id: string;
1114
+ readonly revision: number;
1115
+ readonly ops: readonly EditOp[];
1116
+ readonly changes: readonly FileChange[];
1117
+ readonly decisions: readonly Decision[];
1118
+ readonly warnings: readonly string[];
1119
+ /** Keys whose messages or usages the plan changes. */
1120
+ readonly keys: readonly KeyString[];
1121
+ }
1122
+ interface Answers {
1123
+ readonly [decisionId: string]: string;
1124
+ }
1125
+ interface ApplyResult {
1126
+ readonly revision: number;
1127
+ readonly changes: readonly FileChange[];
1128
+ }
1129
+ interface ProjectChange {
1130
+ readonly revision: number;
1131
+ readonly paths: readonly string[];
1132
+ readonly keys: readonly KeyString[];
1133
+ }
1134
+ interface FileScan {
1135
+ readonly path: string;
1136
+ readonly result: ScanResult;
1137
+ }
1138
+ interface Project {
1139
+ readonly name: string;
1140
+ readonly config: ResolvedConfig;
1141
+ /** Resolves when discovery, parse, scan and index are done. */
1142
+ readonly ready: Promise<void>;
1143
+ readonly revision: number;
1144
+ readonly locales: readonly LocaleCode[];
1145
+ readonly sourceLocale: LocaleCode;
1146
+ readonly resources: readonly Resource[];
1147
+ /** True when keys carry a namespace (`ns:key`). */
1148
+ readonly namespaced: boolean;
1149
+ readonly reporters: ReadonlyMap<string, Reporter>;
1150
+ readonly placeholderSyntaxes: readonly PlaceholderSyntax[];
1151
+ /** Extraction templates: config `extract.templates` first, then those of presets. */
1152
+ readonly extractTemplates: readonly ExtractTemplate[];
1153
+ readonly keys: (query?: KeyQuery) => KeyString[];
1154
+ readonly get: (key: KeyString) => KeyInfo | undefined;
1155
+ readonly message: (key: KeyString, locale: LocaleCode) => Message | undefined;
1156
+ /** The message a usage of `key` shows: the key's own, or one of its derived keys (`item` → `item_other`). */
1157
+ readonly lookup: (key: KeyString, locale: LocaleCode) => Message | undefined;
1158
+ /** Parses user input such as `common:save` or `save` into a key string. */
1159
+ readonly parseKey: (input: string) => KeyString;
1160
+ readonly usages: (query?: UsageQuery) => UsageMatch[];
1161
+ readonly keyAt: (path: string, offset: number) => KeyTarget | undefined;
1162
+ /** Key and parent nodes of a resource file, in file order. */
1163
+ readonly nodes: (path: string) => readonly ResourceNode[];
1164
+ /** The nodes of a key (or parent) in every locale, source locale first. */
1165
+ readonly locations: (key: KeyString) => readonly ResourceNode[];
1166
+ /** Completion positions in a source file. */
1167
+ readonly keySlots: (path: string) => readonly TextRange[];
1168
+ readonly hardStrings: (path?: string) => readonly (HardString & {
1169
+ readonly path: string;
1170
+ })[];
1171
+ readonly analyze: () => Analysis;
1172
+ /** Loads history from the history providers, after `ready`. `watch` reloads it when a provider sees a change. Analysis runs again once it is loaded. */
1173
+ readonly loadHistory: (options?: {
1174
+ readonly watch?: boolean | undefined;
1175
+ }) => Promise<void>;
1176
+ /** When a message last changed. Undefined until history is loaded, and for messages without history. */
1177
+ readonly history: (key: KeyString, locale: LocaleCode) => MessageChange | undefined;
1178
+ /** The value a message had at a time (ms), from the provider that knows the message. */
1179
+ readonly valueAt: (key: KeyString, locale: LocaleCode, at: number) => MessageLeaf | undefined;
1180
+ /** Parts of a translate or review prompt for an agent or LLM; render with `renderPrompt`. */
1181
+ readonly prompt: (kind: "translate" | "review", locale: LocaleCode, options?: PromptOptions) => PromptData;
1182
+ readonly explain: () => ProjectExplanation;
1183
+ readonly localeInfo: (code: LocaleCode) => LocaleInfo;
1184
+ readonly text: (path: string) => string | undefined;
1185
+ /** True when the path is a resource file or a scanned source file. */
1186
+ readonly owns: (path: string) => boolean;
1187
+ readonly plan: (ops: readonly EditOp[]) => Plan;
1188
+ readonly apply: (plan: Plan, options?: {
1189
+ readonly answers?: Answers | undefined;
1190
+ }) => Promise<ApplyResult>;
1191
+ /** Re-reads the given files. Hosts with `watch` call this; the LSP calls it for open buffers. */
1192
+ readonly update: (events: readonly FileEvent[]) => Promise<ProjectChange | undefined>;
1193
+ /** Starts watching through the host. */
1194
+ readonly watch: () => void;
1195
+ readonly onChange: (listener: (change: ProjectChange) => void) => () => void;
1196
+ readonly dispose: () => void;
1197
+ }
1198
+ //#endregion
1199
+ //#region src/project/batch.d.ts
1200
+ /** A value whose placeholders differ from the source value of its key. */
1201
+ interface PlaceholderProblem {
1202
+ readonly key: KeyString;
1203
+ readonly locale: LocaleCode;
1204
+ readonly missing: readonly string[];
1205
+ readonly extra: readonly string[];
1206
+ }
1207
+ /** Parses the batch shape `{ "<locale>": { "<key>": "<value>" } }` (as in `x18n apply`) into set ops. */
1208
+ export declare function parseMessageBatch(project: Project, data: JsonValue): EditOp[];
1209
+ /** Set ops whose value drops or adds placeholders compared to the source value. */
1210
+ type PlaceholderComparer = (source: string, target: string) => {
1211
+ readonly missing: string[];
1212
+ readonly extra: string[];
1213
+ };
1214
+ /**
1215
+ * Compares the placeholders of a target value with its source. Key references (`@:key`) are not
1216
+ * parameters, and implicit names (vue-i18n `{n}` in plural messages) may be left out. Build it once per run.
1217
+ */
1218
+ export declare function createPlaceholderComparer(syntaxes: readonly PlaceholderSyntax[], find?: (value: string) => readonly Placeholder[]): PlaceholderComparer;
1219
+ export declare function placeholderProblems(project: Project, ops: readonly EditOp[]): PlaceholderProblem[];
1220
+ //#endregion
1221
+ //#region src/project/project.d.ts
1222
+ interface CreateProjectOptions {
1223
+ readonly host: Host;
1224
+ readonly setup: Setup;
1225
+ }
1226
+ export declare function createProject(options: CreateProjectOptions): Project;
1227
+ //#endregion
1228
+ //#region src/schema.d.ts
1229
+ export declare function isJsonObject(value: unknown): value is JsonObject;
1230
+ /** Validates YAML and JSON configs, and the serializable part of TS configs. */
1231
+ export declare const ConfigSchema: v.GenericSchema<SerializableConfig>;
1232
+ /** A YAML plugin (`*.x18n-plugin.yml`): the declarative subset of the plugin API. */
1233
+ interface PluginFile {
1234
+ readonly $schema?: string | undefined;
1235
+ readonly name: string;
1236
+ readonly detect?: {
1237
+ readonly dependencies?: {
1238
+ readonly any?: readonly string[] | undefined;
1239
+ readonly all?: readonly string[] | undefined;
1240
+ } | undefined;
1241
+ readonly files?: readonly string[] | undefined;
1242
+ } | undefined;
1243
+ readonly exclusive?: boolean | undefined;
1244
+ readonly config?: {
1245
+ readonly sourceLocale?: string | undefined;
1246
+ readonly locales?: readonly string[] | undefined;
1247
+ readonly resources?: readonly ResourceSpec[] | undefined;
1248
+ readonly namespace?: NamespaceOptions | undefined;
1249
+ readonly keyStyle?: "auto" | "nested" | "flat" | undefined;
1250
+ } | undefined;
1251
+ readonly scanners?: {
1252
+ readonly calls?: readonly CallSpec[] | undefined;
1253
+ readonly regex?: readonly RegexScannerSpec[] | undefined;
1254
+ } | undefined;
1255
+ readonly scopes?: {
1256
+ /** Regex whose first group is the namespace of the code after it (i18n-ally `scopeRangeRegex`). */
1257
+ readonly regex: string;
1258
+ } | undefined;
1259
+ readonly derivedKeys?: readonly string[] | undefined;
1260
+ readonly normalizeKey?: readonly {
1261
+ readonly replace: {
1262
+ readonly pattern: string;
1263
+ readonly with: string;
1264
+ };
1265
+ }[] | undefined;
1266
+ /** Placeholder shapes with `name` as the name: `{name}`, `{{name}}`, `%{name}`. */
1267
+ readonly placeholders?: readonly string[] | undefined;
1268
+ readonly localeInfo?: {
1269
+ readonly [code: string]: {
1270
+ readonly flag?: string | undefined;
1271
+ readonly displayName?: string | undefined;
1272
+ };
1273
+ } | undefined;
1274
+ readonly extract?: {
1275
+ readonly templates?: readonly (string | ExtractTemplate)[] | undefined;
1276
+ } | undefined;
1277
+ }
1278
+ export declare const PluginFileSchema: v.GenericSchema<PluginFile>;
1279
+ interface SchemaIssue {
1280
+ readonly path: string;
1281
+ readonly message: string;
1282
+ }
1283
+ /** Validates data against a schema and returns readable issues instead of throwing. */
1284
+ export declare function validate<T>(schema: v.GenericSchema<T>, data: unknown): {
1285
+ readonly success: true;
1286
+ readonly output: T;
1287
+ } | {
1288
+ readonly success: false;
1289
+ readonly issues: readonly SchemaIssue[];
1290
+ };
1291
+ //#endregion
1292
+ //#region src/text.d.ts
1293
+ /** One edit covering only the part that differs, so bytes outside it stay the same. */
1294
+ export declare function diffText(before: string, after: string): TextEdit[];
1295
+ /** Applies non-overlapping edits given against the same text. */
1296
+ export declare function applyTextEdits(text: string, edits: readonly TextEdit[]): string;
1297
+ interface LinePosition {
1298
+ /** Zero-based. */
1299
+ readonly line: number;
1300
+ /** Zero-based, UTF-16 code units. */
1301
+ readonly character: number;
1302
+ }
1303
+ /** Converts offsets to lines and back for one text. */
1304
+ interface LineIndex {
1305
+ readonly position: (offset: number) => LinePosition;
1306
+ readonly offset: (position: LinePosition) => number;
1307
+ readonly line: (line: number) => string;
1308
+ readonly lineCount: number;
1309
+ }
1310
+ /** Line index of a text, cached for the few texts used at a time (reporters, LSP ranges). */
1311
+ export declare function createLineIndex(text: string): LineIndex;
1312
+ export declare function rangeContains(range: TextRange, offset: number): boolean;
1313
+ /** Fast non-cryptographic string hash (cyrb53), as hex. */
1314
+ export declare function hashText(text: string): string;
1315
+ //#endregion
1316
+ export type { Analysis, Answers, ApplyResult, ArgSource, Builtins, CacheStore, CallSpec, CapabilityConflict, Check, CheckContext, CheckIds, CheckLevel, CheckSetting, ConfigContext, ConfigDraft, ConfigOrigin, CreateProjectOptions, Decision, DecisionOption, DetectContext, Diagnostic, DiagnosticInput, Disposable, EditOp, Envelope, ErrorCode, ErrorInfo, ExtractItem, ExtractOptions, ExtractTemplate, Extractor, FileChange, FileEvent, FileScan, FinderContext, Fix, Format, FormatContext, GlobOptions, GlossaryEntry, HardString, HistoryConfigs, HistoryContext, HistoryOptions, HistoryProvider, HistorySettings, Host, JsonObject, JsonPrimitive, JsonValue, KeyContext, KeyId, KeyInfo, KeyQuery, KeyString, KeyTarget, LineIndex, LinePosition, LocaleCode, LocaleCoverage, LocaleFinder, LocaleInfo, Location, Logger, ManifestReader, MemoryHost, Message, MessageChange, MessageHistory, MessageLeaf, MessageOp, MessageTree, NamespaceFromPath, NamespaceOptions, NodeRange, OverlayHost, ParseResult, Placeholder, PlaceholderComparer, PlaceholderProblem, PlaceholderSyntax, Plan, Plugin, PluginConfigs, PluginFile, PluginOption, PluginRegistry, PluginSpecifier, Preset, PresetExplanation, PresetFactory, PresetOption, Project, ProjectChange, ProjectExplanation, PromptContext, PromptData, PromptDraft, PromptItem, PromptOptions, RegexScannerSpec, ReportInput, ReportSummary, Reporter, ReporterContext, ResolveConfigOptions, ResolvedConfig, Resource, ResourceBlock, ResourceCandidate, ResourceId, ResourceNode, ResourceSpec, ResourceTransform, ResourceTransformContext, ScanContext, ScanResult, Scanner, SchemaIssue, Scope, SerializableConfig, Setup, Severity, SourceFile, TextEdit, TextRange, TreeLeaf, Usage, UsageCandidate, UsageContext, UsageKind, UsageMatch, UsageOptions, UsageQuery, UserConfig, WireDiagnostic, WireRange, WriteOptions };