patram 0.8.0 → 0.10.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/bin/patram.js +2 -2
- package/lib/cli/arguments.types.d.ts +63 -0
- package/lib/{parse-cli-color-options.js → cli/color-options.js} +2 -2
- package/lib/cli/command-helpers.js +35 -0
- package/lib/cli/commands/check.js +73 -0
- package/lib/cli/commands/fields.js +57 -0
- package/lib/cli/commands/queries.js +41 -0
- package/lib/cli/commands/query.js +242 -0
- package/lib/cli/commands/refs.js +72 -0
- package/lib/cli/commands/show.js +58 -0
- package/lib/{cli-help-metadata.js → cli/help-metadata.js} +7 -102
- package/lib/cli/main.js +76 -0
- package/lib/{parse-cli-arguments-helpers.js → cli/parse-arguments-helpers.js} +24 -12
- package/lib/{parse-cli-arguments.js → cli/parse-arguments.js} +12 -12
- package/lib/{parse-cli-query-pagination.js → cli/query-pagination.js} +2 -2
- package/lib/{render-cli-help.js → cli/render-help.js} +84 -3
- package/lib/{resolve-output-mode.js → cli/resolve-output-mode.js} +2 -2
- package/lib/cli/test-helpers.js +30 -0
- package/lib/config/defaults.d.ts +10 -0
- package/lib/config/defaults.js +80 -0
- package/lib/config/load-patram-config.d.ts +76 -0
- package/lib/config/load-patram-config.js +315 -0
- package/lib/config/load-patram-config.types.d.ts +45 -0
- package/lib/{patram-config.d.ts → config/patram-config.d.ts} +31 -31
- package/lib/{patram-config.js → config/patram-config.js} +3 -3
- package/lib/{patram-config.types.d.ts → config/patram-config.types.d.ts} +1 -1
- package/lib/{resolve-patram-graph-config.d.ts → config/resolve-patram-graph-config.d.ts} +2 -2
- package/lib/{resolve-patram-graph-config.js → config/resolve-patram-graph-config.js} +3 -3
- package/lib/{load-patram-config.d.ts → config/schema.d.ts} +149 -191
- package/lib/config/schema.js +328 -0
- package/lib/{source-file-defaults.d.ts → config/source-file-defaults.d.ts} +0 -1
- package/lib/{source-file-defaults.js → config/source-file-defaults.js} +1 -1
- package/lib/config/validation.d.ts +27 -0
- package/lib/config/validation.js +615 -0
- package/lib/directive-validation-test-helpers.js +1 -1
- package/lib/find-close-match.d.ts +8 -0
- package/lib/find-close-match.js +98 -0
- package/lib/{build-graph-identity.d.ts → graph/build-graph-identity.d.ts} +2 -2
- package/lib/{build-graph-identity.js → graph/build-graph-identity.js} +1 -1
- package/lib/{build-graph.d.ts → graph/build-graph.d.ts} +3 -3
- package/lib/{build-graph.js → graph/build-graph.js} +17 -13
- package/lib/{build-graph.types.d.ts → graph/build-graph.types.d.ts} +1 -1
- package/lib/graph/check-directive-metadata.d.ts +23 -0
- package/lib/{check-directive-metadata.js → graph/check-directive-metadata.js} +7 -7
- package/lib/graph/check-directive-path-target.d.ts +32 -0
- package/lib/{check-directive-path-target.js → graph/check-directive-path-target.js} +4 -4
- package/lib/graph/check-directive-value.d.ts +19 -0
- package/lib/{check-directive-value.js → graph/check-directive-value.js} +3 -3
- package/lib/graph/check-graph.d.ts +29 -0
- package/lib/{check-graph.js → graph/check-graph.js} +6 -6
- package/lib/graph/directive-diagnostics.d.ts +20 -0
- package/lib/{directive-diagnostics.js → graph/directive-diagnostics.js} +2 -2
- package/lib/graph/directive-type-rules.d.ts +18 -0
- package/lib/{directive-type-rules.js → graph/directive-type-rules.js} +3 -3
- package/lib/{document-node-identity.d.ts → graph/document-node-identity.d.ts} +2 -2
- package/lib/{document-node-identity.js → graph/document-node-identity.js} +2 -2
- package/lib/graph/inspect-reverse-references.d.ts +22 -0
- package/lib/{inspect-reverse-references.js → graph/inspect-reverse-references.js} +2 -2
- package/lib/{load-project-graph.d.ts → graph/load-project-graph.d.ts} +10 -10
- package/lib/{load-project-graph.js → graph/load-project-graph.js} +12 -12
- package/lib/{parse-where-clause.types.d.ts → graph/parse-where-clause.types.d.ts} +1 -1
- package/lib/{query-graph.d.ts → graph/query/execute.d.ts} +11 -11
- package/lib/{query-graph.js → graph/query/execute.js} +12 -12
- package/lib/{query-inspection.d.ts → graph/query/inspect.d.ts} +10 -8
- package/lib/{query-inspection.js → graph/query/inspect.js} +16 -17
- package/lib/{parse-where-clause.d.ts → graph/query/parse.d.ts} +6 -6
- package/lib/{parse-where-clause.js → graph/query/parse.js} +2 -2
- package/lib/graph/query/resolve.d.ts +28 -0
- package/lib/{resolve-where-clause.js → graph/query/resolve.js} +39 -5
- package/lib/graph/reverse-reference-test-helpers.d.ts +55 -0
- package/lib/{command-output.js → output/command-output.js} +5 -5
- package/lib/{derived-summary.js → output/derived-summary.js} +7 -7
- package/lib/{layout-incoming-references.js → output/layout-incoming-references.js} +4 -4
- package/lib/{layout-incoming-summary-lines.js → output/layout-incoming-summary-lines.js} +0 -5
- package/lib/{layout-stored-queries.js → output/layout-stored-queries.js} +27 -11
- package/lib/{list-queries.js → output/list-queries.js} +3 -2
- package/lib/{render-check-output.js → output/render-check-output.js} +1 -1
- package/lib/{render-field-discovery.js → output/render-field-discovery.js} +3 -3
- package/lib/output/render-output-view.js +56 -0
- package/lib/{render-json-output.js → output/renderers/json.js} +10 -6
- package/lib/{render-plain-output.js → output/renderers/plain.js} +34 -33
- package/lib/{render-rich-output.js → output/renderers/rich.js} +44 -32
- package/lib/{resolve-check-target.js → output/resolve-check-target.js} +1 -1
- package/lib/{render-rich-source.js → output/rich-source/render.js} +6 -6
- package/lib/{show-document.js → output/show-document.js} +12 -12
- package/lib/{render-output-view.js → output/view-model/index.js} +11 -70
- package/lib/{write-paged-output.js → output/write-paged-output.js} +9 -5
- package/lib/{claim-helpers.d.ts → parse/claim-helpers.d.ts} +2 -2
- package/lib/{parse-jsdoc-claims.d.ts → parse/jsdoc/parse-jsdoc-claims.d.ts} +2 -2
- package/lib/{parse-jsdoc-claims.js → parse/jsdoc/parse-jsdoc-claims.js} +9 -9
- package/lib/{parse-jsdoc-prose.d.ts → parse/jsdoc/parse-jsdoc-prose.d.ts} +1 -1
- package/lib/{parse-jsdoc-prose.js → parse/jsdoc/parse-jsdoc-prose.js} +1 -1
- package/lib/{parse-markdown-claims.d.ts → parse/markdown/parse-markdown-claims.d.ts} +3 -3
- package/lib/{parse-markdown-claims.js → parse/markdown/parse-markdown-claims.js} +8 -8
- package/lib/{parse-markdown-directives.d.ts → parse/markdown/parse-markdown-directives.d.ts} +2 -2
- package/lib/{parse-markdown-directives.js → parse/markdown/parse-markdown-directives.js} +3 -3
- package/lib/{parse-claims.d.ts → parse/parse-claims.d.ts} +4 -13
- package/lib/{parse-claims.js → parse/parse-claims.js} +18 -26
- package/lib/{parse-claims.types.d.ts → parse/parse-claims.types.d.ts} +1 -1
- package/lib/{tagged-fenced-block-error.d.ts → parse/tagged-fenced/tagged-fenced-block-error.d.ts} +2 -2
- package/lib/{tagged-fenced-block-parser.d.ts → parse/tagged-fenced/tagged-fenced-block-parser.d.ts} +3 -3
- package/lib/{tagged-fenced-blocks.d.ts → parse/tagged-fenced/tagged-fenced-blocks.d.ts} +7 -7
- package/lib/{tagged-fenced-blocks.js → parse/tagged-fenced/tagged-fenced-blocks.js} +3 -3
- package/lib/{parse-yaml-claims.d.ts → parse/yaml/parse-yaml-claims.d.ts} +4 -4
- package/lib/{parse-yaml-claims.js → parse/yaml/parse-yaml-claims.js} +22 -13
- package/lib/patram.d.ts +29 -28
- package/lib/patram.js +5 -6
- package/lib/{discover-fields.js → scan/discover-fields.js} +145 -18
- package/lib/scan/list-repo-files.d.ts +16 -0
- package/lib/{list-source-files.js → scan/list-repo-files.js} +2 -35
- package/lib/{list-source-files.d.ts → scan/list-source-files.d.ts} +4 -11
- package/lib/scan/list-source-files.js +45 -0
- package/package.json +8 -7
- package/lib/build-graph.types.ts +0 -27
- package/lib/discover-fields.types.ts +0 -52
- package/lib/load-patram-config.js +0 -1215
- package/lib/load-patram-config.types.d.ts +0 -45
- package/lib/load-patram-config.types.ts +0 -56
- package/lib/output-view.types.d.ts +0 -88
- package/lib/output-view.types.ts +0 -113
- package/lib/overlay-graph.d.ts +0 -43
- package/lib/overlay-graph.js +0 -191
- package/lib/parse-claims.types.ts +0 -41
- package/lib/parse-cli-arguments.types.ts +0 -75
- package/lib/parse-where-clause.types.ts +0 -87
- package/lib/patram-cli.js +0 -593
- package/lib/patram-config.types.ts +0 -22
- package/lib/tagged-fenced-blocks.types.ts +0 -38
- /package/lib/{reverse-reference-test-helpers.js → graph/reverse-reference-test-helpers.js} +0 -0
- /package/lib/{format-derived-summary-row.js → output/format-derived-summary-row.js} +0 -0
- /package/lib/{format-node-header.js → output/format-node-header.js} +0 -0
- /package/lib/{format-output-item-block.js → output/format-output-item-block.js} +0 -0
- /package/lib/{format-output-metadata.js → output/format-output-metadata.js} +0 -0
- /package/lib/{claim-helpers.js → parse/claim-helpers.js} +0 -0
- /package/lib/{parse-jsdoc-blocks.d.ts → parse/jsdoc/parse-jsdoc-blocks.d.ts} +0 -0
- /package/lib/{parse-jsdoc-blocks.js → parse/jsdoc/parse-jsdoc-blocks.js} +0 -0
- /package/lib/{tagged-fenced-block-error.js → parse/tagged-fenced/tagged-fenced-block-error.js} +0 -0
- /package/lib/{tagged-fenced-block-markdown.d.ts → parse/tagged-fenced/tagged-fenced-block-markdown.d.ts} +0 -0
- /package/lib/{tagged-fenced-block-markdown.js → parse/tagged-fenced/tagged-fenced-block-markdown.js} +0 -0
- /package/lib/{tagged-fenced-block-metadata.d.ts → parse/tagged-fenced/tagged-fenced-block-metadata.d.ts} +0 -0
- /package/lib/{tagged-fenced-block-metadata.js → parse/tagged-fenced/tagged-fenced-block-metadata.js} +0 -0
- /package/lib/{tagged-fenced-block-parser.js → parse/tagged-fenced/tagged-fenced-block-parser.js} +0 -0
- /package/lib/{tagged-fenced-blocks.types.d.ts → parse/tagged-fenced/tagged-fenced-blocks.types.d.ts} +0 -0
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
* @import {
|
|
4
4
|
* CliCommandName,
|
|
5
5
|
* CliHelpTopicName,
|
|
6
|
-
* } from './
|
|
6
|
+
* } from './arguments.types.ts';
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { findCloseMatch } from '../find-close-match.js';
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
12
|
* @typedef {{
|
|
11
13
|
* description: string,
|
|
@@ -45,7 +47,7 @@
|
|
|
45
47
|
* }} CliHelpTopicDefinition
|
|
46
48
|
*/
|
|
47
49
|
|
|
48
|
-
|
|
50
|
+
const COMMAND_NAMES = /** @type {const} */ ([
|
|
49
51
|
'check',
|
|
50
52
|
'fields',
|
|
51
53
|
'query',
|
|
@@ -54,7 +56,7 @@ export const COMMAND_NAMES = /** @type {const} */ ([
|
|
|
54
56
|
'show',
|
|
55
57
|
]);
|
|
56
58
|
|
|
57
|
-
|
|
59
|
+
const HELP_TOPIC_NAMES = /** @type {const} */ (['query-language']);
|
|
58
60
|
|
|
59
61
|
export const GLOBAL_OPTION_NAMES = new Set([
|
|
60
62
|
'help',
|
|
@@ -284,14 +286,14 @@ const COMMAND_DEFINITIONS = {
|
|
|
284
286
|
},
|
|
285
287
|
show: {
|
|
286
288
|
allowed_option_names: new Set(),
|
|
287
|
-
examples: ['patram show docs/patram.md', 'patram show lib/
|
|
289
|
+
examples: ['patram show docs/patram.md', 'patram show lib/cli/main.js'],
|
|
288
290
|
extra_positionals_message: 'Show accepts exactly one file path.',
|
|
289
291
|
help_topics: [],
|
|
290
292
|
max_positionals: 1,
|
|
291
293
|
min_positionals: 1,
|
|
292
294
|
missing_argument_examples: [
|
|
293
295
|
'patram show docs/patram.md',
|
|
294
|
-
'patram show lib/
|
|
296
|
+
'patram show lib/cli/main.js',
|
|
295
297
|
],
|
|
296
298
|
missing_argument_label: '<file>',
|
|
297
299
|
missing_usage_lines: ['patram show <file>'],
|
|
@@ -532,100 +534,3 @@ function listOptionLabels(command_name) {
|
|
|
532
534
|
|
|
533
535
|
return [...option_labels];
|
|
534
536
|
}
|
|
535
|
-
|
|
536
|
-
/**
|
|
537
|
-
* @param {string} input_text
|
|
538
|
-
* @param {readonly string[]} candidates
|
|
539
|
-
* @returns {string | undefined}
|
|
540
|
-
*/
|
|
541
|
-
function findCloseMatch(input_text, candidates) {
|
|
542
|
-
let best_candidate;
|
|
543
|
-
let best_score = 0;
|
|
544
|
-
|
|
545
|
-
for (const candidate of candidates) {
|
|
546
|
-
const score = scoreCandidate(input_text, candidate);
|
|
547
|
-
|
|
548
|
-
if (score > best_score) {
|
|
549
|
-
best_candidate = candidate;
|
|
550
|
-
best_score = score;
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
if (best_score < 0.6) {
|
|
555
|
-
return undefined;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
return best_candidate;
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
/**
|
|
562
|
-
* @param {string} input_text
|
|
563
|
-
* @param {string} candidate
|
|
564
|
-
* @returns {number}
|
|
565
|
-
*/
|
|
566
|
-
function scoreCandidate(input_text, candidate) {
|
|
567
|
-
const max_length = Math.max(input_text.length, candidate.length);
|
|
568
|
-
|
|
569
|
-
if (max_length === 0) {
|
|
570
|
-
return 1;
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
return (
|
|
574
|
-
1 - calculateDamerauLevenshteinDistance(input_text, candidate) / max_length
|
|
575
|
-
);
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
/**
|
|
579
|
-
* @param {string} left_text
|
|
580
|
-
* @param {string} right_text
|
|
581
|
-
* @returns {number}
|
|
582
|
-
*/
|
|
583
|
-
function calculateDamerauLevenshteinDistance(left_text, right_text) {
|
|
584
|
-
/** @type {number[][]} */
|
|
585
|
-
const matrix = Array.from({ length: left_text.length + 1 }, () =>
|
|
586
|
-
Array(right_text.length + 1).fill(0),
|
|
587
|
-
);
|
|
588
|
-
|
|
589
|
-
for (let left_index = 0; left_index <= left_text.length; left_index += 1) {
|
|
590
|
-
matrix[left_index][0] = left_index;
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
for (
|
|
594
|
-
let right_index = 0;
|
|
595
|
-
right_index <= right_text.length;
|
|
596
|
-
right_index += 1
|
|
597
|
-
) {
|
|
598
|
-
matrix[0][right_index] = right_index;
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
for (let left_index = 1; left_index <= left_text.length; left_index += 1) {
|
|
602
|
-
for (
|
|
603
|
-
let right_index = 1;
|
|
604
|
-
right_index <= right_text.length;
|
|
605
|
-
right_index += 1
|
|
606
|
-
) {
|
|
607
|
-
const substitution_cost =
|
|
608
|
-
left_text[left_index - 1] === right_text[right_index - 1] ? 0 : 1;
|
|
609
|
-
|
|
610
|
-
matrix[left_index][right_index] = Math.min(
|
|
611
|
-
matrix[left_index - 1][right_index] + 1,
|
|
612
|
-
matrix[left_index][right_index - 1] + 1,
|
|
613
|
-
matrix[left_index - 1][right_index - 1] + substitution_cost,
|
|
614
|
-
);
|
|
615
|
-
|
|
616
|
-
if (
|
|
617
|
-
left_index > 1 &&
|
|
618
|
-
right_index > 1 &&
|
|
619
|
-
left_text[left_index - 1] === right_text[right_index - 2] &&
|
|
620
|
-
left_text[left_index - 2] === right_text[right_index - 1]
|
|
621
|
-
) {
|
|
622
|
-
matrix[left_index][right_index] = Math.min(
|
|
623
|
-
matrix[left_index][right_index],
|
|
624
|
-
matrix[left_index - 2][right_index - 2] + 1,
|
|
625
|
-
);
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
return matrix[left_text.length][right_text.length];
|
|
631
|
-
}
|
package/lib/cli/main.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import { ParsedCliCommandRequest } from './arguments.types.ts';
|
|
3
|
+
*/
|
|
4
|
+
import { renderCliParseError, renderHelpRequest } from './render-help.js';
|
|
5
|
+
import { parseCliArguments } from './parse-arguments.js';
|
|
6
|
+
import { runCheckCommand } from './commands/check.js';
|
|
7
|
+
import { runFieldsCommand } from './commands/fields.js';
|
|
8
|
+
import { runQueryCommand } from './commands/query.js';
|
|
9
|
+
import { runQueriesCommand } from './commands/queries.js';
|
|
10
|
+
import { runRefsCommand } from './commands/refs.js';
|
|
11
|
+
import { runShowCommand } from './commands/show.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Patram command execution flow.
|
|
15
|
+
*
|
|
16
|
+
* Loads repo state and routes `check`, `fields`, `query`, `queries`, and
|
|
17
|
+
* `show` through the shared output pipeline.
|
|
18
|
+
*
|
|
19
|
+
* Kind: cli
|
|
20
|
+
* Status: active
|
|
21
|
+
* Implements Command: ../../docs/reference/commands/check.md
|
|
22
|
+
* Implements Command: ../../docs/reference/commands/query.md
|
|
23
|
+
* Implements Command: ../../docs/reference/commands/queries.md
|
|
24
|
+
* Implements Command: ../../docs/reference/commands/refs.md
|
|
25
|
+
* Implements Command: ../../docs/reference/commands/show.md
|
|
26
|
+
* Tracked in: ../../docs/plans/v0/source-anchor-dogfooding.md
|
|
27
|
+
* Decided by: ../../docs/decisions/cli-output-architecture.md
|
|
28
|
+
* Decided by: ../../docs/decisions/cli-argument-parser.md
|
|
29
|
+
* @patram
|
|
30
|
+
* @see {@link ./parse-arguments.js}
|
|
31
|
+
* @see {@link ./commands/query.js}
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Run the Patram CLI.
|
|
36
|
+
*
|
|
37
|
+
* @param {string[]} cli_arguments
|
|
38
|
+
* @param {{ stderr: { write(chunk: string): boolean }, stdout: { isTTY?: boolean, write(chunk: string): boolean }, write_paged_output?: (output_text: string) => Promise<void> }} io_context
|
|
39
|
+
* @returns {Promise<number>}
|
|
40
|
+
*/
|
|
41
|
+
export async function main(cli_arguments, io_context) {
|
|
42
|
+
const parsed_arguments = parseCliArguments(cli_arguments);
|
|
43
|
+
|
|
44
|
+
if (!parsed_arguments.success) {
|
|
45
|
+
io_context.stderr.write(renderCliParseError(parsed_arguments.error));
|
|
46
|
+
|
|
47
|
+
return 1;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (parsed_arguments.value.kind === 'help') {
|
|
51
|
+
io_context.stdout.write(renderHelpRequest(parsed_arguments.value));
|
|
52
|
+
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const parsed_command = /** @type {ParsedCliCommandRequest} */ (
|
|
57
|
+
parsed_arguments.value
|
|
58
|
+
);
|
|
59
|
+
const commandHandler = COMMAND_HANDLERS[parsed_command.command_name];
|
|
60
|
+
|
|
61
|
+
if (commandHandler) {
|
|
62
|
+
return commandHandler(parsed_command, io_context);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
io_context.stderr.write('Unknown command.\n');
|
|
66
|
+
|
|
67
|
+
return 1;
|
|
68
|
+
}
|
|
69
|
+
const COMMAND_HANDLERS = {
|
|
70
|
+
check: runCheckCommand,
|
|
71
|
+
fields: runFieldsCommand,
|
|
72
|
+
queries: runQueriesCommand,
|
|
73
|
+
query: runQueryCommand,
|
|
74
|
+
refs: runRefsCommand,
|
|
75
|
+
show: runShowCommand,
|
|
76
|
+
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/* eslint-disable max-lines */
|
|
2
2
|
/**
|
|
3
|
-
* @typedef {import('./
|
|
4
|
-
* @typedef {import('./
|
|
5
|
-
* @typedef {import('./
|
|
6
|
-
* @typedef {import('./
|
|
3
|
+
* @typedef {import('./arguments.types.ts').CliCommandName} CliCommandName
|
|
4
|
+
* @typedef {import('./arguments.types.ts').CliOutputMode} CliOutputMode
|
|
5
|
+
* @typedef {import('./arguments.types.ts').CliParseError} CliParseError
|
|
6
|
+
* @typedef {import('./arguments.types.ts').ParsedCliHelpRequest} ParsedCliHelpRequest
|
|
7
7
|
* @typedef {{ kind: string, name?: string, rawName?: string, value?: string | boolean }} CliOptionToken
|
|
8
8
|
* @typedef {{ color?: string, explain?: boolean, help?: boolean, json?: boolean, limit?: string, lint?: boolean, 'no-color'?: boolean, offset?: string, plain?: boolean, where?: string }} CliOptionValues
|
|
9
9
|
* @typedef {{ option_tokens: CliOptionToken[], positionals: string[], values: CliOptionValues }} ParsedCommandLine
|
|
@@ -17,9 +17,9 @@ import {
|
|
|
17
17
|
GLOBAL_OPTION_NAMES,
|
|
18
18
|
isCommandName,
|
|
19
19
|
isHelpTopicName,
|
|
20
|
-
} from './
|
|
21
|
-
import { findInvalidColorMode } from './
|
|
22
|
-
import { findInvalidQueryPagination } from './
|
|
20
|
+
} from './help-metadata.js';
|
|
21
|
+
import { findInvalidColorMode } from './color-options.js';
|
|
22
|
+
import { findInvalidQueryPagination } from './query-pagination.js';
|
|
23
23
|
|
|
24
24
|
export const CLI_OPTIONS = /** @type {const} */ ({
|
|
25
25
|
color: { type: 'string' },
|
|
@@ -67,9 +67,7 @@ export function validateHelpCommandLine(command_line) {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
if (command_line.positionals.length > 2) {
|
|
70
|
-
return
|
|
71
|
-
'Help accepts at most one topic or command.',
|
|
72
|
-
);
|
|
70
|
+
return createUnexpectedArgumentError('help', command_line.positionals[2]);
|
|
73
71
|
}
|
|
74
72
|
|
|
75
73
|
return null;
|
|
@@ -422,8 +420,9 @@ function validateCommandPositionals(command_name, command_positionals) {
|
|
|
422
420
|
}
|
|
423
421
|
|
|
424
422
|
if (command_positionals.length > command_definition.max_positionals) {
|
|
425
|
-
return
|
|
426
|
-
|
|
423
|
+
return createUnexpectedArgumentError(
|
|
424
|
+
command_name,
|
|
425
|
+
command_positionals[command_definition.max_positionals],
|
|
427
426
|
);
|
|
428
427
|
}
|
|
429
428
|
|
|
@@ -451,3 +450,16 @@ function isKnownCommandOptionName(option_name) {
|
|
|
451
450
|
option_name === 'where'
|
|
452
451
|
);
|
|
453
452
|
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* @param {'help' | CliCommandName} command_name
|
|
456
|
+
* @param {string | undefined} token
|
|
457
|
+
* @returns {CliParseError}
|
|
458
|
+
*/
|
|
459
|
+
function createUnexpectedArgumentError(command_name, token) {
|
|
460
|
+
return {
|
|
461
|
+
code: 'unexpected_argument',
|
|
462
|
+
command_name,
|
|
463
|
+
token: token ?? '',
|
|
464
|
+
};
|
|
465
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/* eslint-disable max-lines-per-function */
|
|
2
2
|
/**
|
|
3
|
-
* @typedef {import('./parse-
|
|
4
|
-
* @typedef {import('./parse-
|
|
5
|
-
* @typedef {import('./
|
|
6
|
-
* @typedef {import('./
|
|
3
|
+
* @typedef {import('./parse-arguments-helpers.js').CliOptionValues} CliOptionValues
|
|
4
|
+
* @typedef {import('./parse-arguments-helpers.js').ParsedCommandLine} ParsedCommandLine
|
|
5
|
+
* @typedef {import('./arguments.types.ts').CliParseError} CliParseError
|
|
6
|
+
* @typedef {import('./arguments.types.ts').ParseCliArgumentsResult} ParseCliArgumentsResult
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { parseArgs } from 'node:util';
|
|
@@ -23,10 +23,10 @@ import {
|
|
|
23
23
|
validateHelpCommandLine,
|
|
24
24
|
validateParsedCommand,
|
|
25
25
|
validateRootCommandLine,
|
|
26
|
-
} from './parse-
|
|
27
|
-
import { isCommandName } from './
|
|
28
|
-
import { resolveColorMode } from './
|
|
29
|
-
import { buildQueryPagination } from './
|
|
26
|
+
} from './parse-arguments-helpers.js';
|
|
27
|
+
import { isCommandName } from './help-metadata.js';
|
|
28
|
+
import { resolveColorMode } from './color-options.js';
|
|
29
|
+
import { buildQueryPagination } from './query-pagination.js';
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* CLI argument parsing.
|
|
@@ -36,11 +36,11 @@ import { buildQueryPagination } from './parse-cli-query-pagination.js';
|
|
|
36
36
|
*
|
|
37
37
|
* Kind: cli
|
|
38
38
|
* Status: active
|
|
39
|
-
* Tracked in:
|
|
40
|
-
* Decided by:
|
|
39
|
+
* Tracked in: ../../docs/plans/v0/source-anchor-dogfooding.md
|
|
40
|
+
* Decided by: ../../docs/decisions/cli-argument-parser.md
|
|
41
41
|
* @patram
|
|
42
|
-
* @see {@link ./
|
|
43
|
-
* @see {@link
|
|
42
|
+
* @see {@link ./main.js}
|
|
43
|
+
* @see {@link ../../docs/decisions/cli-argument-parser.md}
|
|
44
44
|
*/
|
|
45
45
|
|
|
46
46
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @typedef {import('./parse-
|
|
3
|
-
* @typedef {import('./parse-
|
|
2
|
+
* @typedef {import('./parse-arguments-helpers.js').CliOptionToken} CliOptionToken
|
|
3
|
+
* @typedef {import('./parse-arguments-helpers.js').CliOptionValues} CliOptionValues
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* CliHelpTopicName,
|
|
6
6
|
* CliParseError,
|
|
7
7
|
* ParsedCliHelpRequest,
|
|
8
|
-
* } from './
|
|
9
|
-
* @import { PatramDiagnostic } from '
|
|
8
|
+
* } from './arguments.types.ts';
|
|
9
|
+
* @import { PatramDiagnostic } from '../config/load-patram-config.types.ts';
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import {
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
getRootHelpDefinition,
|
|
16
16
|
listCommandNames,
|
|
17
17
|
listHelpTopicNames,
|
|
18
|
-
} from './
|
|
18
|
+
} from './help-metadata.js';
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* @param {ParsedCliHelpRequest} help_request
|
|
@@ -75,6 +75,20 @@ 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.suggestion,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
78
92
|
return `${parse_error.message}\n`;
|
|
79
93
|
}
|
|
80
94
|
|
|
@@ -326,6 +340,49 @@ function renderMissingRequiredArgumentError(command_name, argument_label) {
|
|
|
326
340
|
]);
|
|
327
341
|
}
|
|
328
342
|
|
|
343
|
+
/**
|
|
344
|
+
* @param {'help' | CliCommandName} command_name
|
|
345
|
+
* @param {string} invalid_token
|
|
346
|
+
* @returns {string}
|
|
347
|
+
*/
|
|
348
|
+
function renderUnexpectedArgumentError(command_name, invalid_token) {
|
|
349
|
+
return joinOutputLines([
|
|
350
|
+
`Unexpected argument: ${invalid_token}`,
|
|
351
|
+
'',
|
|
352
|
+
'Usage:',
|
|
353
|
+
...indentLines(getUnexpectedArgumentUsageLines(command_name)),
|
|
354
|
+
'',
|
|
355
|
+
'Next:',
|
|
356
|
+
` ${renderUnexpectedArgumentNext(command_name)}`,
|
|
357
|
+
]);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* @param {string} stored_query_name
|
|
362
|
+
* @param {string | undefined} suggestion
|
|
363
|
+
* @returns {string}
|
|
364
|
+
*/
|
|
365
|
+
function renderUnknownStoredQueryError(stored_query_name, suggestion) {
|
|
366
|
+
if (suggestion) {
|
|
367
|
+
return joinOutputLines([
|
|
368
|
+
`Unknown stored query: ${stored_query_name}`,
|
|
369
|
+
'',
|
|
370
|
+
'Did you mean:',
|
|
371
|
+
` ${suggestion}`,
|
|
372
|
+
'',
|
|
373
|
+
'Next:',
|
|
374
|
+
` patram query ${suggestion}`,
|
|
375
|
+
]);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return joinOutputLines([
|
|
379
|
+
`Unknown stored query: ${stored_query_name}`,
|
|
380
|
+
'',
|
|
381
|
+
'Next:',
|
|
382
|
+
' patram queries',
|
|
383
|
+
]);
|
|
384
|
+
}
|
|
385
|
+
|
|
329
386
|
/**
|
|
330
387
|
* @param {string} invalid_token
|
|
331
388
|
* @param {CliCommandName | CliHelpTopicName | undefined} suggestion
|
|
@@ -378,6 +435,30 @@ function renderCommandHelpPath(command_name) {
|
|
|
378
435
|
return `patram help ${command_name}`;
|
|
379
436
|
}
|
|
380
437
|
|
|
438
|
+
/**
|
|
439
|
+
* @param {'help' | CliCommandName} command_name
|
|
440
|
+
* @returns {string}
|
|
441
|
+
*/
|
|
442
|
+
function renderUnexpectedArgumentNext(command_name) {
|
|
443
|
+
if (command_name === 'help') {
|
|
444
|
+
return 'patram --help';
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return renderCommandHelpPath(command_name);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* @param {'help' | CliCommandName} command_name
|
|
452
|
+
* @returns {string[]}
|
|
453
|
+
*/
|
|
454
|
+
function getUnexpectedArgumentUsageLines(command_name) {
|
|
455
|
+
if (command_name === 'help') {
|
|
456
|
+
return ['patram help [command]'];
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
return getCommandDefinition(command_name).usage_lines;
|
|
460
|
+
}
|
|
461
|
+
|
|
381
462
|
/**
|
|
382
463
|
* @param {string[]} lines
|
|
383
464
|
* @returns {string[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @import { ParsedCliArguments } from './
|
|
3
|
-
* @import { ResolvedOutputMode } from '
|
|
2
|
+
* @import { ParsedCliArguments } from './arguments.types.ts';
|
|
3
|
+
* @import { ResolvedOutputMode } from '../output/output-view.types.ts';
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function createIoContext() {
|
|
2
|
+
/** @type {{ stderr_chunks: string[], stdout_chunks: string[] }} */
|
|
3
|
+
const io_context = {
|
|
4
|
+
stderr_chunks: [],
|
|
5
|
+
stdout_chunks: [],
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
...io_context,
|
|
10
|
+
stderr: {
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} chunk
|
|
13
|
+
*/
|
|
14
|
+
write(chunk) {
|
|
15
|
+
io_context.stderr_chunks.push(chunk);
|
|
16
|
+
return true;
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
stdout: {
|
|
20
|
+
isTTY: false,
|
|
21
|
+
/**
|
|
22
|
+
* @param {string} chunk
|
|
23
|
+
*/
|
|
24
|
+
write(chunk) {
|
|
25
|
+
io_context.stdout_chunks.push(chunk);
|
|
26
|
+
return true;
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @returns {PatramRepoConfig}
|
|
3
|
+
*/
|
|
4
|
+
export function createDefaultRepoConfig(): PatramRepoConfig;
|
|
5
|
+
/**
|
|
6
|
+
* @param {PatramRepoConfig} repo_config
|
|
7
|
+
* @returns {PatramRepoConfig}
|
|
8
|
+
*/
|
|
9
|
+
export function normalizeRepoConfig(repo_config: PatramRepoConfig): PatramRepoConfig;
|
|
10
|
+
import type { PatramRepoConfig } from './schema.js';
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import { PatramRepoConfig } from './schema.js';
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { DEFAULT_INCLUDE_PATTERNS } from './source-file-defaults.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @returns {PatramRepoConfig}
|
|
9
|
+
*/
|
|
10
|
+
export function createDefaultRepoConfig() {
|
|
11
|
+
return {
|
|
12
|
+
include: [...DEFAULT_INCLUDE_PATTERNS],
|
|
13
|
+
queries: {},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {PatramRepoConfig} repo_config
|
|
19
|
+
* @returns {PatramRepoConfig}
|
|
20
|
+
*/
|
|
21
|
+
export function normalizeRepoConfig(repo_config) {
|
|
22
|
+
/** @type {PatramRepoConfig} */
|
|
23
|
+
const normalized_config = {
|
|
24
|
+
include: [...repo_config.include],
|
|
25
|
+
queries: { ...repo_config.queries },
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
assignOptionalRepoConfigField(
|
|
29
|
+
normalized_config,
|
|
30
|
+
'classes',
|
|
31
|
+
repo_config.classes,
|
|
32
|
+
);
|
|
33
|
+
assignOptionalRepoConfigField(
|
|
34
|
+
normalized_config,
|
|
35
|
+
'derived_summaries',
|
|
36
|
+
repo_config.derived_summaries,
|
|
37
|
+
);
|
|
38
|
+
assignOptionalRepoConfigField(
|
|
39
|
+
normalized_config,
|
|
40
|
+
'fields',
|
|
41
|
+
repo_config.fields,
|
|
42
|
+
);
|
|
43
|
+
assignOptionalRepoConfigField(
|
|
44
|
+
normalized_config,
|
|
45
|
+
'mappings',
|
|
46
|
+
repo_config.mappings,
|
|
47
|
+
);
|
|
48
|
+
assignOptionalRepoConfigField(
|
|
49
|
+
normalized_config,
|
|
50
|
+
'path_classes',
|
|
51
|
+
repo_config.path_classes,
|
|
52
|
+
);
|
|
53
|
+
assignOptionalRepoConfigField(
|
|
54
|
+
normalized_config,
|
|
55
|
+
'relations',
|
|
56
|
+
repo_config.relations,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
return normalized_config;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @template {Exclude<keyof PatramRepoConfig, 'include' | 'queries'>} TKey
|
|
64
|
+
* @param {PatramRepoConfig} normalized_config
|
|
65
|
+
* @param {TKey} field_name
|
|
66
|
+
* @param {unknown} field_value
|
|
67
|
+
*/
|
|
68
|
+
function assignOptionalRepoConfigField(
|
|
69
|
+
normalized_config,
|
|
70
|
+
field_name,
|
|
71
|
+
field_value,
|
|
72
|
+
) {
|
|
73
|
+
if (field_value === undefined || field_value === null) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
normalized_config[field_name] = /** @type {PatramRepoConfig[TKey]} */ (
|
|
78
|
+
field_value
|
|
79
|
+
);
|
|
80
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repo config loading.
|
|
3
|
+
*
|
|
4
|
+
* Reads `.patram.json`, applies defaults, and validates repo config and graph
|
|
5
|
+
* schema before command execution.
|
|
6
|
+
*
|
|
7
|
+
* Kind: config
|
|
8
|
+
* Status: active
|
|
9
|
+
* Tracked in: ../../docs/plans/v0/source-anchor-dogfooding.md
|
|
10
|
+
* Decided by: ../../docs/decisions/single-config-file.md
|
|
11
|
+
* Decided by: ../../docs/decisions/optional-config-default-scan.md
|
|
12
|
+
* @patram
|
|
13
|
+
* @see {@link ./schema.js}
|
|
14
|
+
* @see {@link ./validation.js}
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {object} PatramDiagnostic
|
|
18
|
+
* @property {string} code
|
|
19
|
+
* @property {number} column
|
|
20
|
+
* @property {'error'} level
|
|
21
|
+
* @property {number} line
|
|
22
|
+
* @property {string} message
|
|
23
|
+
* @property {string} path
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {object} LoadPatramConfigResult
|
|
27
|
+
* @property {import('./schema.js').PatramRepoConfig | null} config
|
|
28
|
+
* @property {string} config_path
|
|
29
|
+
* @property {PatramDiagnostic[]} diagnostics
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* @typedef {import('./schema.js').StoredQueryConfig} StoredQueryConfig
|
|
33
|
+
* @typedef {import('./schema.js').FieldDisplayConfig} FieldDisplayConfig
|
|
34
|
+
* @typedef {import('./schema.js').FieldQueryConfig} FieldQueryConfig
|
|
35
|
+
* @typedef {import('./schema.js').MetadataFieldConfig} MetadataFieldConfig
|
|
36
|
+
* @typedef {import('./schema.js').ClassFieldRuleConfig} ClassFieldRuleConfig
|
|
37
|
+
* @typedef {import('./schema.js').ClassSchemaConfig} ClassSchemaConfig
|
|
38
|
+
* @typedef {import('./schema.js').PathClassConfig} PathClassConfig
|
|
39
|
+
* @typedef {import('./schema.js').DerivedSummaryScalar} DerivedSummaryScalar
|
|
40
|
+
* @typedef {import('./schema.js').DerivedSummarySelectCaseConfig} DerivedSummarySelectCaseConfig
|
|
41
|
+
* @typedef {import('./schema.js').DerivedSummaryFieldConfig} DerivedSummaryFieldConfig
|
|
42
|
+
* @typedef {import('./schema.js').DerivedSummaryConfig} DerivedSummaryConfig
|
|
43
|
+
* @typedef {import('./schema.js').PatramRepoConfig} PatramRepoConfig
|
|
44
|
+
*/
|
|
45
|
+
/**
|
|
46
|
+
* Load and validate the repo Patram config.
|
|
47
|
+
*
|
|
48
|
+
* @param {string} [project_directory]
|
|
49
|
+
* @returns {Promise<LoadPatramConfigResult>}
|
|
50
|
+
*/
|
|
51
|
+
export function loadPatramConfig(project_directory?: string): Promise<LoadPatramConfigResult>;
|
|
52
|
+
export type PatramDiagnostic = {
|
|
53
|
+
code: string;
|
|
54
|
+
column: number;
|
|
55
|
+
level: "error";
|
|
56
|
+
line: number;
|
|
57
|
+
message: string;
|
|
58
|
+
path: string;
|
|
59
|
+
};
|
|
60
|
+
export type LoadPatramConfigResult = {
|
|
61
|
+
config: import("./schema.js").PatramRepoConfig | null;
|
|
62
|
+
config_path: string;
|
|
63
|
+
diagnostics: PatramDiagnostic[];
|
|
64
|
+
};
|
|
65
|
+
export type StoredQueryConfig = import("./schema.js").StoredQueryConfig;
|
|
66
|
+
export type FieldDisplayConfig = import("./schema.js").FieldDisplayConfig;
|
|
67
|
+
export type FieldQueryConfig = import("./schema.js").FieldQueryConfig;
|
|
68
|
+
export type MetadataFieldConfig = import("./schema.js").MetadataFieldConfig;
|
|
69
|
+
export type ClassFieldRuleConfig = import("./schema.js").ClassFieldRuleConfig;
|
|
70
|
+
export type ClassSchemaConfig = import("./schema.js").ClassSchemaConfig;
|
|
71
|
+
export type PathClassConfig = import("./schema.js").PathClassConfig;
|
|
72
|
+
export type DerivedSummaryScalar = import("./schema.js").DerivedSummaryScalar;
|
|
73
|
+
export type DerivedSummarySelectCaseConfig = import("./schema.js").DerivedSummarySelectCaseConfig;
|
|
74
|
+
export type DerivedSummaryFieldConfig = import("./schema.js").DerivedSummaryFieldConfig;
|
|
75
|
+
export type DerivedSummaryConfig = import("./schema.js").DerivedSummaryConfig;
|
|
76
|
+
export type PatramRepoConfig = import("./schema.js").PatramRepoConfig;
|