patram 0.9.0 → 0.11.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 (33) hide show
  1. package/lib/cli/arguments.types.d.ts +64 -0
  2. package/lib/cli/commands/check.js +27 -15
  3. package/lib/cli/commands/queries.js +189 -1
  4. package/lib/cli/commands/query.js +6 -3
  5. package/lib/cli/help-metadata.js +45 -110
  6. package/lib/cli/parse-arguments-helpers.js +295 -39
  7. package/lib/cli/render-help.js +87 -0
  8. package/lib/config/load-patram-config.d.ts +11 -0
  9. package/lib/config/load-patram-config.js +9 -88
  10. package/lib/config/manage-stored-queries-helpers.d.ts +69 -0
  11. package/lib/config/manage-stored-queries-helpers.js +262 -0
  12. package/lib/config/manage-stored-queries-jsonc.d.ts +31 -0
  13. package/lib/config/manage-stored-queries-jsonc.js +95 -0
  14. package/lib/config/manage-stored-queries.d.ts +77 -0
  15. package/lib/config/manage-stored-queries.js +294 -0
  16. package/lib/config/schema.d.ts +2 -0
  17. package/lib/config/schema.js +4 -0
  18. package/lib/config/validate-patram-config-value.d.ts +13 -0
  19. package/lib/config/validate-patram-config-value.js +119 -0
  20. package/lib/find-close-match.d.ts +8 -0
  21. package/lib/find-close-match.js +98 -0
  22. package/lib/graph/query/resolve.d.ts +9 -5
  23. package/lib/graph/query/resolve.js +41 -4
  24. package/lib/output/layout-stored-queries.js +18 -2
  25. package/lib/output/list-queries.js +2 -1
  26. package/lib/output/renderers/json.js +9 -5
  27. package/lib/output/renderers/plain.js +15 -26
  28. package/lib/output/renderers/rich.js +22 -26
  29. package/lib/output/resolve-check-target.js +120 -11
  30. package/lib/output/view-model/index.js +5 -18
  31. package/lib/patram.d.ts +8 -0
  32. package/lib/scan/discover-fields.js +136 -10
  33. package/package.json +2 -1
@@ -5,7 +5,7 @@
5
5
  * @typedef {import('./arguments.types.ts').CliParseError} CliParseError
6
6
  * @typedef {import('./arguments.types.ts').ParsedCliHelpRequest} ParsedCliHelpRequest
7
7
  * @typedef {{ kind: string, name?: string, rawName?: string, value?: string | boolean }} CliOptionToken
8
- * @typedef {{ color?: string, explain?: boolean, help?: boolean, json?: boolean, limit?: string, lint?: boolean, 'no-color'?: boolean, offset?: string, plain?: boolean, where?: string }} CliOptionValues
8
+ * @typedef {{ color?: string, desc?: string, explain?: boolean, help?: boolean, json?: boolean, limit?: string, lint?: boolean, name?: string, 'no-color'?: boolean, offset?: string, plain?: boolean, query?: string, where?: string }} CliOptionValues
9
9
  * @typedef {{ option_tokens: CliOptionToken[], positionals: string[], values: CliOptionValues }} ParsedCommandLine
10
10
  */
11
11
 
@@ -23,14 +23,17 @@ import { findInvalidQueryPagination } from './query-pagination.js';
23
23
 
24
24
  export const CLI_OPTIONS = /** @type {const} */ ({
25
25
  color: { type: 'string' },
26
+ desc: { type: 'string' },
26
27
  explain: { type: 'boolean' },
27
28
  help: { type: 'boolean' },
28
29
  json: { type: 'boolean' },
29
30
  limit: { type: 'string' },
30
31
  lint: { type: 'boolean' },
32
+ name: { type: 'string' },
31
33
  'no-color': { type: 'boolean' },
32
34
  offset: { type: 'string' },
33
35
  plain: { type: 'boolean' },
36
+ query: { type: 'string' },
34
37
  where: { type: 'string' },
35
38
  });
36
39
 
@@ -67,9 +70,7 @@ export function validateHelpCommandLine(command_line) {
67
70
  }
68
71
 
69
72
  if (command_line.positionals.length > 2) {
70
- return createMessageParseError(
71
- 'Help accepts at most one topic or command.',
72
- );
73
+ return createUnexpectedArgumentError('help', command_line.positionals[2]);
73
74
  }
74
75
 
75
76
  return null;
