patram 0.7.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} +54 -15
  11. package/lib/cli/main.js +76 -0
  12. package/lib/{parse-cli-arguments-helpers.js → cli/parse-arguments-helpers.js} +18 -11
  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} +4 -4
  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/graph/inspect-reverse-references.js +184 -0
  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/graph/reverse-reference-test-helpers.js +76 -0
  69. package/lib/{command-output.js → output/command-output.js} +6 -5
  70. package/lib/{derived-summary.js → output/derived-summary.js} +7 -7
  71. package/lib/output/layout-incoming-references.js +105 -0
  72. package/lib/output/layout-incoming-summary-lines.js +16 -0
  73. package/lib/{layout-stored-queries.js → output/layout-stored-queries.js} +9 -9
  74. package/lib/{list-queries.js → output/list-queries.js} +1 -1
  75. package/lib/{render-check-output.js → output/render-check-output.js} +1 -1
  76. package/lib/{render-field-discovery.js → output/render-field-discovery.js} +3 -3
  77. package/lib/output/render-output-view.js +56 -0
  78. package/lib/{render-json-output.js → output/renderers/json.js} +92 -63
  79. package/lib/{render-plain-output.js → output/renderers/plain.js} +62 -7
  80. package/lib/{render-rich-output.js → output/renderers/rich.js} +69 -8
  81. package/lib/{resolve-check-target.js → output/resolve-check-target.js} +1 -1
  82. package/lib/{render-rich-source.js → output/rich-source/render.js} +6 -6
  83. package/lib/{show-document.js → output/show-document.js} +54 -16
  84. package/lib/{render-output-view.js → output/view-model/index.js} +56 -47
  85. package/lib/{write-paged-output.js → output/write-paged-output.js} +9 -5
  86. package/lib/{claim-helpers.d.ts → parse/claim-helpers.d.ts} +2 -2
  87. package/lib/{parse-jsdoc-claims.d.ts → parse/jsdoc/parse-jsdoc-claims.d.ts} +2 -2
  88. package/lib/{parse-jsdoc-claims.js → parse/jsdoc/parse-jsdoc-claims.js} +9 -9
  89. package/lib/{parse-jsdoc-prose.d.ts → parse/jsdoc/parse-jsdoc-prose.d.ts} +1 -1
  90. package/lib/{parse-jsdoc-prose.js → parse/jsdoc/parse-jsdoc-prose.js} +1 -1
  91. package/lib/{parse-markdown-claims.d.ts → parse/markdown/parse-markdown-claims.d.ts} +3 -3
  92. package/lib/{parse-markdown-claims.js → parse/markdown/parse-markdown-claims.js} +8 -8
  93. package/lib/{parse-markdown-directives.d.ts → parse/markdown/parse-markdown-directives.d.ts} +2 -2
  94. package/lib/{parse-markdown-directives.js → parse/markdown/parse-markdown-directives.js} +3 -3
  95. package/lib/{parse-claims.d.ts → parse/parse-claims.d.ts} +4 -13
  96. package/lib/{parse-claims.js → parse/parse-claims.js} +18 -26
  97. package/lib/{parse-claims.types.d.ts → parse/parse-claims.types.d.ts} +1 -1
  98. package/lib/{tagged-fenced-block-error.d.ts → parse/tagged-fenced/tagged-fenced-block-error.d.ts} +2 -2
  99. package/lib/{tagged-fenced-block-parser.d.ts → parse/tagged-fenced/tagged-fenced-block-parser.d.ts} +3 -3
  100. package/lib/{tagged-fenced-blocks.d.ts → parse/tagged-fenced/tagged-fenced-blocks.d.ts} +7 -7
  101. package/lib/{tagged-fenced-blocks.js → parse/tagged-fenced/tagged-fenced-blocks.js} +3 -3
  102. package/lib/{parse-yaml-claims.d.ts → parse/yaml/parse-yaml-claims.d.ts} +4 -4
  103. package/lib/{parse-yaml-claims.js → parse/yaml/parse-yaml-claims.js} +22 -13
  104. package/lib/patram.d.ts +29 -28
  105. package/lib/patram.js +5 -6
  106. package/lib/{discover-fields.js → scan/discover-fields.js} +9 -8
  107. package/lib/scan/list-repo-files.d.ts +16 -0
  108. package/lib/{list-source-files.js → scan/list-repo-files.js} +2 -35
  109. package/lib/{list-source-files.d.ts → scan/list-source-files.d.ts} +4 -11
  110. package/lib/scan/list-source-files.js +45 -0
  111. package/package.json +8 -7
  112. package/lib/build-graph.types.ts +0 -27
  113. package/lib/discover-fields.types.ts +0 -52
  114. package/lib/load-patram-config.js +0 -1215
  115. package/lib/load-patram-config.types.d.ts +0 -45
  116. package/lib/load-patram-config.types.ts +0 -56
  117. package/lib/output-view.types.d.ts +0 -80
  118. package/lib/output-view.types.ts +0 -96
  119. package/lib/overlay-graph.d.ts +0 -43
  120. package/lib/overlay-graph.js +0 -191
  121. package/lib/parse-claims.types.ts +0 -41
  122. package/lib/parse-cli-arguments.types.ts +0 -69
  123. package/lib/parse-where-clause.types.ts +0 -87
  124. package/lib/patram-cli.js +0 -528
  125. package/lib/patram-config.types.ts +0 -22
  126. package/lib/tagged-fenced-blocks.types.ts +0 -38
  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
+ }