patram 0.8.0 → 0.9.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 (140) hide show
  1. package/bin/patram.js +2 -2
  2. package/lib/{parse-cli-color-options.js → cli/color-options.js} +2 -2
  3. package/lib/cli/command-helpers.js +35 -0
  4. package/lib/cli/commands/check.js +73 -0
  5. package/lib/cli/commands/fields.js +57 -0
  6. package/lib/cli/commands/queries.js +41 -0
  7. package/lib/cli/commands/query.js +239 -0
  8. package/lib/cli/commands/refs.js +72 -0
  9. package/lib/cli/commands/show.js +58 -0
  10. package/lib/{cli-help-metadata.js → cli/help-metadata.js} +6 -6
  11. package/lib/cli/main.js +76 -0
  12. package/lib/{parse-cli-arguments-helpers.js → cli/parse-arguments-helpers.js} +7 -7
  13. package/lib/{parse-cli-arguments.js → cli/parse-arguments.js} +12 -12
  14. package/lib/{parse-cli-query-pagination.js → cli/query-pagination.js} +2 -2
  15. package/lib/{render-cli-help.js → cli/render-help.js} +3 -3
  16. package/lib/{resolve-output-mode.js → cli/resolve-output-mode.js} +2 -2
  17. package/lib/cli/test-helpers.js +30 -0
  18. package/lib/config/defaults.d.ts +10 -0
  19. package/lib/config/defaults.js +80 -0
  20. package/lib/config/load-patram-config.d.ts +76 -0
  21. package/lib/config/load-patram-config.js +315 -0
  22. package/lib/config/load-patram-config.types.d.ts +45 -0
  23. package/lib/{patram-config.d.ts → config/patram-config.d.ts} +31 -31
  24. package/lib/{patram-config.js → config/patram-config.js} +3 -3
  25. package/lib/{patram-config.types.d.ts → config/patram-config.types.d.ts} +1 -1
  26. package/lib/{resolve-patram-graph-config.d.ts → config/resolve-patram-graph-config.d.ts} +2 -2
  27. package/lib/{resolve-patram-graph-config.js → config/resolve-patram-graph-config.js} +3 -3
  28. package/lib/{load-patram-config.d.ts → config/schema.d.ts} +147 -191
  29. package/lib/config/schema.js +324 -0
  30. package/lib/{source-file-defaults.d.ts → config/source-file-defaults.d.ts} +0 -1
  31. package/lib/{source-file-defaults.js → config/source-file-defaults.js} +1 -1
  32. package/lib/config/validation.d.ts +27 -0
  33. package/lib/config/validation.js +615 -0
  34. package/lib/directive-validation-test-helpers.js +1 -1
  35. package/lib/{build-graph-identity.d.ts → graph/build-graph-identity.d.ts} +2 -2
  36. package/lib/{build-graph-identity.js → graph/build-graph-identity.js} +1 -1
  37. package/lib/{build-graph.d.ts → graph/build-graph.d.ts} +3 -3
  38. package/lib/{build-graph.js → graph/build-graph.js} +17 -13
  39. package/lib/{build-graph.types.d.ts → graph/build-graph.types.d.ts} +1 -1
  40. package/lib/graph/check-directive-metadata.d.ts +23 -0
  41. package/lib/{check-directive-metadata.js → graph/check-directive-metadata.js} +7 -7
  42. package/lib/graph/check-directive-path-target.d.ts +32 -0
  43. package/lib/{check-directive-path-target.js → graph/check-directive-path-target.js} +4 -4
  44. package/lib/graph/check-directive-value.d.ts +19 -0
  45. package/lib/{check-directive-value.js → graph/check-directive-value.js} +3 -3
  46. package/lib/graph/check-graph.d.ts +29 -0
  47. package/lib/{check-graph.js → graph/check-graph.js} +6 -6
  48. package/lib/graph/directive-diagnostics.d.ts +20 -0
  49. package/lib/{directive-diagnostics.js → graph/directive-diagnostics.js} +2 -2
  50. package/lib/graph/directive-type-rules.d.ts +18 -0
  51. package/lib/{directive-type-rules.js → graph/directive-type-rules.js} +3 -3
  52. package/lib/{document-node-identity.d.ts → graph/document-node-identity.d.ts} +2 -2
  53. package/lib/{document-node-identity.js → graph/document-node-identity.js} +2 -2
  54. package/lib/graph/inspect-reverse-references.d.ts +22 -0
  55. package/lib/{inspect-reverse-references.js → graph/inspect-reverse-references.js} +2 -2
  56. package/lib/{load-project-graph.d.ts → graph/load-project-graph.d.ts} +10 -10
  57. package/lib/{load-project-graph.js → graph/load-project-graph.js} +12 -12
  58. package/lib/{parse-where-clause.types.d.ts → graph/parse-where-clause.types.d.ts} +1 -1
  59. package/lib/{query-graph.d.ts → graph/query/execute.d.ts} +11 -11
  60. package/lib/{query-graph.js → graph/query/execute.js} +12 -12
  61. package/lib/{query-inspection.d.ts → graph/query/inspect.d.ts} +10 -8
  62. package/lib/{query-inspection.js → graph/query/inspect.js} +16 -17
  63. package/lib/{parse-where-clause.d.ts → graph/query/parse.d.ts} +6 -6
  64. package/lib/{parse-where-clause.js → graph/query/parse.js} +2 -2
  65. package/lib/graph/query/resolve.d.ts +30 -0
  66. package/lib/{resolve-where-clause.js → graph/query/resolve.js} +1 -1
  67. package/lib/graph/reverse-reference-test-helpers.d.ts +55 -0
  68. package/lib/{command-output.js → output/command-output.js} +5 -5
  69. package/lib/{derived-summary.js → output/derived-summary.js} +7 -7
  70. package/lib/{layout-incoming-references.js → output/layout-incoming-references.js} +4 -4
  71. package/lib/{layout-incoming-summary-lines.js → output/layout-incoming-summary-lines.js} +0 -5
  72. package/lib/{layout-stored-queries.js → output/layout-stored-queries.js} +9 -9
  73. package/lib/{list-queries.js → output/list-queries.js} +1 -1
  74. package/lib/{render-check-output.js → output/render-check-output.js} +1 -1
  75. package/lib/{render-field-discovery.js → output/render-field-discovery.js} +3 -3
  76. package/lib/output/render-output-view.js +56 -0
  77. package/lib/{render-json-output.js → output/renderers/json.js} +1 -1
  78. package/lib/{render-plain-output.js → output/renderers/plain.js} +19 -7
  79. package/lib/{render-rich-output.js → output/renderers/rich.js} +29 -13
  80. package/lib/{resolve-check-target.js → output/resolve-check-target.js} +1 -1
  81. package/lib/{render-rich-source.js → output/rich-source/render.js} +6 -6
  82. package/lib/{show-document.js → output/show-document.js} +12 -12
  83. package/lib/{render-output-view.js → output/view-model/index.js} +6 -52
  84. package/lib/{write-paged-output.js → output/write-paged-output.js} +9 -5
  85. package/lib/{claim-helpers.d.ts → parse/claim-helpers.d.ts} +2 -2
  86. package/lib/{parse-jsdoc-claims.d.ts → parse/jsdoc/parse-jsdoc-claims.d.ts} +2 -2
  87. package/lib/{parse-jsdoc-claims.js → parse/jsdoc/parse-jsdoc-claims.js} +9 -9
  88. package/lib/{parse-jsdoc-prose.d.ts → parse/jsdoc/parse-jsdoc-prose.d.ts} +1 -1
  89. package/lib/{parse-jsdoc-prose.js → parse/jsdoc/parse-jsdoc-prose.js} +1 -1
  90. package/lib/{parse-markdown-claims.d.ts → parse/markdown/parse-markdown-claims.d.ts} +3 -3
  91. package/lib/{parse-markdown-claims.js → parse/markdown/parse-markdown-claims.js} +8 -8
  92. package/lib/{parse-markdown-directives.d.ts → parse/markdown/parse-markdown-directives.d.ts} +2 -2
  93. package/lib/{parse-markdown-directives.js → parse/markdown/parse-markdown-directives.js} +3 -3
  94. package/lib/{parse-claims.d.ts → parse/parse-claims.d.ts} +4 -13
  95. package/lib/{parse-claims.js → parse/parse-claims.js} +18 -26
  96. package/lib/{parse-claims.types.d.ts → parse/parse-claims.types.d.ts} +1 -1
  97. package/lib/{tagged-fenced-block-error.d.ts → parse/tagged-fenced/tagged-fenced-block-error.d.ts} +2 -2
  98. package/lib/{tagged-fenced-block-parser.d.ts → parse/tagged-fenced/tagged-fenced-block-parser.d.ts} +3 -3
  99. package/lib/{tagged-fenced-blocks.d.ts → parse/tagged-fenced/tagged-fenced-blocks.d.ts} +7 -7
  100. package/lib/{tagged-fenced-blocks.js → parse/tagged-fenced/tagged-fenced-blocks.js} +3 -3
  101. package/lib/{parse-yaml-claims.d.ts → parse/yaml/parse-yaml-claims.d.ts} +4 -4
  102. package/lib/{parse-yaml-claims.js → parse/yaml/parse-yaml-claims.js} +22 -13
  103. package/lib/patram.d.ts +29 -28
  104. package/lib/patram.js +5 -6
  105. package/lib/{discover-fields.js → scan/discover-fields.js} +9 -8
  106. package/lib/scan/list-repo-files.d.ts +16 -0
  107. package/lib/{list-source-files.js → scan/list-repo-files.js} +2 -35
  108. package/lib/{list-source-files.d.ts → scan/list-source-files.d.ts} +4 -11
  109. package/lib/scan/list-source-files.js +45 -0
  110. package/package.json +8 -7
  111. package/lib/build-graph.types.ts +0 -27
  112. package/lib/discover-fields.types.ts +0 -52
  113. package/lib/load-patram-config.js +0 -1215
  114. package/lib/load-patram-config.types.d.ts +0 -45
  115. package/lib/load-patram-config.types.ts +0 -56
  116. package/lib/output-view.types.d.ts +0 -88
  117. package/lib/output-view.types.ts +0 -113
  118. package/lib/overlay-graph.d.ts +0 -43
  119. package/lib/overlay-graph.js +0 -191
  120. package/lib/parse-claims.types.ts +0 -41
  121. package/lib/parse-cli-arguments.types.ts +0 -75
  122. package/lib/parse-where-clause.types.ts +0 -87
  123. package/lib/patram-cli.js +0 -593
  124. package/lib/patram-config.types.ts +0 -22
  125. package/lib/tagged-fenced-blocks.types.ts +0 -38
  126. /package/lib/{reverse-reference-test-helpers.js → graph/reverse-reference-test-helpers.js} +0 -0
  127. /package/lib/{format-derived-summary-row.js → output/format-derived-summary-row.js} +0 -0
  128. /package/lib/{format-node-header.js → output/format-node-header.js} +0 -0
  129. /package/lib/{format-output-item-block.js → output/format-output-item-block.js} +0 -0
  130. /package/lib/{format-output-metadata.js → output/format-output-metadata.js} +0 -0
  131. /package/lib/{claim-helpers.js → parse/claim-helpers.js} +0 -0
  132. /package/lib/{parse-jsdoc-blocks.d.ts → parse/jsdoc/parse-jsdoc-blocks.d.ts} +0 -0
  133. /package/lib/{parse-jsdoc-blocks.js → parse/jsdoc/parse-jsdoc-blocks.js} +0 -0
  134. /package/lib/{tagged-fenced-block-error.js → parse/tagged-fenced/tagged-fenced-block-error.js} +0 -0
  135. /package/lib/{tagged-fenced-block-markdown.d.ts → parse/tagged-fenced/tagged-fenced-block-markdown.d.ts} +0 -0
  136. /package/lib/{tagged-fenced-block-markdown.js → parse/tagged-fenced/tagged-fenced-block-markdown.js} +0 -0
  137. /package/lib/{tagged-fenced-block-metadata.d.ts → parse/tagged-fenced/tagged-fenced-block-metadata.d.ts} +0 -0
  138. /package/lib/{tagged-fenced-block-metadata.js → parse/tagged-fenced/tagged-fenced-block-metadata.js} +0 -0
  139. /package/lib/{tagged-fenced-block-parser.js → parse/tagged-fenced/tagged-fenced-block-parser.js} +0 -0
  140. /package/lib/{tagged-fenced-blocks.types.d.ts → parse/tagged-fenced/tagged-fenced-blocks.types.d.ts} +0 -0