@@ -125,6 +126,11 @@ export function validateParsedCommand(command_name, command_line) {
125
126
  command_line.values,
126
127
  command_positionals,
127
128
  ) ??
129
+ findInvalidQueriesMutation(
130
+ command_name,
131
+ command_line.values,
132
+ command_positionals,
133
+ ) ??
128
134
  validateCommandPositionals(command_name, command_positionals)
129
135
  );
130
136
  }
@@ -164,6 +170,25 @@ export function buildCommandArguments(
164
170
  return [command_positionals[0], '--where', parsed_values.where];
165
171
  }
166
172
 
173
+ if (command_name === 'queries') {
174
+ /** @type {string[]} */
175
+ const command_arguments = [...command_positionals];
176
+
177
+ if (parsed_values.name !== undefined) {
178
+ command_arguments.push('--name', parsed_values.name);
179
+ }
180
+
181
+ if (parsed_values.query !== undefined) {
182
+ command_arguments.push('--query', parsed_values.query);
183
+ }
184
+
185
+ if (parsed_values.desc !== undefined) {
186
+ command_arguments.push('--desc', parsed_values.desc);
187
+ }
188
+
189
+ return command_arguments;
190
+ }
191
+
167
192
  return command_positionals;
168
193
  }
169
194
 
@@ -307,24 +332,10 @@ function findInvalidCommandOption(command_name, option_tokens) {
307
332
  */
308
333
  function findMissingOptionValue(option_tokens) {
309
334
  for (const token of option_tokens) {
310
- if (token.name === 'where' && typeof token.value !== 'string') {
311
- return {
312
- argument_label: "<name> or --where '<clause>'",
313
- code: 'missing_required_argument',
314
- command_name: 'query',
315
- };
316
- }
317
-
318
- if (token.name === 'offset' && typeof token.value !== 'string') {
319
- return createMessageParseError('Offset requires a value.');
320
- }
321
-
322
- if (token.name === 'limit' && typeof token.value !== 'string') {
323
- return createMessageParseError('Limit requires a value.');
324
- }
335
+ const missing_value_error = findMissingOptionValueError(token);
325
336
 
326
- if (token.name === 'color' && typeof token.value !== 'string') {
327
- return createMessageParseError('Color requires a value.');
337
+ if (missing_value_error) {
338
+ return missing_value_error;
328
339
  }
329
340
  }
330
341
 
@@ -388,6 +399,42 @@ function findInvalidQueryInspection(command_name, parsed_values) {
388
399
  return null;
389
400
  }
390
401
 
402
+ /**
403
+ * @param {CliCommandName} command_name
404
+ * @param {CliOptionValues} parsed_values
405
+ * @param {string[]} command_positionals
406
+ * @returns {CliParseError | null}
407
+ */
408
+ function findInvalidQueriesMutation(
409
+ command_name,
410
+ parsed_values,
411
+ command_positionals,
412
+ ) {
413
+ if (command_name !== 'queries' || command_positionals.length === 0) {
414
+ return null;
415
+ }
416
+
417
+ const subcommand_name = command_positionals[0];
418
+
419
+ if (
420
+ subcommand_name !== 'add' &&
421
+ subcommand_name !== 'remove' &&
422
+ subcommand_name !== 'update'
423
+ ) {
424
+ return createUnexpectedArgumentError('queries', subcommand_name);
425
+ }
426
+
427
+ if (subcommand_name === 'add') {
428
+ return validateQueriesAddMutation(parsed_values, command_positionals);
429
+ }
430
+
431
+ if (subcommand_name === 'remove') {
432
+ return validateQueriesRemoveMutation(parsed_values, command_positionals);
433
+ }
434
+
435
+ return validateQueriesUpdateMutation(parsed_values, command_positionals);
436
+ }
437
+
391
438
  /**
392
439
  * @param {CliCommandName} command_name
393
440
  * @param {string[]} command_positionals
@@ -396,24 +443,18 @@ function findInvalidQueryInspection(command_name, parsed_values) {
396
443
  function validateCommandPositionals(command_name, command_positionals) {
397
444
  const command_definition = getCommandDefinition(command_name);
398
445
 
446
+ if (allowsQueriesMutationPositionals(command_name, command_positionals)) {
447
+ return null;
448
+ }
449
+
399
450
  if (command_positionals.length < command_definition.min_positionals) {
400
- if (command_name === 'query' && command_definition.missing_argument_label) {
401
- return {
402
- argument_label: command_definition.missing_argument_label,
403
- code: 'missing_required_argument',
404
- command_name: 'query',
405
- };
406
- }
451
+ const missing_argument_error = createMissingArgumentError(
452
+ command_name,
453
+ command_definition.missing_argument_label,
454
+ );
407
455
 
408
- if (
409
- (command_name === 'refs' || command_name === 'show') &&
410
- command_definition.missing_argument_label
411
- ) {
412
- return {
413
- argument_label: command_definition.missing_argument_label,
414
- code: 'missing_required_argument',
415
- command_name,
416
- };
456
+ if (missing_argument_error) {
457
+ return missing_argument_error;
417
458
  }
418
459
 
419
460
  return createMessageParseError(
@@ -422,8 +463,9 @@ function validateCommandPositionals(command_name, command_positionals) {
422
463
  }
423
464
 
424
465
  if (command_positionals.length > command_definition.max_positionals) {
425
- return createMessageParseError(
426
- command_definition.extra_positionals_message,
466
+ return createUnexpectedArgumentError(
467
+ command_name,
468
+ command_positionals[command_definition.max_positionals],
427
469
  );
428
470
  }
429
471
 
@@ -444,10 +486,224 @@ function validateCommandPositionals(command_name, command_positionals) {
444
486
  */
445
487
  function isKnownCommandOptionName(option_name) {
446
488
  return (
489
+ option_name === 'desc' ||
447
490
  option_name === 'explain' ||
448
491
  option_name === 'limit' ||
449
492
  option_name === 'lint' ||
493
+ option_name === 'name' ||
450
494
  option_name === 'offset' ||
495
+ option_name === 'query' ||
451
496
  option_name === 'where'
452
497
  );
453
498
  }
499
+
500
+ /**
501
+ * @param {CliOptionToken} option_token
502
+ * @returns {CliParseError | null}
503
+ */
504
+ function findMissingOptionValueError(option_token) {
505
+ if (typeof option_token.value === 'string') {
506
+ return null;
507
+ }
508
+
509
+ if (option_token.name === 'where') {
510
+ return {
511
+ argument_label: "<name> or --where '<clause>'",
512
+ code: 'missing_required_argument',
513
+ command_name: 'query',
514
+ };
515
+ }
516
+
517
+ const message = getMissingOptionValueMessage(option_token.name);
518
+
519
+ if (!message) {
520
+ return null;
521
+ }
522
+
523
+ return createMessageParseError(message);
524
+ }
525
+
526
+ /**
527
+ * @param {string | undefined} option_name
528
+ * @returns {string | null}
529
+ */
530
+ function getMissingOptionValueMessage(option_name) {
531
+ /** @type {Record<string, string>} */
532
+ const option_messages = {
533
+ color: 'Color requires a value.',
534
+ desc: 'Desc requires a value.',
535
+ limit: 'Limit requires a value.',
536
+ name: 'Name requires a value.',
537
+ offset: 'Offset requires a value.',
538
+ query: 'Query requires a value.',
539
+ };
540
+
541
+ if (!option_name || !Object.hasOwn(option_messages, option_name)) {
542
+ return null;
543
+ }
544
+
545
+ return option_messages[option_name];
546
+ }
547
+
548
+ /**
549
+ * @param {CliOptionValues} parsed_values
550
+ * @param {string[]} command_positionals
551
+ * @returns {CliParseError | null}
552
+ */
553
+ function validateQueriesAddMutation(parsed_values, command_positionals) {
554
+ const positional_error = validateQueriesMutationPositionals(
555
+ command_positionals,
556
+ 'Queries add requires a stored query name.',
557
+ );
558
+
559
+ if (positional_error) {
560
+ return positional_error;
561
+ }
562
+
563
+ if (parsed_values.name !== undefined) {
564
+ return createMessageParseError('Queries add does not accept "--name".');
565
+ }
566
+
567
+ if (parsed_values.query === undefined) {
568
+ return createMessageParseError('Queries add requires "--query <clause>".');
569
+ }
570
+
571
+ return null;
572
+ }
573
+
574
+ /**
575
+ * @param {CliOptionValues} parsed_values
576
+ * @param {string[]} command_positionals
577
+ * @returns {CliParseError | null}
578
+ */
579
+ function validateQueriesRemoveMutation(parsed_values, command_positionals) {
580
+ const positional_error = validateQueriesMutationPositionals(
581
+ command_positionals,
582
+ 'Queries remove requires a stored query name.',
583
+ );
584
+
585
+ if (positional_error) {
586
+ return positional_error;
587
+ }
588
+
589
+ if (
590
+ parsed_values.desc !== undefined ||
591
+ parsed_values.name !== undefined ||
592
+ parsed_values.query !== undefined
593
+ ) {
594
+ return createMessageParseError(
595
+ 'Queries remove does not accept mutation options.',
596
+ );
597
+ }
598
+
599
+ return null;
600
+ }
601
+
602
+ /**
603
+ * @param {CliOptionValues} parsed_values
604
+ * @param {string[]} command_positionals
605
+ * @returns {CliParseError | null}
606
+ */
607
+ function validateQueriesUpdateMutation(parsed_values, command_positionals) {
608
+ const positional_error = validateQueriesMutationPositionals(
609
+ command_positionals,
610
+ 'Queries update requires a stored query name.',
611
+ );
612
+
613
+ if (positional_error) {
614
+ return positional_error;
615
+ }
616
+
617
+ if (
618
+ parsed_values.desc === undefined &&
619
+ parsed_values.name === undefined &&
620
+ parsed_values.query === undefined
621
+ ) {
622
+ return createMessageParseError(
623
+ 'Queries update requires at least one of "--name", "--query", or "--desc".',
624
+ );
625
+ }
626
+
627
+ return null;
628
+ }
629
+
630
+ /**
631
+ * @param {string[]} command_positionals
632
+ * @param {string} missing_name_message
633
+ * @returns {CliParseError | null}
634
+ */
635
+ function validateQueriesMutationPositionals(
636
+ command_positionals,
637
+ missing_name_message,
638
+ ) {
639
+ if (command_positionals.length < 2) {
640
+ return createMessageParseError(missing_name_message);
641
+ }
642
+
643
+ if (command_positionals.length > 2) {
644
+ return createUnexpectedArgumentError('queries', command_positionals[2]);
645
+ }
646
+
647
+ return null;
648
+ }
649
+
650
+ /**
651
+ * @param {CliCommandName} command_name
652
+ * @param {string[]} command_positionals
653
+ * @returns {boolean}
654
+ */
655
+ function allowsQueriesMutationPositionals(command_name, command_positionals) {
656
+ if (command_name !== 'queries' || command_positionals.length === 0) {
657
+ return false;
658
+ }
659
+
660
+ const subcommand_name = command_positionals[0];
661
+
662
+ return (
663
+ subcommand_name === 'add' ||
664
+ subcommand_name === 'remove' ||
665
+ subcommand_name === 'update'
666
+ );
667
+ }
668
+
669
+ /**
670
+ * @param {CliCommandName} command_name
671
+ * @param {string | null} missing_argument_label
672
+ * @returns {CliParseError | null}
673
+ */
674
+ function createMissingArgumentError(command_name, missing_argument_label) {
675
+ if (!missing_argument_label) {
676
+ return null;
677
+ }
678
+
679
+ if (command_name === 'query') {
680
+ return {
681
+ argument_label: missing_argument_label,
682
+ code: 'missing_required_argument',
683
+ command_name: 'query',
684
+ };
685
+ }
686
+
687
+ if (command_name === 'refs' || command_name === 'show') {
688
+ return {
689
+ argument_label: missing_argument_label,
690
+ code: 'missing_required_argument',
691
+ command_name,
692
+ };
693
+ }
694
+
695
+ return null;
696
+ }
697
+
698
+ /**
699
+ * @param {'help' | CliCommandName} command_name
700
+ * @param {string | undefined} token
701
+ * @returns {CliParseError}
702
+ */
703
+ function createUnexpectedArgumentError(command_name, token) {
704
+ return {
705
+ code: 'unexpected_argument',
706
+ command_name,
707
+ token: token ?? '',
708
+ };
709
+ }
@@ -75,6 +75,21 @@ export function renderCliParseError(parse_error) {
75
75
  );
76
76
  }
77
77
 
78
+ if (parse_error.code === 'unexpected_argument') {
79
+ return renderUnexpectedArgumentError(
80
+ parse_error.command_name,
81
+ parse_error.token,
82
+ );
83
+ }
84
+
85
+ if (parse_error.code === 'unknown_stored_query') {
86
+ return renderUnknownStoredQueryError(
87
+ parse_error.name,
88
+ parse_error.next_path,
89
+ parse_error.suggestion,
90
+ );
91
+ }
92
+
78
93
  return `${parse_error.message}\n`;
79
94
  }
80
95
 
@@ -326,6 +341,54 @@ function renderMissingRequiredArgumentError(command_name, argument_label) {
326
341
  ]);
