locter 2.2.1 → 4.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.MD +581 -44
  2. package/dist/index.d.mts +563 -0
  3. package/dist/index.mjs +1117 -671
  4. package/dist/index.mjs.map +1 -1
  5. package/package.json +36 -40
  6. package/dist/index.cjs +0 -743
  7. package/dist/index.cjs.map +0 -1
  8. package/dist/index.d.ts +0 -3
  9. package/dist/loader/built-in/conf/index.d.ts +0 -1
  10. package/dist/loader/built-in/conf/module.d.ts +0 -6
  11. package/dist/loader/built-in/index.d.ts +0 -3
  12. package/dist/loader/built-in/json/index.d.ts +0 -1
  13. package/dist/loader/built-in/json/module.d.ts +0 -5
  14. package/dist/loader/built-in/module/index.d.ts +0 -3
  15. package/dist/loader/built-in/module/module.d.ts +0 -15
  16. package/dist/loader/built-in/module/type.d.ts +0 -8
  17. package/dist/loader/built-in/module/utils.d.ts +0 -9
  18. package/dist/loader/built-in/yaml/index.d.ts +0 -1
  19. package/dist/loader/built-in/yaml/module.d.ts +0 -5
  20. package/dist/loader/constants.d.ts +0 -6
  21. package/dist/loader/helpers.d.ts +0 -6
  22. package/dist/loader/index.d.ts +0 -3
  23. package/dist/loader/module.d.ts +0 -18
  24. package/dist/loader/singleton.d.ts +0 -2
  25. package/dist/loader/type.d.ts +0 -8
  26. package/dist/locator/async.d.ts +0 -3
  27. package/dist/locator/index.d.ts +0 -4
  28. package/dist/locator/sync.d.ts +0 -3
  29. package/dist/locator/types.d.ts +0 -15
  30. package/dist/locator/utils.d.ts +0 -7
  31. package/dist/utils/error.d.ts +0 -1
  32. package/dist/utils/file-name.d.ts +0 -2
  33. package/dist/utils/file-path.d.ts +0 -1
  34. package/dist/utils/has-property.d.ts +0 -2
  35. package/dist/utils/index.d.ts +0 -8
  36. package/dist/utils/object.d.ts +0 -2
  37. package/dist/utils/runtime.d.ts +0 -2
  38. package/dist/utils/to-array.d.ts +0 -1
  39. package/dist/utils/typescript.d.ts +0 -1