package/bin/patram.js CHANGED
@@ -4,7 +4,7 @@ import { realpath } from 'node:fs/promises';
4
4
  import process from 'node:process';
5
5
  import { fileURLToPath } from 'node:url';
6
6
 
7
- import { main } from '../lib/patram-cli.js';
7
+ import { main } from '../lib/cli/main.js';
8
8
 
9
9
  /**
10
10
  * Patram CLI entrypoint.
@@ -17,7 +17,7 @@ import { main } from '../lib/patram-cli.js';
17
17
  * Tracked in: ../docs/plans/v0/source-anchor-dogfooding.md
18
18
  * Decided by: ../docs/decisions/cli-entrypoint-symlink.md
19
19
  * @patram
20
- * @see {@link ../lib/patram-cli.js}
20
+ * @see {@link ../lib/cli/main.js}
21
21
  * @see {@link ../docs/patram.md}
22
22
  */
23
23
 
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @typedef {import('./parse-cli-arguments-helpers.js').CliOptionToken} CliOptionToken
3
- * @typedef {import('./parse-cli-arguments.types.ts').CliColorMode} CliColorMode
2
+ * @typedef {import('./parse-arguments-helpers.js').CliOptionToken} CliOptionToken
3
+ * @typedef {import('./arguments.types.ts').CliColorMode} CliColorMode
4
4
  */