327
342
  }
328
343
 
344
+ /**
345
+ * @param {'help' | CliCommandName} command_name
346
+ * @param {string} invalid_token
347
+ * @returns {string}
348
+ */
349
+ function renderUnexpectedArgumentError(command_name, invalid_token) {
350
+ return joinOutputLines([
351
+ `Unexpected argument: ${invalid_token}`,
352
+ '',
353
+ 'Usage:',
354
+ ...indentLines(getUnexpectedArgumentUsageLines(command_name)),
355
+ '',
356
+ 'Next:',
357
+ ` ${renderUnexpectedArgumentNext(command_name)}`,
358
+ ]);
359
+ }
360
+
361
+ /**
362
+ * @param {string} stored_query_name
363
+ * @param {string | undefined} next_path
364
+ * @param {string | undefined} suggestion
365
+ * @returns {string}
366
+ */
367
+ function renderUnknownStoredQueryError(
368
+ stored_query_name,
369
+ next_path,
370
+ suggestion,
371
+ ) {
372
+ if (suggestion) {
373
+ return joinOutputLines([
374
+ `Unknown stored query: ${stored_query_name}`,
375
+ '',
376
+ 'Did you mean:',
377
+ ` ${suggestion}`,
378
+ '',
379
+ 'Next:',
380
+ ` ${next_path ?? `patram query ${suggestion}`}`,
381
+ ]);
382
+ }
383
+
384
+ return joinOutputLines([
385
+ `Unknown stored query: ${stored_query_name}`,
386
+ '',
387
+ 'Next:',
388
+ ' patram queries',
389
+ ]);
390
+ }
391
+
329
392
  /**
330
393
  * @param {string} invalid_token
331
394
  * @param {CliCommandName | CliHelpTopicName | undefined} suggestion
@@ -378,6 +441,30 @@ function renderCommandHelpPath(command_name) {
378
441
  return `patram help ${command_name}`;
379
442
  }
380
443
 
444
+ /**
445
+ * @param {'help' | CliCommandName} command_name
446
+ * @returns {string}
447
+ */
448
+ function renderUnexpectedArgumentNext(command_name) {
449
+ if (command_name === 'help') {
450
+ return 'patram --help';
451
+ }
452
+
453
+ return renderCommandHelpPath(command_name);
454
+ }
455
+
456
+ /**
457
+ * @param {'help' | CliCommandName} command_name
458
+ * @returns {string[]}
459
+ */
460
+ function getUnexpectedArgumentUsageLines(command_name) {
461
+ if (command_name === 'help') {
462
+ return ['patram help [command]'];
463
+ }
464
+
465
+ return getCommandDefinition(command_name).usage_lines;
466
+ }
467
+
381
468
  /**
382
469
  * @param {string[]} lines
383
470
  * @returns {string[]}
@@ -49,6 +49,17 @@
49
49
  * @returns {Promise<LoadPatramConfigResult>}
50
50
  */