@@ -0,0 +1,563 @@
1
+ import { BaseError, ErrorOptions } from "@ebec/core";
2
+ import { createJiti } from "jiti";
3
+ import { ToStringOptions } from "yaml";
4
+ //#region src/errors/base.d.ts
5
+ type LocterErrorOptions = ErrorOptions & {
6
+ path?: string;
7
+ };
8
+ type LocterErrorInput = string | LocterErrorOptions;
9
+ declare const LOCTER_ERROR_MARKER: unique symbol;
10
+ declare class LocterError extends BaseError {
11
+ static [Symbol.hasInstance](input: unknown): boolean;
12
+ readonly path?: string;
13
+ constructor(input?: LocterErrorInput);
14
+ }
15
+ //#endregion
16
+ //#region src/errors/load.d.ts
17
+ declare const LOCTER_LOAD_ERROR_MARKER: unique symbol;
18
+ declare class LocterLoadError extends LocterError {
19
+ static [Symbol.hasInstance](input: unknown): boolean;
20
+ constructor(input?: LocterErrorInput);
21
+ }
22
+ //#endregion
23
+ //#region src/errors/not-found.d.ts
24
+ declare const LOCTER_NOT_FOUND_ERROR_MARKER: unique symbol;
25
+ declare class LocterNotFoundError extends LocterError {
26
+ static [Symbol.hasInstance](input: unknown): boolean;
27
+ constructor(input?: LocterErrorInput);
28
+ }
29
+ //#endregion
30
+ //#region src/errors/unknown-extension.d.ts
31
+ declare const LOCTER_UNKNOWN_EXTENSION_ERROR_MARKER: unique symbol;
32
+ declare class LocterUnknownExtensionError extends LocterError {
33
+ static [Symbol.hasInstance](input: unknown): boolean;
34
+ constructor(input?: LocterErrorInput);
35
+ }
36
+ //#endregion
37
+ //#region src/errors/wrap.d.ts
38
+ declare function wrapLoaderError(input: unknown, path: string): LocterError;
39
+ declare function wrapWriteError(input: unknown, path: string): LocterError;
40
+ //#endregion
41
+ //#region src/errors/write.d.ts
42
+ declare const LOCTER_WRITE_ERROR_MARKER: unique symbol;
43
+ declare class LocterWriteError extends LocterError {
44
+ static [Symbol.hasInstance](input: unknown): boolean;
45
+ constructor(input?: LocterErrorInput);
46
+ }
47
+ //#endregion
48
+ //#region src/locator/types.d.ts
49
+ type LocatorInfo = {
50
+ directory: string;
51
+ name: string;
52
+ extension?: string;
53
+ path: string;
54
+ };
55
+ type LocatorOptions = {
56
+ cwd: string[];
57
+ ignore: string[];
58
+ onlyFiles: boolean;
59
+ onlyDirectories: boolean;
60
+ dot: boolean;
61
+ };
62
+ type LocatorOptionsInput = Partial<Omit<LocatorOptions, 'cwd' | 'ignore'>> & {
63
+ cwd?: string | string[];
64
+ ignore?: string | string[];
65
+ };
66
+ //#endregion
67
+ //#region src/locator/async.d.ts
68
+ declare function locateMany(pattern: string | string[], options?: LocatorOptionsInput): Promise<LocatorInfo[]>;
69
+ declare function locate(pattern: string | string[], options?: LocatorOptionsInput): Promise<LocatorInfo | undefined>;
70
+ //#endregion
71
+ //#region src/locator/sync.d.ts
72
+ declare function locateManySync(pattern: string | string[], options?: LocatorOptionsInput): LocatorInfo[];
73
+ declare function locateSync(pattern: string | string[], options?: LocatorOptionsInput): LocatorInfo | undefined;
74
+ //#endregion
75
+ //#region src/locator/up.d.ts
76
+ type LocatorUpOptionsInput = Omit<LocatorOptionsInput, 'cwd'> & {
77
+ cwd?: string;
78
+ stopAt?: string;
79
+ };
80
+ declare function locateUp(pattern: string | string[], options?: LocatorUpOptionsInput): Promise<LocatorInfo | undefined>;
81
+ declare function locateUpSync(pattern: string | string[], options?: LocatorUpOptionsInput): LocatorInfo | undefined;
82
+ //#endregion
83
+ //#region src/locator/utils.d.ts
84
+ declare function isLocatorInfo(input: unknown): input is LocatorInfo;
85
+ declare function buildFilePath(input: LocatorInfo | string): string;
86
+ //#endregion
87
+ //#region src/utils/twin.d.ts
88
+ /**
89
+ * Internal protocol to derive the parallel sync + async public surfaces
90
+ * from one shared body. A body is a generator that yields effect pairs —
91
+ * an async and a sync thunk for the same operation — and the two drivers
92
+ * (runTwinAsync / runTwinSync) execute the side they stand for. Effect
93
+ * errors are re-entered into the body via `Generator.throw`, so try/catch
94
+ * inside a body behaves identically in both variants.
95
+ *
96
+ * Deliberately NOT exported from the utils barrel — this is internal
97
+ * plumbing, not public API.
98
+ */
99
+ type TwinOp<T = unknown> = {
100
+ async: () => Promise<T>;
101
+ sync: () => T;
102
+ };
103
+ type TwinBody<R> = Generator<TwinOp<any>, R, any>;
104
+ //#endregion
105
+ //#region src/format/type.d.ts
106
+ interface IReader {
107
+ read: (input: string) => Promise<any>;
108
+ readSync: (input: string) => any;
109
+ }
110
+ interface IWriter {
111
+ write: (path: string, value: unknown) => Promise<void>;
112
+ writeSync: (path: string, value: unknown) => void;
113
+ }
114
+ //#endregion
115
+ //#region src/format/text-file/reader.d.ts
116
+ /**
117
+ * Base class for readers of text-based file formats: reads the file as
118
+ * UTF-8, delegates to `parse`, and wraps I/O and parse errors in typed
119
+ * LocterError subclasses. Subclasses implement `parse` only — both
120
+ * `read` variants are derived from the same body.
121
+ */
122
+ declare abstract class TextFileReader implements IReader {
123
+ abstract parse(content: string): any;
124
+ read(input: string): Promise<any>;
125
+ readSync(input: string): any;
126
+ protected body(input: string): TwinBody<any>;
127
+ }
128
+ //#endregion
129
+ //#region src/format/text-file/writer.d.ts
130
+ /**
131
+ * Base class for writers of text-based file formats: serializes via
132
+ * `stringify`, creates missing parent directories, writes the file as
133
+ * UTF-8 (always terminated by a single trailing newline), and wraps
134
+ * failures in LocterWriteError. Subclasses implement `stringify` only —
135
+ * both `write` variants are derived from the same body.
136
+ */
137
+ declare abstract class TextFileWriter implements IWriter {
138
+ /**
139
+ * Opt-in: when true, the body reads the target file first (undefined
140
+ * if absent) and passes its content to `stringify` as `existing` —
141
+ * the hook behind format-preserving write-back (YAML comment
142
+ * grafting, JSON indent detection).
143
+ */
144
+ protected get usesExistingContent(): boolean;
145
+ abstract stringify(value: unknown, existing?: string): string;
146
+ write(input: string, value: unknown): Promise<void>;
147
+ writeSync(input: string, value: unknown): void;
148
+ protected body(input: string, value: unknown): TwinBody<void>;
149
+ }
150
+ //#endregion
151
+ //#region src/format/built-in/conf/reader.d.ts
152
+ declare class ConfReader extends TextFileReader {
153
+ parse(contents: string): Record<string, any>;
154
+ }
155
+ //#endregion
156
+ //#region src/format/built-in/conf/writer.d.ts
157
+ /**
158
+ * Serializes an object to `key=value` lines (the inverse of ConfReader):
159
+ * nested objects become dot-separated keys, arrays become repeated
160
+ * `key[]=` lines. Round-trips are structural, not textual — comments,
161
+ * blank lines, and line order of an existing file are not preserved,
162
+ * and a string that parses as another type (e.g. '123') reads back as
163
+ * that type.
164
+ */
165
+ declare class ConfWriter extends TextFileWriter {
166
+ stringify(value: unknown): string;
167
+ }
168
+ //#endregion
169
+ //#region src/format/built-in/json/reader.d.ts
170
+ declare class JSONReader extends TextFileReader {
171
+ parse(content: string): any;
172
+ }
173
+ //#endregion
174
+ //#region src/format/built-in/json/writer.d.ts
175
+ type JSONWriterOptions = {
176
+ /**
177
+ * Indentation of the emitted JSON. A number of spaces, a literal
178
+ * indent string, or 'auto' — detect the indentation of the existing
179
+ * target file and keep it (falls back to 4 for new files).
180
+ *
181
+ * @default 4
182
+ */
183
+ indent?: number | string | 'auto';
184
+ };
185
+ declare class JSONWriter extends TextFileWriter {
186
+ protected options: JSONWriterOptions;
187
+ constructor(options?: JSONWriterOptions);
188
+ protected get usesExistingContent(): boolean;
189
+ stringify(value: unknown, existing?: string): string;
190
+ }
191
+ //#endregion
192
+ //#region src/format/built-in/module/constants.d.ts
193
+ /**
194
+ * Single source of truth for the extensions handled by the module loader:
195
+ * consumed by BOTH the built-in routing registry and the jiti config.
196
+ */
197
+ declare const MODULE_FILE_EXTENSIONS: readonly [".js", ".mjs", ".mts", ".cjs", ".cts", ".ts"];
198
+ //#endregion
199
+ //#region src/format/built-in/module/type.d.ts
200
+ type ModuleExportFilterFn = (key: string, value: unknown) => boolean;
201
+ type ModuleExport = {
202
+ key: string;
203
+ value: any;
204
+ };
205
+ type ModuleLoadOptions = {
206
+ withFilePrefix?: boolean;
207
+ };
208
+ type ModuleLoadFn = (id: string) => unknown | Promise<unknown>;
209
+ type ModuleLoadSyncFn = (id: string) => unknown;
210
+ type ModuleReaderOptions = {
211
+ /**
212
+ * Custom asynchronous module loader. When set, this replaces the
213
+ * built-in `await import(id)` call. Useful for test runners (e.g. Vitest)
214
+ * where dynamic imports inside `node_modules/locter` would otherwise
215
+ * escape the runner's module graph — defining this in user space lets
216
+ * the runner rewrite the `import()`.
217
+ */
218
+ load?: ModuleLoadFn;
219
+ /**
220
+ * Custom synchronous module loader. When set, this replaces the built-in
221
+ * `require(id)` call.
222
+ */
223
+ loadSync?: ModuleLoadSyncFn;
224
+ };
225
+ //#endregion
226
+ //#region src/format/built-in/module/reader.d.ts
227
+ type Jiti = ReturnType<typeof createJiti>;
228
+ declare class ModuleReader implements IReader {
229
+ protected instance: Jiti;
230
+ protected loadFn?: ModuleLoadFn;
231
+ protected loadSyncFn?: ModuleLoadSyncFn;
232
+ constructor(options?: ModuleReaderOptions);
233
+ /**
234
+ * Returns the previous configuration, so callers can restore it.
235
+ */
236
+ configure(options: ModuleReaderOptions): ModuleReaderOptions;
237
+ /**
238
+ * Returns the raw module value (import / require / jiti output) —
239
+ * normalization to a module record happens once, at the
240
+ * FormatRegistry boundary.
241
+ *
242
+ * read/readSync are deliberately NOT derived from a shared body
243
+ * (unlike every other sync/async twin in this package): their
244
+ * recovery paths differ. The async variant falls back to loadSync
245
+ * under ts-node (jiti's async path does not cooperate with ts-node)
246
+ * and to the jiti instance otherwise; the sync variant only has the
247
+ * jiti fallback. The divergence is pinned by the fallback tests in
248
+ * test/unit/format/module.spec.ts.
249
+ */
250
+ read(input: string): Promise<any>;
251
+ readSync(input: string): any;
252
+ load(data: LocatorInfo | string, options?: ModuleLoadOptions): Promise<unknown>;
253
+ loadSync(data: LocatorInfo | string, options?: ModuleLoadOptions): unknown;
254
+ private build;
255
+ }
256
+ //#endregion
257
+ //#region src/format/built-in/module/utils.d.ts
258
+ /**
259
+ * True when the value is a record produced by locter's read()/toModuleRecord.
260
+ * Detection is brand-based; a plain object with an `__esModule` key is NOT
261
+ * a module record.
262
+ */
263
+ declare function isModuleRecord(input: unknown): input is Record<string, any>;
264
+ declare function getModuleExport(data: Record<string, any>, filterFn: ModuleExportFilterFn): ModuleExport | undefined;
265
+ //#endregion
266
+ //#region src/format/built-in/yaml/reader.d.ts
267
+ declare class YAMLReader extends TextFileReader {
268
+ parse(content: string): any;
269
+ }
270
+ //#endregion
271
+ //#region src/format/built-in/yaml/writer.d.ts
272
+ type YAMLWriterOptions = ToStringOptions;
273
+ /**
274
+ * Writes YAML preserving hand-edited structure where possible: when the
275
+ * target file already exists, the new value is grafted into its parsed
276
+ * document, so comments and anchors attached to surviving keys survive
277
+ * the write-back. New files are plain `yaml.stringify` output. An
278
+ * existing file that fails to parse throws (wrapped as LocterWriteError)
279
+ * instead of being silently overwritten.
280
+ */
281
+ declare class YAMLWriter extends TextFileWriter {
282
+ protected options: YAMLWriterOptions;
283
+ constructor(options?: YAMLWriterOptions);
284
+ protected get usesExistingContent(): boolean;
285
+ stringify(value: unknown, existing?: string): string;
286
+ }
287
+ //#endregion
288
+ //#region src/format/built-in/registry.d.ts
289
+ /**
290
+ * Every built-in format, in one place. Keys are the format ids; each entry
291
+ * couples routing and construction. The id union, the extension → format
292
+ * table, lazy caching, and the typed `builtInReader()` accessor are all
293
+ * DERIVED from this object. Adding a format = adding one entry.
294
+ *
295
+ * Intentionally NOT re-exported from any barrel (internal API).
296
+ */
297
+ declare const BUILT_IN_PRESETS: {
298
+ readonly module: {
299
+ readonly extensions: readonly [".js", ".mjs", ".mts", ".cjs", ".cts", ".ts"];
300
+ readonly reader: () => ModuleReader;
301
+ };
302
+ readonly conf: {
303
+ readonly extensions: readonly [".conf"];
304
+ readonly reader: () => ConfReader;
305
+ readonly writer: () => ConfWriter;
306
+ };
307
+ readonly json: {
308
+ readonly extensions: readonly [".json"];
309
+ readonly reader: () => JSONReader;
310
+ readonly writer: () => JSONWriter;
311
+ };
312
+ readonly yaml: {
313
+ readonly extensions: readonly [".yml", ".yaml"];
314
+ readonly reader: () => YAMLReader;
315
+ readonly writer: () => YAMLWriter;
316
+ };
317
+ };
318
+ type BuiltInFormatId = keyof typeof BUILT_IN_PRESETS;
319
+ type BuiltInReaderOf<K extends BuiltInFormatId> = ReturnType<(typeof BUILT_IN_PRESETS)[K]['reader']>;
320
+ /**
321
+ * Built-in format ids whose preset declares a writer — derived at the type
322
+ * level, so builtInWriter('module') is a compile error, not a runtime one.
323
+ */
324
+ type WritableBuiltInFormatId = { [K in BuiltInFormatId]: (typeof BUILT_IN_PRESETS)[K] extends {
325
+ writer: () => IWriter;
326
+ } ? K : never; }[BuiltInFormatId];
327
+ type BuiltInWriterOf<K extends WritableBuiltInFormatId> = ReturnType<(typeof BUILT_IN_PRESETS)[K]['writer']>;
328
+ //#endregion
329
+ //#region src/format/registry/type.d.ts
330
+ /**
331
+ * Lazy reader construction. Invoked on the first input that matches the
332
+ * rule it was registered for; the first successfully constructed reader
333
+ * is cached (a factory that throws is retried on the next match).
334
+ */
335
+ type ReaderFactory = () => IReader;
336
+ /**
337
+ * Lazy writer construction — same lifecycle as ReaderFactory.
338
+ */
339
+ type WriterFactory = () => IWriter;
340
+ /**
341
+ * A user-registered dispatch rule. Rules are matched in registration order,
342
+ * BEFORE the built-in extension table (i.e. user rules override built-ins).
343
+ * Rules only ever see file paths — bare module specifiers (no extension)
344
+ * are always routed to the module reader first.
345
+ *
346
+ * The reader and writer slots are independent: read dispatch only
347
+ * considers rules with a reader, write dispatch only rules with a writer.
348
+ * A reader-only rule for '.json' overrides how '.json' is read without
349
+ * shadowing the built-in JSON writer (and vice versa). At least one slot
350
+ * is required.
351
+ */
352
+ type Rule = {
353
+ /**
354
+ * Stable identity. Registering an existing id REPLACES that rule in
355
+ * place (position preserved, cached instance evicted). Built-in ids
356
+ * ('module', 'conf', 'json', 'yaml') are reserved. Omitted → auto-generated.
357
+ */
358
+ id?: string;
359
+ test: RegExp | string[];
360
+ reader?: IReader | ReaderFactory;
361
+ writer?: IWriter | WriterFactory;
362
+ };
363
+ /**
364
+ * Normalized registration record — returned by register()/entries().
365
+ */
366
+ type FormatRegistration = {
367
+ id: string;
368
+ test: RegExp | string[];
369
+ /**
370
+ * true for entries derived from the built-in registry; those cannot
371
+ * be unregistered (but can be shadowed by user rules).
372
+ */
373
+ builtIn: boolean;
374
+ };
375
+ /**
376
+ * One built-in format: routing (extensions) + instantiation (reader and
377
+ * optional writer), inseparable by construction. A preset without a
378
+ * writer is a read-only format (e.g. module).
379
+ */
380
+ type FormatPreset = {
381
+ /** Extensions (with leading dot) routed to this format. Must be disjoint across presets. */
382
+ extensions: readonly string[];
383
+ /** Lazy reader factory — invoked at most once per FormatRegistry instance. */
384
+ reader: () => IReader;
385
+ /** Lazy writer factory — invoked at most once per FormatRegistry instance. */
386
+ writer?: () => IWriter;
387
+ };
388
+ //#endregion
389
+ //#region src/format/registry/module.d.ts
390
+ type FormatRegistryOptions = {
391
+ /**
392
+ * Seed user rules (matched before built-ins, in array order).
393
+ */
394
+ rules?: Rule[];
395
+ };
396
+ /**
397
+ * A rule compiled to memoizing per-slot accessors. Caller-owned Rule
398
+ * objects are never mutated; factory caching lives in the closures.
399
+ */
400
+ type CompiledRule = {
401
+ id: string;
402
+ test: RegExp | string[];
403
+ getReader?: () => IReader;
404
+ getWriter?: () => IWriter;
405
+ };
406
+ declare class FormatRegistry {
407
+ /**
408
+ * User rules only — built-ins live in the extension table instead.
409
+ */
410
+ protected rules: CompiledRule[];
411
+ /**
412
+ * Lazy per-instance cache of built-in reader instances.
413
+ */
414
+ protected builtInReaderCache: Map<BuiltInFormatId, IReader>;
415
+ /**
416
+ * Lazy per-instance cache of built-in writer instances.
417
+ */
418
+ protected builtInWriterCache: Map<BuiltInFormatId, IWriter>;
419
+ /**
420
+ * extension → built-in format id, precomputed once from BUILT_IN_PRESETS.
421
+ */
422
+ protected builtInExtensions: Map<string, BuiltInFormatId>;
423
+ protected ruleCounter: number;
424
+ constructor(options?: FormatRegistryOptions);
425
+ register(rule: Rule): FormatRegistration;
426
+ /**
427
+ * Remove a user-registered rule by id. Built-in ids cannot be
428
+ * unregistered (returns false).
429
+ */
430
+ unregister(id: string): boolean;
431
+ has(id: string): boolean;
432
+ /**
433
+ * All registrations in effective match order: user rules
434
+ * (registration order) first, then the built-ins.
435
+ */
436
+ entries(): FormatRegistration[];
437
+ /**
438
+ * Restore the registry to its construction state: drop all user rules
439
+ * and evict every cached reader instance (including a module reader
440
+ * configured via setModuleReader / configure).
441
+ */
442
+ reset(): void;
443
+ read(input: LocatorInfo | string): Promise<any>;
444
+ readSync(input: LocatorInfo | string): any;
445
+ /**
446
+ * Shared body of read/readSync: dispatch, read, normalize, wrap.
447
+ */
448
+ protected readBody(input: LocatorInfo | string): TwinBody<any>;
449
+ write(input: LocatorInfo | string, value: unknown): Promise<void>;
450
+ writeSync(input: LocatorInfo | string, value: unknown): void;
451
+ /**
452
+ * Shared body of write/writeSync: dispatch, unwrap records, write, wrap.
453
+ * The inverse boundary of readBody: a record produced by read() (brand
454
+ * detected) is unwrapped to its `.default` value; anything else is
455
+ * written as-is.
456
+ */
457
+ protected writeBody(input: LocatorInfo | string, value: unknown): TwinBody<void>;
458
+ /**
459
+ * The single normalization boundary: every read result becomes a module
460
+ * record (`.default` is always the loaded value, top-level keys stay
461
+ * accessible as named exports). Provenance decides how: module-reader
462
+ * output may legitimately already be a record (`__esModule` is meaningful
463
+ * there); any other reader returns arbitrary parsed data, which is always
464
+ * wrapped — even if it happens to contain an `__esModule` key.
465
+ */
466
+ protected toRecord(output: unknown, reader: IReader): any;
467
+ /**
468
+ * Typed accessor for the LIVE built-in reader instance (lazy, cached).
469
+ */
470
+ builtInReader<K extends BuiltInFormatId>(id: K): BuiltInReaderOf<K>;
471
+ /**
472
+ * Typed accessor for the LIVE built-in writer instance (lazy, cached).
473
+ * Only writable format ids are accepted — read-only formats (module)
474
+ * are a compile error.
475
+ */
476
+ builtInWriter<K extends WritableBuiltInFormatId>(id: K): BuiltInWriterOf<K>;
477
+ /**
478
+ * Dispatch order:
479
+ * 1. bare specifier (no extension) → module reader, always
480
+ * 2. user rules, registration order → first match wins (can override built-ins)
481
+ * 3. built-in extension table
482
+ * 4. undefined → read/readSync throw LocterUnknownExtensionError
483
+ */
484
+ findReader(input: string): IReader | undefined;
485
+ /**
486
+ * Write-side dispatch. No bare-specifier step (there is nothing to
487
+ * write to); only rules with a writer slot participate, then built-in
488
+ * presets that declare a writer.
489
+ */
490
+ findWriter(input: string): IWriter | undefined;
491
+ protected findRule(input: string, filter: (rule: CompiledRule) => boolean): CompiledRule | undefined;
492
+ protected findBuiltInId(input: string): BuiltInFormatId | undefined;
493
+ protected unknownExtensionError(input: string): LocterUnknownExtensionError;
494
+ protected compile(id: string, rule: Rule): CompiledRule;
495
+ protected generateRuleId(): string;
496
+ }
497
+ //#endregion
498
+ //#region src/format/registry/singleton.d.ts
499
+ declare function useFormatRegistry(): FormatRegistry;
500
+ //#endregion
501
+ //#region src/format/helpers.d.ts
502
+ declare function registerFormat(rule: Rule): FormatRegistration;
503
+ /**
504
+ * Remove a rule from the process-global registry by its id
505
+ * (as returned by registerFormat). Built-in ids cannot be unregistered.
506
+ */
507
+ declare function unregisterFormat(id: string): boolean;
508
+ declare function read(input: LocatorInfo | string): Promise<any>;
509
+ declare function readSync(input: LocatorInfo | string): any;
510
+ declare function write(input: LocatorInfo | string, value: unknown): Promise<void>;
511
+ declare function writeSync(input: LocatorInfo | string, value: unknown): void;
512
+ /**
513
+ * Override the built-in module reader's `import` / `require` calls.
514
+ *
515
+ * Useful for test runners (e.g. Vitest) where the dynamic `import()` inside
516
+ * `node_modules/locter` would bypass the runner's module graph. Calling this
517
+ * from user code (e.g. a Vitest setup file) lets the runner rewrite the
518
+ * `import()` so loaded modules share identity with statically imported ones.
519
+ *
520
+ * Returns a restore function that re-applies the previous configuration —
521
+ * handy for scoped overrides (e.g. test teardown). The restore function is
522
+ * scoped to the exact reader instance it configured: after a registry
523
+ * reset() (which discards that instance) it becomes a no-op instead of
524
+ * re-applying stale configuration to the fresh instance.
525
+ *
526
+ * @example
527
+ * ```ts
528
+ * // vitest setup file
529
+ * import { setModuleReader } from 'locter';
530
+ *
531
+ * setModuleReader({
532
+ * load: (id) => import(id),
533
+ * });
534
+ * ```
535
+ */
536
+ declare function setModuleReader(options: ModuleReaderOptions): () => void;
537
+ //#endregion
538
+ //#region src/format/package-field.d.ts
539
+ type ReadPackageFieldOptions = {
540
+ cwd?: string;
541
+ walkUp?: boolean;
542
+ stopAt?: string;
543
+ };
544
+ type WritePackageFieldOptions = ReadPackageFieldOptions;
545
+ declare function readPackageField<T = unknown>(field: string, options?: ReadPackageFieldOptions): Promise<T | undefined>;
546
+ declare function readPackageFieldSync<T = unknown>(field: string, options?: ReadPackageFieldOptions): T | undefined;
547
+ /**
548
+ * Set a top-level field of the nearest `package.json` (same locate
549
+ * semantics as readPackageField) and write it back, preserving the
550
+ * file's existing indentation. Passing `undefined` removes the field.
551
+ * Throws LocterNotFoundError when no package.json could be located.
552
+ */
553
+ declare function writePackageField(field: string, value: unknown, options?: WritePackageFieldOptions): Promise<void>;
554
+ declare function writePackageFieldSync(field: string, value: unknown, options?: WritePackageFieldOptions): void;
555
+ //#endregion
556
+ //#region src/utils/runtime.d.ts
557
+ declare function isJestRuntimeEnvironment(): boolean;
558
+ declare function isVitestRuntimeEnvironment(): boolean;
559
+ declare function isTsNodeRuntimeEnvironment(): boolean;
560
+ declare function isTsxRuntimeEnvironment(): boolean;
561
+ //#endregion
562
+ export { ConfReader, ConfWriter, type FormatPreset, type FormatRegistration, FormatRegistry, type FormatRegistryOptions, type IReader, type IWriter, JSONReader, JSONWriter, type JSONWriterOptions, LOCTER_ERROR_MARKER, LOCTER_LOAD_ERROR_MARKER, LOCTER_NOT_FOUND_ERROR_MARKER, LOCTER_UNKNOWN_EXTENSION_ERROR_MARKER, LOCTER_WRITE_ERROR_MARKER, type LocatorInfo, type LocatorOptions, type LocatorOptionsInput, type LocatorUpOptionsInput, LocterError, type LocterErrorInput, type LocterErrorOptions, LocterLoadError, LocterNotFoundError, LocterUnknownExtensionError, LocterWriteError, MODULE_FILE_EXTENSIONS, type ModuleExport, type ModuleExportFilterFn, type ModuleLoadFn, type ModuleLoadOptions, type ModuleLoadSyncFn, ModuleReader, type ModuleReaderOptions, type ReadPackageFieldOptions, type ReaderFactory, type Rule, TextFileReader, TextFileWriter, type WritePackageFieldOptions, type WriterFactory, YAMLReader, YAMLWriter, type YAMLWriterOptions, buildFilePath, getModuleExport, isJestRuntimeEnvironment, isLocatorInfo, isModuleRecord, isTsNodeRuntimeEnvironment, isTsxRuntimeEnvironment, isVitestRuntimeEnvironment, locate, locateMany, locateManySync, locateSync, locateUp, locateUpSync, read, readPackageField, readPackageFieldSync, readSync, registerFormat, setModuleReader, unregisterFormat, useFormatRegistry, wrapLoaderError, wrapWriteError, write, writePackageField, writePackageFieldSync, writeSync };
563
+ //# sourceMappingURL=index.d.mts.map