locter 3.0.0 → 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.
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { BaseError, ErrorOptions } from "@ebec/core";
2
2
  import { createJiti } from "jiti";
3
-
3
+ import { ToStringOptions } from "yaml";
4
4
  //#region src/errors/base.d.ts
5
5
  type LocterErrorOptions = ErrorOptions & {
6
6
  path?: string;
@@ -36,28 +36,13 @@ declare class LocterUnknownExtensionError extends LocterError {
36
36
  //#endregion
37
37
  //#region src/errors/wrap.d.ts
38
38
  declare function wrapLoaderError(input: unknown, path: string): LocterError;
39
+ declare function wrapWriteError(input: unknown, path: string): LocterError;
39
40
  //#endregion
40
- //#region src/loader/type.d.ts
41
- type Loader = {
42
- execute: (input: string) => Promise<any>;
43
- executeSync: (input: string) => any;
44
- };
45
- type Rule = {
46
- test: RegExp | string[];
47
- loader: Loader | string;
48
- };
49
- //#endregion
50
- //#region src/loader/built-in/conf/module.d.ts
51
- declare class ConfLoader implements Loader {
52
- execute(input: string): Promise<Record<string, any>>;
53
- executeSync(input: string): Record<string, any>;
54
- parse(contents: string): Record<string, any>;
55
- }
56
- //#endregion
57
- //#region src/loader/built-in/json/module.d.ts
58
- declare class JSONLoader implements Loader {
59
- execute(input: string): Promise<any>;
60
- executeSync(input: string): any;
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);
61
46
  }
62
47
  //#endregion
63
48
  //#region src/locator/types.d.ts
@@ -96,15 +81,123 @@ declare function locateUp(pattern: string | string[], options?: LocatorUpOptions
96
81
  declare function locateUpSync(pattern: string | string[], options?: LocatorUpOptionsInput): LocatorInfo | undefined;
97
82
  //#endregion
98
83
  //#region src/locator/utils.d.ts
99
- declare function buildLocatorPatterns(pattern: string | string[]): string[];
100
- declare function buildLocatorOptions(options?: LocatorOptionsInput): LocatorOptions;
101
- declare function pathToLocatorInfo(input: string, skipResolve?: boolean): LocatorInfo;
102
84
  declare function isLocatorInfo(input: unknown): input is LocatorInfo;
103
85
  declare function buildFilePath(input: LocatorInfo | string): string;
104
- declare function buildFilePathWithoutExtension(input: LocatorInfo | string): string;
105
86
  //#endregion
106
- //#region src/loader/built-in/module/type.d.ts
107
- type LoaderFilterFn = (key: string, value: unknown) => boolean;
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;
108
201
  type ModuleExport = {
109
202
  key: string;
110
203
  value: any;
@@ -114,7 +207,7 @@ type ModuleLoadOptions = {
114
207
  };
115
208
  type ModuleLoadFn = (id: string) => unknown | Promise<unknown>;
116
209
  type ModuleLoadSyncFn = (id: string) => unknown;
117
- type ModuleLoaderOptions = {
210
+ type ModuleReaderOptions = {
118
211
  /**
119
212
  * Custom asynchronous module loader. When set, this replaces the
120
213
  * built-in `await import(id)` call. Useful for test runners (e.g. Vitest)
@@ -130,115 +223,341 @@ type ModuleLoaderOptions = {
130
223
  loadSync?: ModuleLoadSyncFn;
131
224
  };
132
225
  //#endregion
133
- //#region src/loader/built-in/module/module.d.ts
226
+ //#region src/format/built-in/module/reader.d.ts
134
227
  type Jiti = ReturnType<typeof createJiti>;
135
- declare class ModuleLoader implements Loader {
228
+ declare class ModuleReader implements IReader {
136
229
  protected instance: Jiti;
137
230
  protected loadFn?: ModuleLoadFn;
138
231
  protected loadSyncFn?: ModuleLoadSyncFn;
139
- constructor(options?: ModuleLoaderOptions);
140
- configure(options: ModuleLoaderOptions): void;
141
- execute(input: string): Promise<any>;
142
- executeSync(input: string): any;
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;
143
252
  load(data: LocatorInfo | string, options?: ModuleLoadOptions): Promise<unknown>;
144
253
  loadSync(data: LocatorInfo | string, options?: ModuleLoadOptions): unknown;
145
254
  private build;
146
255
  }
147
256
  //#endregion
148
- //#region src/loader/built-in/module/utils.d.ts
149
- type ESModule = {
150
- [key: string]: any;
151
- __esModule: boolean;
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;
152
387
  };
153
- declare function isESModule(input: unknown): input is ESModule;
154
- declare function toModuleRecord(data: unknown): any;
155
- declare function getModuleExport(data: Record<string, any>, filterFn: LoaderFilterFn): ModuleExport | undefined;
156
388
  //#endregion
157
- //#region src/loader/built-in/yaml/module.d.ts
158
- declare class YAMLLoader implements Loader {
159
- execute(input: string): Promise<any>;
160
- executeSync(input: string): any;
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;
161
496
  }
162
497
  //#endregion
163
- //#region src/loader/helpers.d.ts
164
- declare function registerLoader(rule: Rule): void;
165
- declare function registerLoader(test: string[] | RegExp, loader: Loader): void;
166
- declare function load(input: LocatorInfo | string): Promise<any>;
167
- declare function loadSync(input: LocatorInfo | string): any;
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;
168
512
  /**
169
- * Override the built-in module loader's `import` / `require` calls.
513
+ * Override the built-in module reader's `import` / `require` calls.
170
514
  *
171
515
  * Useful for test runners (e.g. Vitest) where the dynamic `import()` inside
172
516
  * `node_modules/locter` would bypass the runner's module graph. Calling this
173
517
  * from user code (e.g. a Vitest setup file) lets the runner rewrite the
174
518
  * `import()` so loaded modules share identity with statically imported ones.
175
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
+ *
176
526
  * @example
177
527
  * ```ts
178
528
  * // vitest setup file
179
- * import { setModuleLoader } from 'locter';
529
+ * import { setModuleReader } from 'locter';
180
530
  *
181
- * setModuleLoader({
531
+ * setModuleReader({
182
532
  * load: (id) => import(id),
183
533
  * });
184
534
  * ```
185
535
  */
186
- declare function setModuleLoader(options: ModuleLoaderOptions): void;
187
- //#endregion
188
- //#region src/loader/module.d.ts
189
- declare class LoaderManager implements Loader {
190
- protected loaders: Record<string, Loader>;
191
- protected rules: Rule[];
192
- constructor();
193
- register(rule: Rule): void;
194
- register(test: string[] | RegExp, loader: Loader): void;
195
- execute(input: string): Promise<any>;
196
- executeSync(input: string): any;
197
- protected unknownExtensionError(input: string): LocterUnknownExtensionError;
198
- findLoader(input: string): Loader | string | undefined;
199
- /**
200
- * Resolve loader by id.
201
- *
202
- * @param id
203
- */
204
- resolve(id: string | Loader): Loader;
205
- normalizePath(input: string): string;
206
- }
536
+ declare function setModuleReader(options: ModuleReaderOptions): () => void;
207
537
  //#endregion
208
- //#region src/loader/package-field.d.ts
209
- type LoadPackageFieldOptions = {
538
+ //#region src/format/package-field.d.ts
539
+ type ReadPackageFieldOptions = {
210
540
  cwd?: string;
211
541
  walkUp?: boolean;
212
542
  stopAt?: string;
213
543
  };
214
- declare function loadPackageField<T = unknown>(field: string, options?: LoadPackageFieldOptions): Promise<T | undefined>;
215
- declare function loadPackageFieldSync<T = unknown>(field: string, options?: LoadPackageFieldOptions): T | undefined;
216
- //#endregion
217
- //#region src/utils/file-name.d.ts
218
- declare function getFileNameExtension(input: string, allowed?: string[]): string | undefined;
219
- declare function removeFileNameExtension(input: string, extensions?: string[]): string;
220
- //#endregion
221
- //#region src/utils/has-property.d.ts
222
- declare function hasOwnProperty<X extends Record<string, any>, Y extends PropertyKey>(obj: X, prop: Y): obj is X & Record<Y, unknown>;
223
- declare function hasStringProperty<X extends Record<string, any>, Y extends PropertyKey>(obj: X, prop: Y): obj is X & Record<Y, string>;
224
- //#endregion
225
- //#region src/utils/object.d.ts
226
- declare function isObject(item: unknown): item is Record<string, any>;
227
- declare function isSafeObjectKey(key: string): boolean;
228
- //#endregion
229
- //#region src/utils/to-array.d.ts
230
- declare function toArray(input: string | string[]): string[];
231
- //#endregion
232
- //#region src/utils/file-path.d.ts
233
- declare function isFilePath(input: string): boolean | "";
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;
234
555
  //#endregion
235
556
  //#region src/utils/runtime.d.ts
236
557
  declare function isJestRuntimeEnvironment(): boolean;
237
558
  declare function isVitestRuntimeEnvironment(): boolean;
238
559
  declare function isTsNodeRuntimeEnvironment(): boolean;
560
+ declare function isTsxRuntimeEnvironment(): boolean;
239
561
  //#endregion
240
- //#region src/utils/typescript.d.ts
241
- declare function isTypeScriptError(input: unknown): input is Error;
242
- //#endregion
243
- export { ConfLoader, JSONLoader, LOCTER_ERROR_MARKER, LOCTER_LOAD_ERROR_MARKER, LOCTER_NOT_FOUND_ERROR_MARKER, LOCTER_UNKNOWN_EXTENSION_ERROR_MARKER, LoadPackageFieldOptions, LoaderFilterFn, LoaderManager, LocatorInfo, LocatorOptions, LocatorOptionsInput, LocatorUpOptionsInput, LocterError, LocterErrorInput, LocterErrorOptions, LocterLoadError, LocterNotFoundError, LocterUnknownExtensionError, ModuleExport, ModuleLoadFn, ModuleLoadOptions, ModuleLoadSyncFn, ModuleLoader, ModuleLoaderOptions, YAMLLoader, buildFilePath, buildFilePathWithoutExtension, buildLocatorOptions, buildLocatorPatterns, getFileNameExtension, getModuleExport, hasOwnProperty, hasStringProperty, isESModule, isFilePath, isJestRuntimeEnvironment, isLocatorInfo, isObject, isSafeObjectKey, isTsNodeRuntimeEnvironment, isTypeScriptError, isVitestRuntimeEnvironment, load, loadPackageField, loadPackageFieldSync, loadSync, locate, locateMany, locateManySync, locateSync, locateUp, locateUpSync, pathToLocatorInfo, registerLoader, removeFileNameExtension, setModuleLoader, toArray, toModuleRecord, wrapLoaderError };
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 };
244
563
  //# sourceMappingURL=index.d.mts.map