51
51
  export function loadPatramConfig(project_directory?: string): Promise<LoadPatramConfigResult>;
52
+ /**
53
+ * @param {string} config_source
54
+ * @returns {{ success: true, value: unknown } | { success: false, diagnostic: PatramDiagnostic }}
55
+ */
56
+ export function parsePatramConfigSource(config_source: string): {
57
+ success: true;
58
+ value: unknown;
59
+ } | {
60
+ success: false;
61
+ diagnostic: PatramDiagnostic;
62
+ };
52
63
  export type PatramDiagnostic = {
53
64
  code: string;
54
65
  column: number;
@@ -18,15 +18,9 @@ import { readFile } from 'node:fs/promises';
18
18
  import { resolve } from 'node:path';
19
19
  import process from 'node:process';
20
20
 
21
- import { CONFIG_FILE_NAME, patram_repo_config_schema } from './schema.js';
22
- import { createDefaultRepoConfig, normalizeRepoConfig } from './defaults.js';
23
- import {
24
- validateDerivedSummaries,
25
- validateFieldSchemaConfig,
26
- validateGraphSchema,
27
- validateLegacyConfigShape,
28
- validateStoredQueries,
29
- } from './validation.js';
21
+ import { CONFIG_FILE_NAME } from './schema.js';
22
+ import { createDefaultRepoConfig } from './defaults.js';
23
+ import { validatePatramConfigValue } from './validate-patram-config-value.js';
30
24
 
31
25
  /**
32
26
  * Repo config loading.
@@ -90,56 +84,19 @@ export async function loadPatramConfig(project_directory = process.cwd()) {
90
84
  return createLoadResult(createDefaultRepoConfig(), []);
91
85
  }
92
86
 
93
- const parse_result = parseConfigJson(config_source);
87
+ const parse_result = parsePatramConfigSource(config_source);
94
88
 
95
89
  if (!parse_result.success) {
96
90
  return createLoadResult(null, [parse_result.diagnostic]);
97
91
  }
98
92
 
99
- const legacy_config_diagnostics = validateLegacyConfigShape(
100
- parse_result.value,
101
- );
93
+ const validation_result = validatePatramConfigValue(parse_result.value);
102
94
 
103
- if (legacy_config_diagnostics.length > 0) {
104
- return createLoadResult(null, legacy_config_diagnostics);
95
+ if (!validation_result.success) {
96
+ return createLoadResult(null, validation_result.diagnostics);
105
97
  }
106
98
 
107
- const config_result = patram_repo_config_schema.safeParse(parse_result.value);
108
-
109
- if (!config_result.success) {
110
- return createLoadResult(
111
- null,
112
- config_result.error.issues.map(createValidationDiagnostic),
113
- );
114
- }
115
-
116
- const graph_schema_diagnostics = validateGraphSchema(config_result.data);
117
-
118
- if (graph_schema_diagnostics.length > 0) {
119
- return createLoadResult(null, graph_schema_diagnostics);
120
- }
121
-
122
- const normalized_config = normalizeRepoConfig(config_result.data);
123
- const field_schema_diagnostics = validateFieldSchemaConfig(normalized_config);
124
-
125
- if (field_schema_diagnostics.length > 0) {
126
- return createLoadResult(null, field_schema_diagnostics);
127
- }
128
-
129
- const stored_query_diagnostics = validateStoredQueries(normalized_config);
130
-
131
- if (stored_query_diagnostics.length > 0) {
132
- return createLoadResult(null, stored_query_diagnostics);
133
- }
134
-
135
- const derived_summary_diagnostics =
136
- validateDerivedSummaries(normalized_config);
137
-
138
- if (derived_summary_diagnostics.length > 0) {
139
- return createLoadResult(null, derived_summary_diagnostics);
140
- }
141
-
142
- return createLoadResult(normalized_config, []);
99
+ return createLoadResult(validation_result.config, []);
143
100
  }
144
101
 
145
102
  /**
@@ -162,7 +119,7 @@ async function readConfigSource(config_file_path) {
162
119
  * @param {string} config_source
163
120
  * @returns {{ success: true, value: unknown } | { success: false, diagnostic: PatramDiagnostic }}
164
121
  */
165
- function parseConfigJson(config_source) {
122
+ export function parsePatramConfigSource(config_source) {
166
123
  try {
167
124
  return {
168
125
  success: true,
@@ -211,34 +168,6 @@ function createInvalidJsonDiagnostic(config_source, error) {
211
168
  };
212
169
  }
213
170
 
214
- /**
215
- * @param {import('zod').core.$ZodIssue} issue
216
- * @returns {PatramDiagnostic}
217
- */
218
- function createValidationDiagnostic(issue) {
219
- const issue_path = formatIssuePath(issue.path);
220
-
221
- if (issue_path) {
222
- return {
223
- code: 'config.invalid',
224
- column: 1,
225
- level: 'error',
226
- line: 1,
227
- message: `Invalid config at "${issue_path}": ${issue.message}`,
228
- path: CONFIG_FILE_NAME,
229
- };
230
- }
231
-
232
- return {
233
- code: 'config.invalid',
234
- column: 1,
235
- level: 'error',
236
- line: 1,
237
- message: `Invalid config: ${issue.message}`,
238
- path: CONFIG_FILE_NAME,
239
- };
240
- }
241
-
242
171
  /**
243
172
  * @param {unknown} error
244
173
  * @returns {error is NodeJS.ErrnoException}
@@ -281,14 +210,6 @@ function getJsonSyntaxOrigin(config_source, error_message) {
281
210
  };
282
211
  }
283
212
 
284
- /**
285
- * @param {(string | number | symbol | undefined)[]} issue_path
286
- * @returns {string}
287
- */
288
- function formatIssuePath(issue_path) {
289
- return issue_path.map(String).join('.');
290
- }
291
-
292
213
  /**
293
214
  * @param {string} source_text
294
215
  * @param {number} offset