pi-readseek 0.4.12 → 0.4.14

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.
@@ -8,23 +8,23 @@ import { DetailLevel } from "./readseek/enums.js";
8
8
  import type { FileMap, FileSymbol } from "./readseek/types.js";
9
9
  import { SymbolKind } from "./readseek/enums.js";
10
10
 
11
- export interface ReadseekHashline {
11
+ export interface ReadSeekHashline {
12
12
  line: number;
13
13
  hash: string;
14
14
  text: string;
15
15
  }
16
16
 
17
- export interface ReadseekReadOutput {
17
+ interface ReadSeekReadOutput {
18
18
  file: string;
19
19
  language: string;
20
20
  line_count: number;
21
21
  file_hash: string;
22
22
  start_line: number;
23
23
  end_line: number;
24
- hashlines: ReadseekHashline[];
24
+ hashlines: ReadSeekHashline[];
25
25
  }
26
26
 
27
- interface ReadseekSymbol {
27
+ interface ReadSeekSymbol {
28
28
  kind: string;
29
29
  name: string;
30
30
  qualified_name: string;
@@ -34,45 +34,45 @@ interface ReadseekSymbol {
34
34
  end_hash: string;
35
35
  }
36
36
 
37
- interface ReadseekMapOutput {
37
+ interface ReadSeekMapOutput {
38
38
  file: string;
39
39
  language: string;
40
40
  line_count: number;
41
41
  file_hash: string;
42
- symbols: ReadseekSymbol[];
42
+ symbols: ReadSeekSymbol[];
43
43
  }
44
44
 
45
- export interface ReadseekSearchCapture {
45
+ interface ReadSeekSearchCapture {
46
46
  name: string;
47
47
  start_line: number;
48
48
  end_line: number;
49
49
  start_hash: string;
50
50
  end_hash: string;
51
- hashlines: ReadseekHashline[];
51
+ hashlines: ReadSeekHashline[];
52
52
  }
53
53
 
54
- export interface ReadseekSearchMatch {
54
+ interface ReadSeekSearchMatch {
55
55
  pattern_index: number;
56
56
  start_line: number;
57
57
  end_line: number;
58
58
  start_hash: string;
59
59
  end_hash: string;
60
- hashlines: ReadseekHashline[];
61
- captures: ReadseekSearchCapture[];
60
+ hashlines: ReadSeekHashline[];
61
+ captures: ReadSeekSearchCapture[];
62
62
  }
63
63
 
64
- export interface ReadseekSearchFileOutput {
64
+ export interface ReadSeekSearchFileOutput {
65
65
  file: string;
66
66
  language: string;
67
67
  file_hash: string;
68
- matches: ReadseekSearchMatch[];
68
+ matches: ReadSeekSearchMatch[];
69
69
  }
70
70
 
71
- interface ReadseekSearchOutput {
72
- results: ReadseekSearchFileOutput[];
71
+ interface ReadSeekSearchOutput {
72
+ results: ReadSeekSearchFileOutput[];
73
73
  }
74
74
 
75
- export interface ReadseekReference {
75
+ export interface ReadSeekReference {
76
76
  file: string;
77
77
  line: number;
78
78
  column: number;
@@ -81,11 +81,11 @@ export interface ReadseekReference {
81
81
  enclosingSymbol?: string;
82
82
  }
83
83
 
84
- interface ReadseekRefsOutput {
85
- references: ReadseekReference[];
84
+ interface ReadSeekRefsOutput {
85
+ references: ReadSeekReference[];
86
86
  }
87
87
 
88
- export interface ReadseekRefsOptions {
88
+ interface ReadSeekRefsOptions {
89
89
  scope?: boolean;
90
90
  line?: number;
91
91
  column?: number;
@@ -96,19 +96,48 @@ export interface ReadseekRefsOptions {
96
96
  signal?: AbortSignal;
97
97
  }
98
98
 
99
- export interface ReadseekDiagnostic {
99
+ export interface ReadSeekDiagnostic {
100
100
  kind: "error" | "missing";
101
101
  start_line: number;
102
102
  end_line: number;
103
103
  }
104
104
 
105
- export interface ReadseekCheckOutput {
105
+ export interface ReadSeekCheckOutput {
106
106
  errorCount: number;
107
107
  missingCount: number;
108
- diagnostics: ReadseekDiagnostic[];
108
+ diagnostics: ReadSeekDiagnostic[];
109
109
  }
110
110
 
111
- export interface ReadseekSearchOptions {
111
+ export interface ReadSeekImageInfo {
112
+ format: string;
113
+ width: number;
114
+ height: number;
115
+ animated: boolean;
116
+ }
117
+
118
+ export interface ReadSeekOcrLine {
119
+ text: string;
120
+ bbox: [number, number, number, number];
121
+ }
122
+
123
+ export interface ReadSeekOcrText {
124
+ text: string;
125
+ lines: ReadSeekOcrLine[];
126
+ }
127
+
128
+ export interface ReadSeekDetection {
129
+ file: string;
130
+ language: string;
131
+ engine: string | null;
132
+ supported: boolean;
133
+ binary: boolean;
134
+ mime: string | null;
135
+ syntax: string | null;
136
+ image: ReadSeekImageInfo | null;
137
+ ocr?: ReadSeekOcrText;
138
+ }
139
+
140
+ interface ReadSeekSearchOptions {
112
141
  language?: string;
113
142
  cached?: boolean;
114
143
  others?: boolean;
@@ -131,7 +160,7 @@ function parentQualifiedNameFor(qualifiedName: string): string {
131
160
  return lastDot === -1 ? "" : qualifiedName.slice(0, lastDot);
132
161
  }
133
162
 
134
- function symbolsFromReadseek(symbols: ReadseekSymbol[]): FileSymbol[] {
163
+ function symbolsFromReadSeek(symbols: ReadSeekSymbol[]): FileSymbol[] {
135
164
  const symbolsByQualifiedName = new Map<string, FileSymbol[]>();
136
165
  const entries: Array<{ parentQualifiedName: string; symbol: FileSymbol }> = [];
137
166
 
@@ -168,13 +197,13 @@ function symbolsFromReadseek(symbols: ReadseekSymbol[]): FileSymbol[] {
168
197
 
169
198
  const require = createRequire(import.meta.url);
170
199
  const READSEEK_REPO_PACKAGE_NAMES = new Set(["@jarkkojs/readseek", "readseek"]);
171
- let defaultReadseekDirInit: Promise<string | null> | undefined;
200
+ let defaultReadSeekDirInit: Promise<string | null> | undefined;
172
201
 
173
202
  function readseekPackageDir(): string {
174
203
  return path.dirname(require.resolve("@jarkkojs/readseek/package.json"));
175
204
  }
176
205
 
177
- export function readseekBinaryPath(): string {
206
+ function readseekBinaryPath(): string {
178
207
  if (process.env.READSEEK_BIN) return process.env.READSEEK_BIN;
179
208
 
180
209
  const platformPackage = (() => {
@@ -194,7 +223,7 @@ export function readseekBinaryPath(): string {
194
223
  return path.join(path.dirname(packageJson), "bin", process.platform === "win32" ? "readseek.exe" : "readseek");
195
224
  }
196
225
 
197
- export function isReadseekAvailable(): boolean {
226
+ export function isReadSeekAvailable(): boolean {
198
227
  try {
199
228
  readseekBinaryPath();
200
229
  return true;
@@ -203,7 +232,7 @@ export function isReadseekAvailable(): boolean {
203
232
  }
204
233
  }
205
234
 
206
- export interface ReadseekFailure {
235
+ interface ReadSeekFailure {
207
236
  code: "readseek-not-installed" | "readseek-execution-error";
208
237
  message: string;
209
238
  hint?: string;
@@ -214,7 +243,7 @@ export interface ReadseekFailure {
214
243
  * taxonomy: a missing binary or package (`readseek-not-installed`, with an
215
244
  * install hint) versus any other execution error.
216
245
  */
217
- export function classifyReadseekFailure(err: unknown): ReadseekFailure {
246
+ export function classifyReadSeekFailure(err: unknown): ReadSeekFailure {
218
247
  const message = String((err as { message?: unknown } | null)?.message || err);
219
248
  const missing =
220
249
  (err as { code?: unknown } | null)?.code === "ENOENT" ||
@@ -233,7 +262,7 @@ function directoryExists(dirPath: string): boolean {
233
262
  }
234
263
  }
235
264
 
236
- function isOwnReadseekRepository(cwd = process.cwd()): boolean {
265
+ function isOwnReadSeekRepository(cwd = process.cwd()): boolean {
237
266
  let dir = path.resolve(cwd);
238
267
  while (true) {
239
268
  const packageJsonPath = path.join(dir, "package.json");
@@ -252,12 +281,12 @@ function isOwnReadseekRepository(cwd = process.cwd()): boolean {
252
281
  }
253
282
  }
254
283
 
255
- function defaultReadseekDir(): string | null {
284
+ function defaultReadSeekDir(): string | null {
256
285
  const home = homedir();
257
286
  return home ? path.join(home, ".pi", "readseek") : null;
258
287
  }
259
288
 
260
- async function spawnReadseekRaw(args: string[], options: RunReadseekOptions = {}): Promise<string> {
289
+ async function spawnReadSeekRaw(args: string[], options: RunReadSeekOptions = {}): Promise<string> {
261
290
  return new Promise<string>((resolve, reject) => {
262
291
  let settled = false;
263
292
  const fail = (error: Error): void => {
@@ -318,38 +347,38 @@ async function spawnReadseekRaw(args: string[], options: RunReadseekOptions = {}
318
347
  });
319
348
  }
320
349
 
321
- async function ensureDefaultReadseekDir(): Promise<string | null> {
322
- const dir = defaultReadseekDir();
350
+ async function ensureDefaultReadSeekDir(): Promise<string | null> {
351
+ const dir = defaultReadSeekDir();
323
352
  if (!dir) return null;
324
353
  if (directoryExists(dir)) return dir;
325
354
 
326
- defaultReadseekDirInit ??= spawnReadseekRaw(["--readseek-dir", dir, "init"])
355
+ defaultReadSeekDirInit ??= spawnReadSeekRaw(["--readseek-dir", dir, "init"])
327
356
  .then(() => (directoryExists(dir) ? dir : null))
328
357
  .catch(() => null)
329
358
  .finally(() => {
330
- defaultReadseekDirInit = undefined;
359
+ defaultReadSeekDirInit = undefined;
331
360
  });
332
- return defaultReadseekDirInit;
361
+ return defaultReadSeekDirInit;
333
362
  }
334
363
 
335
364
  async function readseekInvocationArgs(args: string[]): Promise<string[]> {
336
- if (isOwnReadseekRepository()) return args;
365
+ if (isOwnReadSeekRepository()) return args;
337
366
 
338
- const readseekDir = await ensureDefaultReadseekDir();
367
+ const readseekDir = await ensureDefaultReadSeekDir();
339
368
  return readseekDir ? ["--readseek-dir", readseekDir, ...args] : args;
340
369
  }
341
370
 
342
- interface RunReadseekOptions {
371
+ interface RunReadSeekOptions {
343
372
  signal?: AbortSignal;
344
373
  stdin?: string;
345
374
  }
346
375
 
347
- async function runReadseekRaw(args: string[], options: RunReadseekOptions = {}): Promise<string> {
348
- return spawnReadseekRaw(await readseekInvocationArgs(args), options);
376
+ async function runReadSeekRaw(args: string[], options: RunReadSeekOptions = {}): Promise<string> {
377
+ return spawnReadSeekRaw(await readseekInvocationArgs(args), options);
349
378
  }
350
379
 
351
- async function runReadseek(args: string[], options: RunReadseekOptions = {}): Promise<unknown> {
352
- const stdout = await runReadseekRaw(args, options);
380
+ async function runReadSeek(args: string[], options: RunReadSeekOptions = {}): Promise<unknown> {
381
+ const stdout = await runReadSeekRaw(args, options);
353
382
  return JSON.parse(stdout) as unknown;
354
383
  }
355
384
 
@@ -363,7 +392,12 @@ function requireString(value: unknown, field: string): string {
363
392
  return value;
364
393
  }
365
394
 
366
- function parseReadOutput(value: unknown): ReadseekReadOutput {
395
+ function requireBoolean(value: unknown, field: string): boolean {
396
+ if (typeof value !== "boolean") throw new Error(`invalid readseek ${field}: expected boolean`);
397
+ return value;
398
+ }
399
+
400
+ function parseReadOutput(value: unknown): ReadSeekReadOutput {
367
401
  if (!value || typeof value !== "object") throw new Error("invalid readseek read output");
368
402
  const output = value as Record<string, unknown>;
369
403
  const hashlines = output.hashlines;
@@ -379,7 +413,7 @@ function parseReadOutput(value: unknown): ReadseekReadOutput {
379
413
  };
380
414
  }
381
415
 
382
- function parseMapOutput(value: unknown): ReadseekMapOutput {
416
+ function parseMapOutput(value: unknown): ReadSeekMapOutput {
383
417
  if (!value || typeof value !== "object") throw new Error("invalid readseek map output");
384
418
  const output = value as Record<string, unknown>;
385
419
  const symbols = output.symbols;
@@ -405,7 +439,7 @@ function parseMapOutput(value: unknown): ReadseekMapOutput {
405
439
  };
406
440
  }
407
441
 
408
- function parseHashline(value: unknown, field: string): ReadseekHashline {
442
+ function parseHashline(value: unknown, field: string): ReadSeekHashline {
409
443
  if (!value || typeof value !== "object") throw new Error(`invalid readseek ${field}`);
410
444
  const item = value as Record<string, unknown>;
411
445
  return {
@@ -415,12 +449,12 @@ function parseHashline(value: unknown, field: string): ReadseekHashline {
415
449
  };
416
450
  }
417
451
 
418
- function parseSearchHashlines(value: unknown, field: string): ReadseekHashline[] {
452
+ function parseSearchHashlines(value: unknown, field: string): ReadSeekHashline[] {
419
453
  if (!Array.isArray(value)) throw new Error(`invalid readseek ${field}`);
420
454
  return value.map((line) => parseHashline(line, field));
421
455
  }
422
456
 
423
- function parseSearchOutput(value: unknown): ReadseekSearchOutput {
457
+ function parseSearchOutput(value: unknown): ReadSeekSearchOutput {
424
458
  if (!value || typeof value !== "object") throw new Error("invalid readseek search output");
425
459
  const output = value as Record<string, unknown>;
426
460
  if (!Array.isArray(output.results)) throw new Error("invalid readseek search results");
@@ -463,14 +497,14 @@ function parseSearchOutput(value: unknown): ReadseekSearchOutput {
463
497
  };
464
498
  }
465
499
 
466
- export async function readseekRead(filePath: string, startLine?: number, endLine?: number): Promise<ReadseekReadOutput> {
500
+ export async function readseekRead(filePath: string, startLine?: number, endLine?: number): Promise<ReadSeekReadOutput> {
467
501
  const args = ["read", filePath];
468
502
  if (startLine !== undefined) args.push("--start", String(startLine));
469
503
  if (endLine !== undefined) args.push("--end", String(endLine));
470
- return parseReadOutput(await runReadseek(args));
504
+ return parseReadOutput(await runReadSeek(args));
471
505
  }
472
506
 
473
- function fileMapFromReadseekOutput(output: ReadseekMapOutput, filePath: string, totalBytes: number): FileMap | null {
507
+ function fileMapFromReadSeekOutput(output: ReadSeekMapOutput, filePath: string, totalBytes: number): FileMap | null {
474
508
  if (output.language === "unknown" && output.symbols.length === 0) return null;
475
509
  return {
476
510
  path: filePath,
@@ -478,8 +512,7 @@ function fileMapFromReadseekOutput(output: ReadseekMapOutput, filePath: string,
478
512
  totalBytes,
479
513
  language: normalizeLanguage(output.language),
480
514
  detailLevel: DetailLevel.Full,
481
- imports: [],
482
- symbols: symbolsFromReadseek(output.symbols),
515
+ symbols: symbolsFromReadSeek(output.symbols),
483
516
  };
484
517
  }
485
518
 
@@ -488,21 +521,21 @@ export async function readseekMap(
488
521
  totalBytes: number,
489
522
  options: { signal?: AbortSignal } = {},
490
523
  ): Promise<FileMap | null> {
491
- const output = parseMapOutput(await runReadseek(["map", filePath], { signal: options.signal }));
492
- return fileMapFromReadseekOutput(output, filePath, totalBytes);
524
+ const output = parseMapOutput(await runReadSeek(["map", filePath], { signal: options.signal }));
525
+ return fileMapFromReadSeekOutput(output, filePath, totalBytes);
493
526
  }
494
527
 
495
528
  export async function readseekSearch(
496
529
  target: string,
497
530
  pattern: string,
498
- options: ReadseekSearchOptions = {},
499
- ): Promise<ReadseekSearchFileOutput[]> {
531
+ options: ReadSeekSearchOptions = {},
532
+ ): Promise<ReadSeekSearchFileOutput[]> {
500
533
  const args = ["search", target, pattern];
501
534
  if (options.language) args.push("--language", options.language);
502
535
  if (options.cached) args.push("--cached");
503
536
  if (options.others) args.push("--others");
504
537
  if (options.ignored) args.push("--ignored");
505
- return parseSearchOutput(await runReadseek(args, { signal: options.signal })).results;
538
+ return parseSearchOutput(await runReadSeek(args, { signal: options.signal })).results;
506
539
  }
507
540
 
508
541
  export async function readseekMapContent(
@@ -511,9 +544,9 @@ export async function readseekMapContent(
511
544
  options: { signal?: AbortSignal } = {},
512
545
  ): Promise<FileMap | null> {
513
546
  const output = parseMapOutput(
514
- await runReadseek(["map", "--stdin", filePath], { signal: options.signal, stdin: content }),
547
+ await runReadSeek(["map", "--stdin", filePath], { signal: options.signal, stdin: content }),
515
548
  );
516
- return fileMapFromReadseekOutput(output, filePath, Buffer.byteLength(content, "utf8"));
549
+ return fileMapFromReadSeekOutput(output, filePath, Buffer.byteLength(content, "utf8"));
517
550
  }
518
551
 
519
552
  function optionalString(value: unknown, field: string): string | undefined {
@@ -521,7 +554,12 @@ function optionalString(value: unknown, field: string): string | undefined {
521
554
  return requireString(value, field);
522
555
  }
523
556
 
524
- function parseRefsOutput(value: unknown): ReadseekRefsOutput {
557
+ function nullableString(value: unknown, field: string): string | null {
558
+ if (value === undefined || value === null) return null;
559
+ return requireString(value, field);
560
+ }
561
+
562
+ function parseRefsOutput(value: unknown): ReadSeekRefsOutput {
525
563
  if (!value || typeof value !== "object") throw new Error("invalid readseek refs output");
526
564
  const output = value as Record<string, unknown>;
527
565
  if (!Array.isArray(output.references)) throw new Error("invalid readseek references");
@@ -549,8 +587,8 @@ function parseRefsOutput(value: unknown): ReadseekRefsOutput {
549
587
  export async function readseekRefs(
550
588
  target: string,
551
589
  name: string,
552
- options: ReadseekRefsOptions = {},
553
- ): Promise<ReadseekReference[]> {
590
+ options: ReadSeekRefsOptions = {},
591
+ ): Promise<ReadSeekReference[]> {
554
592
  const args = ["refs", target, name];
555
593
  if (options.scope) args.push("--scope");
556
594
  if (options.line !== undefined) args.push("--line", String(options.line));
@@ -559,15 +597,15 @@ export async function readseekRefs(
559
597
  if (options.cached) args.push("--cached");
560
598
  if (options.others) args.push("--others");
561
599
  if (options.ignored) args.push("--ignored");
562
- return parseRefsOutput(await runReadseek(args, { signal: options.signal })).references;
600
+ return parseRefsOutput(await runReadSeek(args, { signal: options.signal })).references;
563
601
  }
564
602
 
565
- function parseDiagnosticKind(value: unknown): ReadseekDiagnostic["kind"] {
603
+ function parseDiagnosticKind(value: unknown): ReadSeekDiagnostic["kind"] {
566
604
  if (value === "error" || value === "missing") return value;
567
605
  throw new Error("invalid readseek diagnostic.kind");
568
606
  }
569
607
 
570
- function parseCheckOutput(value: unknown): ReadseekCheckOutput {
608
+ function parseCheckOutput(value: unknown): ReadSeekCheckOutput {
571
609
  if (!value || typeof value !== "object") throw new Error("invalid readseek check output");
572
610
  const output = value as Record<string, unknown>;
573
611
  if (!Array.isArray(output.diagnostics)) throw new Error("invalid readseek diagnostics");
@@ -590,8 +628,66 @@ export async function readseekCheck(
590
628
  filePath: string,
591
629
  content: string,
592
630
  options: { signal?: AbortSignal } = {},
593
- ): Promise<ReadseekCheckOutput> {
631
+ ): Promise<ReadSeekCheckOutput> {
594
632
  return parseCheckOutput(
595
- await runReadseek(["check", "--stdin", filePath], { signal: options.signal, stdin: content }),
633
+ await runReadSeek(["check", "--stdin", filePath], { signal: options.signal, stdin: content }),
596
634
  );
597
635
  }
636
+
637
+ function parseImageInfo(value: unknown): ReadSeekImageInfo | null {
638
+ if (value === undefined || value === null) return null;
639
+ if (typeof value !== "object") throw new Error("invalid readseek detect image");
640
+ const image = value as Record<string, unknown>;
641
+ return {
642
+ format: requireString(image.format, "image.format"),
643
+ width: requireNumber(image.width, "image.width"),
644
+ height: requireNumber(image.height, "image.height"),
645
+ animated: requireBoolean(image.animated, "image.animated"),
646
+ };
647
+ }
648
+
649
+ function parseOcrText(value: unknown): ReadSeekOcrText | undefined {
650
+ if (value === undefined || value === null) return undefined;
651
+ if (typeof value !== "object") throw new Error("invalid readseek detect ocr");
652
+ const ocr = value as Record<string, unknown>;
653
+ if (!Array.isArray(ocr.lines)) throw new Error("invalid readseek detect ocr.lines");
654
+ return {
655
+ text: requireString(ocr.text, "ocr.text"),
656
+ lines: ocr.lines.map((line) => {
657
+ if (!line || typeof line !== "object") throw new Error("invalid readseek detect ocr line");
658
+ const item = line as Record<string, unknown>;
659
+ const bbox = item.bbox;
660
+ if (!Array.isArray(bbox) || bbox.length !== 4) throw new Error("invalid readseek detect ocr bbox");
661
+ return {
662
+ text: requireString(item.text, "ocr.line.text"),
663
+ bbox: bbox.map((n, i) => requireNumber(n, `ocr.line.bbox[${i}]`)) as [number, number, number, number],
664
+ };
665
+ }),
666
+ };
667
+ }
668
+
669
+ function parseDetectOutput(value: unknown): ReadSeekDetection {
670
+ if (!value || typeof value !== "object") throw new Error("invalid readseek detect output");
671
+ const output = value as Record<string, unknown>;
672
+ return {
673
+ file: requireString(output.file, "file"),
674
+ language: requireString(output.language, "language"),
675
+ engine: nullableString(output.engine, "engine"),
676
+ supported: requireBoolean(output.supported, "supported"),
677
+ binary: requireBoolean(output.binary, "binary"),
678
+ mime: nullableString(output.mime, "mime"),
679
+ syntax: nullableString(output.syntax, "syntax"),
680
+ image: parseImageInfo(output.image),
681
+ ocr: parseOcrText(output.ocr),
682
+ };
683
+ }
684
+
685
+ export async function readseekDetect(
686
+ filePath: string,
687
+ options: { ocr?: boolean; signal?: AbortSignal } = {},
688
+ ): Promise<ReadSeekDetection> {
689
+ const args = ["detect"];
690
+ if (options.ocr) args.push("--ocr");
691
+ args.push(filePath);
692
+ return parseDetectOutput(await runReadSeek(args, { signal: options.signal }));
693
+ }
@@ -2,20 +2,20 @@ import { existsSync, readFileSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
3
  import { join } from "node:path";
4
4
 
5
- export interface ReadseekJsonSettings {
5
+ interface ReadSeekJsonSettings {
6
6
  grep?: { maxLines?: number; maxBytes?: number };
7
7
  edit?: { diffDisplay?: "collapsed" | "expanded" };
8
8
  }
9
9
 
10
- export interface ReadseekSettingsWarning {
10
+ interface ReadSeekSettingsWarning {
11
11
  source: string;
12
12
  message: string;
13
13
  path?: string;
14
14
  }
15
15
 
16
- export interface ReadseekSettingsResult {
17
- settings: ReadseekJsonSettings;
18
- warnings: ReadseekSettingsWarning[];
16
+ interface ReadSeekSettingsResult {
17
+ settings: ReadSeekJsonSettings;
18
+ warnings: ReadSeekSettingsWarning[];
19
19
  }
20
20
 
21
21
 
@@ -31,7 +31,7 @@ function isRecord(value: unknown): value is Record<string, unknown> {
31
31
  return typeof value === "object" && value !== null && !Array.isArray(value);
32
32
  }
33
33
 
34
- function invalid(source: string, path: string): ReadseekSettingsWarning {
34
+ function invalid(source: string, path: string): ReadSeekSettingsWarning {
35
35
  return { source, path, message: `Invalid readseek setting at ${path}` };
36
36
  }
37
37
 
@@ -40,7 +40,7 @@ function readPositive(
40
40
  key: string,
41
41
  path: string,
42
42
  source: string,
43
- warnings: ReadseekSettingsWarning[],
43
+ warnings: ReadSeekSettingsWarning[],
44
44
  ): number | undefined {
45
45
  if (!(key in raw)) return undefined;
46
46
  const val = raw[key];
@@ -50,13 +50,13 @@ function readPositive(
50
50
  }
51
51
 
52
52
 
53
- function validateSettings(raw: unknown, source: string): ReadseekSettingsResult {
54
- const settings: ReadseekJsonSettings = {};
55
- const warnings: ReadseekSettingsWarning[] = [];
53
+ function validateSettings(raw: unknown, source: string): ReadSeekSettingsResult {
54
+ const settings: ReadSeekJsonSettings = {};
55
+ const warnings: ReadSeekSettingsWarning[] = [];
56
56
  if (!isRecord(raw)) return { settings, warnings };
57
57
 
58
58
  if (isRecord(raw.grep)) {
59
- const grep: NonNullable<ReadseekJsonSettings["grep"]> = {};
59
+ const grep: NonNullable<ReadSeekJsonSettings["grep"]> = {};
60
60
  const maxLines = readPositive(raw.grep, "maxLines", "grep.maxLines", source, warnings);
61
61
  if (maxLines !== undefined) grep.maxLines = maxLines;
62
62
  const maxBytes = readPositive(raw.grep, "maxBytes", "grep.maxBytes", source, warnings);
@@ -66,7 +66,7 @@ function validateSettings(raw: unknown, source: string): ReadseekSettingsResult
66
66
 
67
67
 
68
68
  if (isRecord(raw.edit)) {
69
- const edit: NonNullable<ReadseekJsonSettings["edit"]> = {};
69
+ const edit: NonNullable<ReadSeekJsonSettings["edit"]> = {};
70
70
  if ("diffDisplay" in raw.edit) {
71
71
  const value = raw.edit.diffDisplay;
72
72
  if (value === "collapsed" || value === "expanded") edit.diffDisplay = value;
@@ -78,7 +78,7 @@ function validateSettings(raw: unknown, source: string): ReadseekSettingsResult
78
78
  return { settings, warnings };
79
79
  }
80
80
 
81
- function readSettingsFile(path: string): ReadseekSettingsResult {
81
+ function readSettingsFile(path: string): ReadSeekSettingsResult {
82
82
  if (!existsSync(path)) return { settings: {}, warnings: [] };
83
83
 
84
84
  try {
@@ -90,8 +90,8 @@ function readSettingsFile(path: string): ReadseekSettingsResult {
90
90
  }
91
91
  }
92
92
 
93
- function mergeSettings(base: ReadseekJsonSettings, override: ReadseekJsonSettings): ReadseekJsonSettings {
94
- const merged: ReadseekJsonSettings = {};
93
+ function mergeSettings(base: ReadSeekJsonSettings, override: ReadSeekJsonSettings): ReadSeekJsonSettings {
94
+ const merged: ReadSeekJsonSettings = {};
95
95
  const grep = { ...(base.grep ?? {}), ...(override.grep ?? {}) };
96
96
  if (Object.keys(grep).length > 0) merged.grep = grep;
97
97
  const edit = { ...(base.edit ?? {}), ...(override.edit ?? {}) };
@@ -99,7 +99,7 @@ function mergeSettings(base: ReadseekJsonSettings, override: ReadseekJsonSetting
99
99
  return merged;
100
100
  }
101
101
 
102
- export function resolveReadseekJsonSettings(): ReadseekSettingsResult {
102
+ export function resolveReadSeekJsonSettings(): ReadSeekSettingsResult {
103
103
  const globalResult = readSettingsFile(defaultGlobalSettingsPath());
104
104
  const projectResult = readSettingsFile(defaultProjectSettingsPath());
105
105
  return {
@@ -114,7 +114,7 @@ export function resolveEditDiffDisplay(env: NodeJS.ProcessEnv = process.env): "c
114
114
  const normalized = raw.trim().toLowerCase();
115
115
  if (normalized === "expanded" || normalized === "collapsed") return normalized;
116
116
  }
117
- const json = resolveReadseekJsonSettings().settings.edit?.diffDisplay;
117
+ const json = resolveReadSeekJsonSettings().settings.edit?.diffDisplay;
118
118
  if (json === "expanded" || json === "collapsed") return json;
119
119
  return "collapsed";
120
120
  }