5
5
 
6
6
  const VALID_COLOR_MODES = new Set(['auto', 'always', 'never']);
@@ -0,0 +1,35 @@
1
+ /** @import * as $k$$k$$l$output$l$output$j$view$k$types$k$ts from '../output/output-view.types.ts'; */
2
+ import process from 'node:process';
3
+
4
+ import { resolveOutputMode } from './resolve-output-mode.js';
5
+
6
+ /**
7
+ * @param {import('./arguments.types.ts').ParsedCliCommandRequest} parsed_command
8
+ * @param {{ stdout: { isTTY?: boolean } }} io_context
9
+ * @returns {$k$$k$$l$output$l$output$j$view$k$types$k$ts.ResolvedOutputMode}
10
+ */
11
+ export function resolveCommandOutputMode(parsed_command, io_context) {
12
+ return resolveOutputMode(parsed_command, {
13
+ is_tty: io_context.stdout.isTTY === true,
14
+ no_color: process.env.NO_COLOR !== undefined,
15
+ term: process.env.TERM,
16
+ });
17
+ }
18
+
19
+ /**
20
+ * @param {{ write(chunk: string): boolean }} output_stream
21
+ * @param {import('../config/load-patram-config.types.ts').PatramDiagnostic[]} diagnostics
22
+ */
23
+ export function writeDiagnostics(output_stream, diagnostics) {
24
+ for (const diagnostic of diagnostics) {
25
+ output_stream.write(formatDiagnostic(diagnostic));
26
+ }
27
+ }
28
+
29
+ /**
30
+ * @param {import('../config/load-patram-config.types.ts').PatramDiagnostic} diagnostic
31
+ * @returns {string}
32
+ */
33
+ function formatDiagnostic(diagnostic) {
34
+ return `${diagnostic.path}:${diagnostic.line}:${diagnostic.column} ${diagnostic.level} ${diagnostic.code} ${diagnostic.message}\n`;
35
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @import { ParsedCliCommandRequest } from '../arguments.types.ts';
3
+ */
4
+
5
+ import { checkGraph } from '../../graph/check-graph.js';
6
+ import { loadProjectGraph } from '../../graph/load-project-graph.js';
7
+ import {
8
+ renderCheckDiagnostics,
9
+ renderCheckSuccess,
10
+ } from '../../output/render-check-output.js';
11
+ import {
12
+ resolveCheckTarget,
13
+ selectCheckTargetDiagnostics,
14
+ selectCheckTargetSourceFiles,
15
+ } from '../../output/resolve-check-target.js';
16
+ import { listRepoFiles } from '../../scan/list-repo-files.js';
17
+
18
+ import { resolveCommandOutputMode } from '../command-helpers.js';
19
+
20
+ /**
21
+ * @param {ParsedCliCommandRequest} parsed_command
22
+ * @param {{ stderr: { write(chunk: string): boolean }, stdout: { isTTY?: boolean, write(chunk: string): boolean }, write_paged_output?: (output_text: string) => Promise<void> }} io_context
23
+ * @returns {Promise<number>}
24
+ */
25
+ export async function runCheckCommand(parsed_command, io_context) {
26
+ const output_mode = resolveCommandOutputMode(parsed_command, io_context);
27
+ const resolved_target = await resolveCheckTarget(
28
+ parsed_command.command_arguments[0],
29
+ );
30
+ const project_graph_result = await loadProjectGraph(
31
+ resolved_target.project_directory,
32
+ );
33
+ const repo_file_paths = await listRepoFiles(
34
+ resolved_target.project_directory,
35
+ );
36
+ const selected_source_file_paths = selectCheckTargetSourceFiles(
37
+ project_graph_result.source_file_paths,
38
+ resolved_target,
39
+ );
40
+
41
+ if (project_graph_result.diagnostics.length > 0) {
42
+ io_context.stderr.write(
43
+ renderCheckDiagnostics(project_graph_result.diagnostics, output_mode),
44
+ );
45
+
46
+ return 1;
47
+ }
48
+
49
+ const diagnostics = checkGraph(
50
+ project_graph_result.graph,
51
+ repo_file_paths,
52
+ project_graph_result.config,
53
+ project_graph_result.claims,
54
+ );
55
+ const selected_diagnostics = selectCheckTargetDiagnostics(
56
+ diagnostics,
57
+ resolved_target,
58
+ );
59
+
60
+ if (selected_diagnostics.length > 0) {
61
+ io_context.stderr.write(
62
+ renderCheckDiagnostics(selected_diagnostics, output_mode),
63
+ );
64
+
65
+ return 1;
66
+ }
67
+
68
+ io_context.stdout.write(
69
+ renderCheckSuccess(selected_source_file_paths.length, output_mode),
70
+ );
71
+
72
+ return 0;
73
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @import { ParsedCliCommandRequest } from '../arguments.types.ts';
3
+ * @import { PatramRepoConfig } from '../../config/load-patram-config.types.ts';
4
+ */
5
+
6
+ import process from 'node:process';
7
+
8
+ import { loadPatramConfig } from '../../config/load-patram-config.js';
9
+ import { writeRenderedCommandOutput } from '../../output/command-output.js';
10
+ import { renderFieldDiscovery } from '../../output/render-field-discovery.js';
11
+ import { discoverFields } from '../../scan/discover-fields.js';
12
+
13
+ import { resolveCommandOutputMode } from '../command-helpers.js';
14
+
15
+ /**
16
+ * @param {ParsedCliCommandRequest} parsed_command
17
+ * @param {{ stderr: { write(chunk: string): boolean }, stdout: { isTTY?: boolean, write(chunk: string): boolean } }} io_context
18
+ * @returns {Promise<number>}
19
+ */
20
+ export async function runFieldsCommand(parsed_command, io_context) {
21
+ const output_mode = resolveCommandOutputMode(parsed_command, io_context);
22
+ const load_result = await loadPatramConfig(process.cwd());
23
+ const defined_field_names =
24
+ load_result.diagnostics.length === 0
25
+ ? collectDefinedDiscoveryNames(load_result.config)
26
+ : new Set();
27
+ const discovery_result = await discoverFields(process.cwd(), {
28
+ defined_field_names,
29
+ });
30
+
31
+ await writeRenderedCommandOutput(
32
+ io_context,
33
+ parsed_command,
34
+ renderFieldDiscovery(discovery_result, output_mode),
35
+ );
36
+
37
+ return 0;
38
+ }
39
+
40
+ /**
41
+ * @param {PatramRepoConfig | null} repo_config
42
+ * @returns {Set<string>}
43
+ */
44
+ function collectDefinedDiscoveryNames(repo_config) {
45
+ /** @type {Set<string>} */
46
+ const defined_field_names = new Set();
47
+
48
+ for (const field_name of Object.keys(repo_config?.fields ?? {})) {
49
+ defined_field_names.add(field_name);
50
+ }
51
+
52
+ for (const relation_name of Object.keys(repo_config?.relations ?? {})) {
53
+ defined_field_names.add(relation_name);
54
+ }
55
+
56
+ return defined_field_names;
57
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * @import { ParsedCliCommandRequest } from '../arguments.types.ts';
3
+ */
4
+
5
+ import process from 'node:process';
6
+
7
+ import { loadPatramConfig } from '../../config/load-patram-config.js';
8
+ import { writeCommandOutput } from '../../output/command-output.js';
9
+ import { listQueries } from '../../output/list-queries.js';
10
+ import { createOutputView } from '../../output/render-output-view.js';
11
+
12
+ import { writeDiagnostics } from '../command-helpers.js';
13
+
14
+ /**
15
+ * @param {ParsedCliCommandRequest} parsed_command
16
+ * @param {{ stderr: { write(chunk: string): boolean }, stdout: { isTTY?: boolean, write(chunk: string): boolean }, write_paged_output?: (output_text: string) => Promise<void> }} io_context
17
+ * @returns {Promise<number>}
18
+ */
19
+ export async function runQueriesCommand(parsed_command, io_context) {
20
+ const load_result = await loadPatramConfig(process.cwd());
21
+
22
+ if (load_result.diagnostics.length > 0) {
23
+ writeDiagnostics(io_context.stderr, load_result.diagnostics);
24
+
25
+ return 1;
26
+ }
27
+
28
+ const repo_config = load_result.config;
29
+
30
+ if (!repo_config) {
31
+ throw new Error('Expected a valid Patram repo config.');
32
+ }
33
+
34
+ await writeCommandOutput(
35
+ io_context,
36
+ parsed_command,
37
+ createOutputView('queries', listQueries(repo_config.queries)),
38
+ );
39
+
40
+ return 0;
41
+ }
@@ -0,0 +1,239 @@
1
+ /**
2
+ * @import { ParsedCliCommandRequest } from '../arguments.types.ts';
3
+ * @import { GraphNode } from '../../graph/build-graph.types.ts';
4
+ * @import { ResolvedOutputMode } from '../../output/output-view.types.ts';
5
+ */
6
+
7
+ import process from 'node:process';
8
+
9
+ import {
10
+ shouldPageCommandOutput,
11
+ writeCommandOutput,
12
+ } from '../../output/command-output.js';
13
+ import { createDerivedSummaryEvaluator } from '../../output/derived-summary.js';
14
+ import { renderCheckDiagnostics } from '../../output/render-check-output.js';
15
+ import { renderInvalidWhereDiagnostic } from '../render-help.js';
16
+ import { createOutputView } from '../../output/render-output-view.js';
17
+ import { loadPatramConfig } from '../../config/load-patram-config.js';
18
+ import { loadProjectGraph } from '../../graph/load-project-graph.js';
19
+ import { DEFAULT_QUERY_LIMIT, queryGraph } from '../../graph/query/execute.js';
20
+ import {
21
+ inspectQuery,
22
+ renderQueryInspection,
23
+ } from '../../graph/query/inspect.js';
24
+ import { resolveWhereClause } from '../../graph/query/resolve.js';
25
+
26
+ import {
27
+ resolveCommandOutputMode,
28
+ writeDiagnostics,
29
+ } from '../command-helpers.js';
30
+
31
+ /**
32
+ * @param {ParsedCliCommandRequest} parsed_command
33
+ * @param {{ stderr: { write(chunk: string): boolean }, stdout: { isTTY?: boolean, write(chunk: string): boolean }, write_paged_output?: (output_text: string) => Promise<void> }} io_context
34
+ * @returns {Promise<number>}
35
+ */
36
+ export async function runQueryCommand(parsed_command, io_context) {
37
+ const use_pager = shouldPageCommandOutput(parsed_command, io_context.stdout);
38
+ const output_mode = resolveCommandOutputMode(parsed_command, io_context);
39
+
40
+ if (parsed_command.query_inspection_mode) {
41
+ return runQueryInspectionCommand(
42
+ parsed_command,
43
+ io_context,
44
+ output_mode,
45
+ use_pager,
46
+ );
47
+ }
48
+
49
+ const project_graph_result = await loadProjectGraph(process.cwd());
50
+
51
+ if (project_graph_result.diagnostics.length > 0) {
52
+ writeDiagnostics(io_context.stderr, project_graph_result.diagnostics);
53
+
54
+ return 1;
55
+ }
56
+
57
+ const where_clause = resolveWhereClause(
58
+ project_graph_result.config,
59
+ parsed_command.command_arguments,
60
+ );
61
+
62
+ if (!where_clause.success) {
63
+ io_context.stderr.write(`${where_clause.message}\n`);
64
+
65
+ return 1;
66
+ }
67
+
68
+ const query_result = queryGraph(
69
+ project_graph_result.graph,
70
+ where_clause.value.where_clause,
71
+ project_graph_result.config,
72
+ createQueryPaginationOptions(parsed_command, use_pager),
73
+ );
74
+
75
+ if (query_result.diagnostics.length > 0) {
76
+ io_context.stderr.write(
77
+ renderInvalidWhereDiagnostic(query_result.diagnostics[0]),
78
+ );
79
+
80
+ return 1;
81
+ }
82
+
83
+ const derived_summary_evaluator = createDerivedSummaryEvaluator(
84
+ project_graph_result.config,
85
+ project_graph_result.graph,
86
+ );
87
+
88
+ await writeCommandOutput(
89
+ io_context,
90
+ parsed_command,
91
+ createOutputView('query', query_result.nodes, {
92
+ derived_summary_evaluator,
93
+ ...createQueryOutputOptions(parsed_command, query_result, use_pager),
94
+ repo_config: project_graph_result.config,
95
+ }),
96
+ );
97
+
98
+ return 0;
99
+ }
100
+
101
+ /**
102
+ * @param {ParsedCliCommandRequest} parsed_command
103
+ * @param {{ stderr: { write(chunk: string): boolean }, stdout: { isTTY?: boolean, write(chunk: string): boolean } }} io_context
104
+ * @param {ResolvedOutputMode} output_mode
105
+ * @param {boolean} use_pager
106
+ * @returns {Promise<number>}
107
+ */
108
+ async function runQueryInspectionCommand(
109
+ parsed_command,
110
+ io_context,
111
+ output_mode,
112
+ use_pager,
113
+ ) {
114
+ const query_inspection_mode = parsed_command.query_inspection_mode;
115
+
116
+ if (!query_inspection_mode) {
117
+ throw new Error('Expected a query inspection mode.');
118
+ }
119
+
120
+ const load_result = await loadPatramConfig(process.cwd());
121
+
122
+ if (load_result.diagnostics.length > 0) {
123
+ io_context.stderr.write(
124
+ renderCheckDiagnostics(load_result.diagnostics, output_mode),
125
+ );
126
+
127
+ return 1;
128
+ }
129
+
130
+ const repo_config = load_result.config;
131
+
132
+ if (!repo_config) {
133
+ throw new Error('Expected a valid Patram repo config.');
134
+ }
135
+
136
+ const where_clause = resolveWhereClause(
137
+ repo_config,
138
+ parsed_command.command_arguments,
139
+ );
140
+
141
+ if (!where_clause.success) {
142
+ io_context.stderr.write(`${where_clause.message}\n`);
143
+
144
+ return 1;
145
+ }
146
+
147
+ const query_inspection = inspectQuery(repo_config, where_clause.value, {
148
+ inspection_mode: query_inspection_mode,
149
+ ...createQueryExecutionOptions(parsed_command, use_pager),
150
+ });
151
+
152
+ if (!query_inspection.success) {
153
+ io_context.stderr.write(
154
+ renderCheckDiagnostics(query_inspection.diagnostics, output_mode),
155
+ );
156
+
157
+ return 1;
158
+ }
159
+
160
+ io_context.stdout.write(
161
+ renderQueryInspection(query_inspection.value, output_mode),
162
+ );
163
+
164
+ return 0;
165
+ }
166
+
167
+ /**
168
+ * @param {ParsedCliCommandRequest} parsed_command
169
+ * @param {{ total_count: number, nodes: GraphNode[] }} query_result
170
+ * @param {boolean} use_pager
171
+ * @returns {{ hints: string[], limit: number, offset: number, total_count: number }}
172
+ */
173
+ function createQueryOutputOptions(parsed_command, query_result, use_pager) {
174
+ /** @type {string[]} */
175
+ const hints = [];
176
+ const limit =
177
+ parsed_command.query_limit ??
178
+ (use_pager ? query_result.nodes.length : DEFAULT_QUERY_LIMIT);
179
+ const offset = parsed_command.query_offset ?? 0;
180
+
181
+ if (query_result.total_count === 0) {
182
+ hints.push("Try: patram query --where '$class=task'");
183
+ }
184
+
185
+ if (
186
+ !use_pager &&
187
+ parsed_command.query_limit === undefined &&
188
+ parsed_command.query_offset === undefined &&
189
+ query_result.total_count > DEFAULT_QUERY_LIMIT
190
+ ) {
191
+ hints.push(
192
+ 'Hint: use --offset <n> or --limit <n> to page through more matches.',
193
+ );
194
+ }
195
+
196
+ return {
197
+ hints,
198
+ limit,
199
+ offset,
200
+ total_count: query_result.total_count,
201
+ };
202
+ }
203
+
204
+ /**
205
+ * @param {ParsedCliCommandRequest} parsed_command
206
+ * @param {boolean} use_pager
207
+ * @returns {{ limit?: number, offset: number }}
208
+ */
209
+ function createQueryPaginationOptions(parsed_command, use_pager) {
210
+ /** @type {{ limit?: number, offset: number }} */
211
+ const pagination_options = {
212
+ offset: parsed_command.query_offset ?? 0,
213
+ };
214
+
215
+ if (parsed_command.query_limit !== undefined) {
216
+ pagination_options.limit = parsed_command.query_limit;
217
+ } else if (!use_pager) {
218
+ pagination_options.limit = DEFAULT_QUERY_LIMIT;
219
+ }
220
+
221
+ return pagination_options;
222
+ }
223
+
224
+ /**
225
+ * @param {ParsedCliCommandRequest} parsed_command
226
+ * @param {boolean} use_pager
227
+ * @returns {{ limit: number | null, offset: number }}
228
+ */
229
+ function createQueryExecutionOptions(parsed_command, use_pager) {
230
+ const pagination_options = createQueryPaginationOptions(
231
+ parsed_command,
232
+ use_pager,
233
+ );
234
+
235
+ return {
236
+ limit: pagination_options.limit ?? null,
237
+ offset: pagination_options.offset,
238
+ };
239
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * @import { ParsedCliCommandRequest } from '../arguments.types.ts';
3
+ */
4
+
5
+ import process from 'node:process';
6
+
7
+ import { loadProjectGraph } from '../../graph/load-project-graph.js';
8
+ import { inspectReverseReferences } from '../../graph/inspect-reverse-references.js';
9
+ import { writeCommandOutput } from '../../output/command-output.js';
10
+ import { createDerivedSummaryEvaluator } from '../../output/derived-summary.js';
11
+ import { createRefsOutputView } from '../../output/render-output-view.js';
12
+
13
+ import { renderInvalidWhereDiagnostic } from '../render-help.js';
14
+ import { writeDiagnostics } from '../command-helpers.js';
15
+
16
+ /**
17
+ * @param {ParsedCliCommandRequest} parsed_command
18
+ * @param {{ stderr: { write(chunk: string): boolean }, stdout: { isTTY?: boolean, write(chunk: string): boolean }, write_paged_output?: (output_text: string) => Promise<void> }} io_context
19
+ * @returns {Promise<number>}
20
+ */
21
+ export async function runRefsCommand(parsed_command, io_context) {
22
+ const project_graph_result = await loadProjectGraph(process.cwd());
23
+
24
+ if (project_graph_result.diagnostics.length > 0) {
25
+ writeDiagnostics(io_context.stderr, project_graph_result.diagnostics);
26
+
27
+ return 1;
28
+ }
29
+
30
+ const refs_output = inspectReverseReferences(
31
+ project_graph_result.graph,
32
+ parsed_command.command_arguments[0],
33
+ project_graph_result.config,
34
+ resolveRefsWhereClause(parsed_command.command_arguments),
35
+ );
36
+
37
+ if (refs_output.diagnostics.length > 0) {
38
+ io_context.stderr.write(
39
+ renderInvalidWhereDiagnostic(refs_output.diagnostics[0]),
40
+ );
41
+
42
+ return 1;
43
+ }
44
+
45
+ const derived_summary_evaluator = createDerivedSummaryEvaluator(
46
+ project_graph_result.config,
47
+ project_graph_result.graph,
48
+ );
49
+
50
+ await writeCommandOutput(
51
+ io_context,
52
+ parsed_command,
53
+ createRefsOutputView(refs_output, {
54
+ derived_summary_evaluator,
55
+ repo_config: project_graph_result.config,
56
+ }),
57
+ );
58
+
59
+ return 0;
60
+ }
61
+
62
+ /**
63
+ * @param {string[]} command_arguments
64
+ * @returns {string | undefined}
65
+ */
66
+ function resolveRefsWhereClause(command_arguments) {
67
+ if (command_arguments[1] !== '--where') {
68
+ return undefined;
69
+ }
70
+
71
+ return command_arguments.slice(2).join(' ').trim();
72
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @import { ParsedCliCommandRequest } from '../arguments.types.ts';
3
+ */
4
+
5
+ import process from 'node:process';
6
+
7
+ import { loadProjectGraph } from '../../graph/load-project-graph.js';
8
+ import { writeCommandOutput } from '../../output/command-output.js';
9
+ import { createDerivedSummaryEvaluator } from '../../output/derived-summary.js';
10
+ import { createShowOutputView } from '../../output/render-output-view.js';
11
+ import { loadShowOutput } from '../../output/show-document.js';
12
+
13
+ import { writeDiagnostics } from '../command-helpers.js';
14
+
15
+ /**
16
+ * @param {ParsedCliCommandRequest} parsed_command
17
+ * @param {{ stderr: { write(chunk: string): boolean }, stdout: { isTTY?: boolean, write(chunk: string): boolean }, write_paged_output?: (output_text: string) => Promise<void> }} io_context
18
+ * @returns {Promise<number>}
19
+ */
20
+ export async function runShowCommand(parsed_command, io_context) {
21
+ const project_graph_result = await loadProjectGraph(process.cwd());
22
+
23
+ if (project_graph_result.diagnostics.length > 0) {
24
+ writeDiagnostics(io_context.stderr, project_graph_result.diagnostics);
25
+
26
+ return 1;
27
+ }
28
+
29
+ const show_output = await loadShowOutput(
30
+ parsed_command.command_arguments[0],
31
+ process.cwd(),
32
+ project_graph_result.graph,
33
+ );
34
+
35
+ if (!show_output.success) {
36
+ writeDiagnostics(io_context.stderr, [show_output.diagnostic]);
37
+
38
+ return 1;
39
+ }
40
+
41
+ const derived_summary_evaluator = createDerivedSummaryEvaluator(
42
+ project_graph_result.config,
43
+ project_graph_result.graph,
44
+ );
45
+
46
+ await writeCommandOutput(
47
+ io_context,
48
+ parsed_command,
49
+ createShowOutputView(show_output.value, {
50
+ derived_summary_evaluator,
51
+ document_node_ids: project_graph_result.graph.document_node_ids,
52
+ graph_nodes: project_graph_result.graph.nodes,
53
+ repo_config: project_graph_result.config,
54
+ }),
55
+ );
56
+
57
+ return 0;
58
+ }
@@ -3,7 +3,7 @@
3
3
  * @import {
4
4
  * CliCommandName,
5
5
  * CliHelpTopicName,
6
- * } from './parse-cli-arguments.types.ts';
6
+ * } from './arguments.types.ts';
7
7
  */
8
8
 
9
9
  /**
@@ -45,7 +45,7 @@
45
45
  * }} CliHelpTopicDefinition
46
46
  */
47
47
 
48
- export const COMMAND_NAMES = /** @type {const} */ ([
48
+ const COMMAND_NAMES = /** @type {const} */ ([
49
49
  'check',
50
50
  'fields',
51
51
  'query',
@@ -54,7 +54,7 @@ export const COMMAND_NAMES = /** @type {const} */ ([
54
54
  'show',
55
55
  ]);
56
56
 
57
- export const HELP_TOPIC_NAMES = /** @type {const} */ (['query-language']);
57
+ const HELP_TOPIC_NAMES = /** @type {const} */ (['query-language']);
58
58
 
59
59
  export const GLOBAL_OPTION_NAMES = new Set([
60
60
  'help',
@@ -284,14 +284,14 @@ const COMMAND_DEFINITIONS = {
284
284
  },
285
285
  show: {
286
286
  allowed_option_names: new Set(),
287
- examples: ['patram show docs/patram.md', 'patram show lib/patram-cli.js'],
287
+ examples: ['patram show docs/patram.md', 'patram show lib/cli/main.js'],
288
288
  extra_positionals_message: 'Show accepts exactly one file path.',
289
289
  help_topics: [],
290
290
  max_positionals: 1,
291
291
  min_positionals: 1,
292
292
  missing_argument_examples: [
293
293
  'patram show docs/patram.md',
294
- 'patram show lib/patram-cli.js',
294
+ 'patram show lib/cli/main.js',
295
295
  ],
296
296
  missing_argument_label: '<file>',
297
297
  missing_usage_lines: ['patram show <file>'],
@@ -583,7 +583,7 @@ function scoreCandidate(input_text, candidate) {
583
583
  function calculateDamerauLevenshteinDistance(left_text, right_text) {
584
584
  /** @type {number[][]} */
585
585
  const matrix = Array.from({ length: left_text.length + 1 }, () =>
586
- Array(right_text.length + 1).fill(0),
586
+ Array.from({ length: right_text.length + 1 }, () => 0),
587
587
  );
588
588
 
589
589
  for (let left_index = 0; left_index <= left_text.length; left_index += 1) {