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.
Files changed (143) hide show
  1. package/bin/patram.js +2 -2
  2. package/lib/cli/arguments.types.d.ts +63 -0
  3. package/lib/{parse-cli-color-options.js → cli/color-options.js} +2 -2
  4. package/lib/cli/command-helpers.js +35 -0
  5. package/lib/cli/commands/check.js +73 -0
  6. package/lib/cli/commands/fields.js +57 -0
  7. package/lib/cli/commands/queries.js +41 -0
  8. package/lib/cli/commands/query.js +242 -0
  9. package/lib/cli/commands/refs.js +72 -0
  10. package/lib/cli/commands/show.js +58 -0
  11. package/lib/{cli-help-metadata.js → cli/help-metadata.js} +7 -102
  12. package/lib/cli/main.js +76 -0
  13. package/lib/{parse-cli-arguments-helpers.js → cli/parse-arguments-helpers.js} +24 -12
  14. package/lib/{parse-cli-arguments.js → cli/parse-arguments.js} +12 -12
  15. package/lib/{parse-cli-query-pagination.js → cli/query-pagination.js} +2 -2
  16. package/lib/{render-cli-help.js → cli/render-help.js} +84 -3
  17. package/lib/{resolve-output-mode.js → cli/resolve-output-mode.js} +2 -2
  18. package/lib/cli/test-helpers.js +30 -0
  19. package/lib/config/defaults.d.ts +10 -0
  20. package/lib/config/defaults.js +80 -0
  21. package/lib/config/load-patram-config.d.ts +76 -0
  22. package/lib/config/load-patram-config.js +315 -0
  23. package/lib/config/load-patram-config.types.d.ts +45 -0
  24. package/lib/{patram-config.d.ts → config/patram-config.d.ts} +31 -31
  25. package/lib/{patram-config.js → config/patram-config.js} +3 -3
  26. package/lib/{patram-config.types.d.ts → config/patram-config.types.d.ts} +1 -1
  27. package/lib/{resolve-patram-graph-config.d.ts → config/resolve-patram-graph-config.d.ts} +2 -2
  28. package/lib/{resolve-patram-graph-config.js → config/resolve-patram-graph-config.js} +3 -3
  29. package/lib/{load-patram-config.d.ts → config/schema.d.ts} +149 -191
  30. package/lib/config/schema.js +328 -0
  31. package/lib/{source-file-defaults.d.ts → config/source-file-defaults.d.ts} +0 -1
  32. package/lib/{source-file-defaults.js → config/source-file-defaults.js} +1 -1
  33. package/lib/config/validation.d.ts +27 -0
  34. package/lib/config/validation.js +615 -0
  35. package/lib/directive-validation-test-helpers.js +1 -1
  36. package/lib/find-close-match.d.ts +8 -0
  37. package/lib/find-close-match.js +98 -0
  38. package/lib/{build-graph-identity.d.ts → graph/build-graph-identity.d.ts} +2 -2
  39. package/lib/{build-graph-identity.js → graph/build-graph-identity.js} +1 -1
  40. package/lib/{build-graph.d.ts → graph/build-graph.d.ts} +3 -3
  41. package/lib/{build-graph.js → graph/build-graph.js} +17 -13
  42. package/lib/{build-graph.types.d.ts → graph/build-graph.types.d.ts} +1 -1
  43. package/lib/graph/check-directive-metadata.d.ts +23 -0
  44. package/lib/{check-directive-metadata.js → graph/check-directive-metadata.js} +7 -7
  45. package/lib/graph/check-directive-path-target.d.ts +32 -0
  46. package/lib/{check-directive-path-target.js → graph/check-directive-path-target.js} +4 -4
  47. package/lib/graph/check-directive-value.d.ts +19 -0
  48. package/lib/{check-directive-value.js → graph/check-directive-value.js} +3 -3
  49. package/lib/graph/check-graph.d.ts +29 -0
  50. package/lib/{check-graph.js → graph/check-graph.js} +6 -6
  51. package/lib/graph/directive-diagnostics.d.ts +20 -0
  52. package/lib/{directive-diagnostics.js → graph/directive-diagnostics.js} +2 -2
  53. package/lib/graph/directive-type-rules.d.ts +18 -0
  54. package/lib/{directive-type-rules.js → graph/directive-type-rules.js} +3 -3
  55. package/lib/{document-node-identity.d.ts → graph/document-node-identity.d.ts} +2 -2
  56. package/lib/{document-node-identity.js → graph/document-node-identity.js} +2 -2
  57. package/lib/graph/inspect-reverse-references.d.ts +22 -0
  58. package/lib/{inspect-reverse-references.js → graph/inspect-reverse-references.js} +2 -2
  59. package/lib/{load-project-graph.d.ts → graph/load-project-graph.d.ts} +10 -10
  60. package/lib/{load-project-graph.js → graph/load-project-graph.js} +12 -12
  61. package/lib/{parse-where-clause.types.d.ts → graph/parse-where-clause.types.d.ts} +1 -1
  62. package/lib/{query-graph.d.ts → graph/query/execute.d.ts} +11 -11
  63. package/lib/{query-graph.js → graph/query/execute.js} +12 -12
  64. package/lib/{query-inspection.d.ts → graph/query/inspect.d.ts} +10 -8
  65. package/lib/{query-inspection.js → graph/query/inspect.js} +16 -17
  66. package/lib/{parse-where-clause.d.ts → graph/query/parse.d.ts} +6 -6
  67. package/lib/{parse-where-clause.js → graph/query/parse.js} +2 -2
  68. package/lib/graph/query/resolve.d.ts +28 -0
  69. package/lib/{resolve-where-clause.js → graph/query/resolve.js} +39 -5
  70. package/lib/graph/reverse-reference-test-helpers.d.ts +55 -0
  71. package/lib/{command-output.js → output/command-output.js} +5 -5
  72. package/lib/{derived-summary.js → output/derived-summary.js} +7 -7
  73. package/lib/{layout-incoming-references.js → output/layout-incoming-references.js} +4 -4
  74. package/lib/{layout-incoming-summary-lines.js → output/layout-incoming-summary-lines.js} +0 -5
  75. package/lib/{layout-stored-queries.js → output/layout-stored-queries.js} +27 -11
  76. package/lib/{list-queries.js → output/list-queries.js} +3 -2
  77. package/lib/{render-check-output.js → output/render-check-output.js} +1 -1
  78. package/lib/{render-field-discovery.js → output/render-field-discovery.js} +3 -3
  79. package/lib/output/render-output-view.js +56 -0
  80. package/lib/{render-json-output.js → output/renderers/json.js} +10 -6
  81. package/lib/{render-plain-output.js → output/renderers/plain.js} +34 -33
  82. package/lib/{render-rich-output.js → output/renderers/rich.js} +44 -32
  83. package/lib/{resolve-check-target.js → output/resolve-check-target.js} +1 -1
  84. package/lib/{render-rich-source.js → output/rich-source/render.js} +6 -6
  85. package/lib/{show-document.js → output/show-document.js} +12 -12
  86. package/lib/{render-output-view.js → output/view-model/index.js} +11 -70
  87. package/lib/{write-paged-output.js → output/write-paged-output.js} +9 -5
  88. package/lib/{claim-helpers.d.ts → parse/claim-helpers.d.ts} +2 -2
  89. package/lib/{parse-jsdoc-claims.d.ts → parse/jsdoc/parse-jsdoc-claims.d.ts} +2 -2
  90. package/lib/{parse-jsdoc-claims.js → parse/jsdoc/parse-jsdoc-claims.js} +9 -9
  91. package/lib/{parse-jsdoc-prose.d.ts → parse/jsdoc/parse-jsdoc-prose.d.ts} +1 -1
  92. package/lib/{parse-jsdoc-prose.js → parse/jsdoc/parse-jsdoc-prose.js} +1 -1
  93. package/lib/{parse-markdown-claims.d.ts → parse/markdown/parse-markdown-claims.d.ts} +3 -3
  94. package/lib/{parse-markdown-claims.js → parse/markdown/parse-markdown-claims.js} +8 -8
  95. package/lib/{parse-markdown-directives.d.ts → parse/markdown/parse-markdown-directives.d.ts} +2 -2
  96. package/lib/{parse-markdown-directives.js → parse/markdown/parse-markdown-directives.js} +3 -3
  97. package/lib/{parse-claims.d.ts → parse/parse-claims.d.ts} +4 -13
  98. package/lib/{parse-claims.js → parse/parse-claims.js} +18 -26
  99. package/lib/{parse-claims.types.d.ts → parse/parse-claims.types.d.ts} +1 -1
  100. package/lib/{tagged-fenced-block-error.d.ts → parse/tagged-fenced/tagged-fenced-block-error.d.ts} +2 -2
  101. package/lib/{tagged-fenced-block-parser.d.ts → parse/tagged-fenced/tagged-fenced-block-parser.d.ts} +3 -3
  102. package/lib/{tagged-fenced-blocks.d.ts → parse/tagged-fenced/tagged-fenced-blocks.d.ts} +7 -7
  103. package/lib/{tagged-fenced-blocks.js → parse/tagged-fenced/tagged-fenced-blocks.js} +3 -3
  104. package/lib/{parse-yaml-claims.d.ts → parse/yaml/parse-yaml-claims.d.ts} +4 -4
  105. package/lib/{parse-yaml-claims.js → parse/yaml/parse-yaml-claims.js} +22 -13
  106. package/lib/patram.d.ts +29 -28
  107. package/lib/patram.js +5 -6
  108. package/lib/{discover-fields.js → scan/discover-fields.js} +145 -18
  109. package/lib/scan/list-repo-files.d.ts +16 -0
  110. package/lib/{list-source-files.js → scan/list-repo-files.js} +2 -35
  111. package/lib/{list-source-files.d.ts → scan/list-source-files.d.ts} +4 -11
  112. package/lib/scan/list-source-files.js +45 -0
  113. package/package.json +8 -7
  114. package/lib/build-graph.types.ts +0 -27
  115. package/lib/discover-fields.types.ts +0 -52
  116. package/lib/load-patram-config.js +0 -1215
  117. package/lib/load-patram-config.types.d.ts +0 -45
  118. package/lib/load-patram-config.types.ts +0 -56
  119. package/lib/output-view.types.d.ts +0 -88
  120. package/lib/output-view.types.ts +0 -113
  121. package/lib/overlay-graph.d.ts +0 -43
  122. package/lib/overlay-graph.js +0 -191
  123. package/lib/parse-claims.types.ts +0 -41
  124. package/lib/parse-cli-arguments.types.ts +0 -75
  125. package/lib/parse-where-clause.types.ts +0 -87
  126. package/lib/patram-cli.js +0 -593
  127. package/lib/patram-config.types.ts +0 -22
  128. package/lib/tagged-fenced-blocks.types.ts +0 -38
  129. /package/lib/{reverse-reference-test-helpers.js → graph/reverse-reference-test-helpers.js} +0 -0
  130. /package/lib/{format-derived-summary-row.js → output/format-derived-summary-row.js} +0 -0
  131. /package/lib/{format-node-header.js → output/format-node-header.js} +0 -0
  132. /package/lib/{format-output-item-block.js → output/format-output-item-block.js} +0 -0
  133. /package/lib/{format-output-metadata.js → output/format-output-metadata.js} +0 -0
  134. /package/lib/{claim-helpers.js → parse/claim-helpers.js} +0 -0
  135. /package/lib/{parse-jsdoc-blocks.d.ts → parse/jsdoc/parse-jsdoc-blocks.d.ts} +0 -0
  136. /package/lib/{parse-jsdoc-blocks.js → parse/jsdoc/parse-jsdoc-blocks.js} +0 -0
  137. /package/lib/{tagged-fenced-block-error.js → parse/tagged-fenced/tagged-fenced-block-error.js} +0 -0
  138. /package/lib/{tagged-fenced-block-markdown.d.ts → parse/tagged-fenced/tagged-fenced-block-markdown.d.ts} +0 -0
  139. /package/lib/{tagged-fenced-block-markdown.js → parse/tagged-fenced/tagged-fenced-block-markdown.js} +0 -0
  140. /package/lib/{tagged-fenced-block-metadata.d.ts → parse/tagged-fenced/tagged-fenced-block-metadata.d.ts} +0 -0
  141. /package/lib/{tagged-fenced-block-metadata.js → parse/tagged-fenced/tagged-fenced-block-metadata.js} +0 -0
  142. /package/lib/{tagged-fenced-block-parser.js → parse/tagged-fenced/tagged-fenced-block-parser.js} +0 -0
  143. /package/lib/{tagged-fenced-blocks.types.d.ts → parse/tagged-fenced/tagged-fenced-blocks.types.d.ts} +0 -0
@@ -3,14 +3,14 @@
3
3
  * @import { OutputStoredQueryItem } from './output-view.types.ts';
4
4
  */
5
5
 
6
- import { parseWhereClause } from './parse-where-clause.js';
6
+ import { parseWhereClause } from '../graph/query/parse.js';
7
7
 
8
8
  const MAX_STORED_QUERY_WIDTH = 100;
9
9
  const MIN_TERM_COLUMN_WIDTH = 20;
10
10
  const STORED_QUERY_COLUMN_GAP = 2;
11
11
 
12
12
  /**
13
- * @typedef {'field_name' | 'keyword' | 'literal' | 'name' | 'operator' | 'plain'} StoredQuerySegmentKind
13
+ * @typedef {'description' | 'field_name' | 'keyword' | 'literal' | 'name' | 'operator' | 'plain'} StoredQuerySegmentKind
14
14
  */
15
15
 
16
16
  /**
@@ -56,7 +56,8 @@ function layoutStoredQuery(output_item, name_column_width, term_column_width) {
56
56
  name_column_width + STORED_QUERY_COLUMN_GAP,
57
57
  );
58
58
 
59
- return term_lines.map((line_segments, line_index) => {
59
+ /** @type {StoredQuerySegment[][]} */
60
+ const output_lines = term_lines.map((line_segments, line_index) => {
60
61
  if (line_index === 0) {
61
62
  return [
62
63
  {
@@ -79,6 +80,21 @@ function layoutStoredQuery(output_item, name_column_width, term_column_width) {
79
80
  ...line_segments,
80
81
  ];
81
82
  });
83
+
84
+ if (output_item.description) {
85
+ for (const description_line of output_item.description.split('\n')) {
86
+ output_lines.push([
87
+ {
88
+ kind: 'description',
89
+ text: `${' '.repeat(name_column_width + STORED_QUERY_COLUMN_GAP)}${description_line}`,
90
+ },
91
+ ]);
92
+ }
93
+ }
94
+
95
+ output_lines.push([]);
96
+
97
+ return output_lines;
82
98
  }
83
99
 
84
100
  /**
@@ -96,7 +112,7 @@ function createStoredQueryPhrases(where_clause) {
96
112
  }
97
113
 
98
114
  /**
99
- * @param {import('./parse-where-clause.types.ts').ParsedExpression} expression
115
+ * @param {import('../graph/parse-where-clause.types.ts').ParsedExpression} expression
100
116
  * @returns {StoredQuerySegment[][]}
101
117
  */
102
118
  function createExpressionPhrases(expression) {
@@ -114,7 +130,7 @@ function createExpressionPhrases(expression) {
114
130
  }
115
131
 
116
132
  /**
117
- * @param {import('./parse-where-clause.types.ts').ParsedExpression} expression
133
+ * @param {import('../graph/parse-where-clause.types.ts').ParsedExpression} expression
118
134
  * @param {'and' | 'or'} operator
119
135
  * @param {boolean} should_prefix_operator
120
136
  * @returns {StoredQuerySegment[]}
@@ -139,7 +155,7 @@ function createExpressionPhrase(expression, operator, should_prefix_operator) {
139
155
  }
140
156
 
141
157
  /**
142
- * @param {import('./parse-where-clause.types.ts').ParsedExpression} expression
158
+ * @param {import('../graph/parse-where-clause.types.ts').ParsedExpression} expression
143
159
  * @param {number} parent_precedence
144
160
  * @returns {StoredQuerySegment[]}
145
161
  */
@@ -159,7 +175,7 @@ function createExpressionSegments(expression, parent_precedence) {
159
175
  }
160
176
 
161
177
  /**
162
- * @param {import('./parse-where-clause.types.ts').ParsedExpression} expression
178
+ * @param {import('../graph/parse-where-clause.types.ts').ParsedExpression} expression
163
179
  * @returns {StoredQuerySegment[]}
164
180
  */
165
181
  function createRawExpressionSegments(expression) {
@@ -202,7 +218,7 @@ function createRawExpressionSegments(expression) {
202
218
  }
203
219
 
204
220
  /**
205
- * @param {import('./parse-where-clause.types.ts').ParsedExpression} expression
221
+ * @param {import('../graph/parse-where-clause.types.ts').ParsedExpression} expression
206
222
  * @returns {number}
207
223
  */
208
224
  function getExpressionPrecedence(expression) {
@@ -230,7 +246,7 @@ function getBooleanExpressionPrecedence(operator) {
230
246
  }
231
247
 
232
248
  /**
233
- * @param {import('./parse-where-clause.types.ts').ParsedTerm} term
249
+ * @param {import('../graph/parse-where-clause.types.ts').ParsedTerm} term
234
250
  * @returns {StoredQuerySegment[]}
235
251
  */
236
252
  function createTermSegments(term) {
@@ -265,7 +281,7 @@ function createTermSegments(term) {
265
281
  }
266
282
 
267
283
  /**
268
- * @param {import('./parse-where-clause.types.ts').ParsedFieldSetTerm} term
284
+ * @param {import('../graph/parse-where-clause.types.ts').ParsedFieldSetTerm} term
269
285
  * @returns {StoredQuerySegment[]}
270
286
  */
271
287
  function createFieldSetSegments(term) {
@@ -281,7 +297,7 @@ function createFieldSetSegments(term) {
281
297
  }
282
298
 
283
299
  /**
284
- * @param {import('./parse-where-clause.types.ts').ParsedAggregateTerm} term
300
+ * @param {import('../graph/parse-where-clause.types.ts').ParsedAggregateTerm} term
285
301
  * @returns {StoredQuerySegment[]}
286
302
  */
287
303
  function createAggregateSegments(term) {
@@ -1,17 +1,18 @@
1
1
  /**
2
- * @import { StoredQueryConfig } from './load-patram-config.types.ts';
2
+ * @import { StoredQueryConfig } from '../config/load-patram-config.types.ts';
3
3
  */
4
4
 
5
5
  /**
6
6
  * List stored queries in stable name order.
7
7
  *
8
8
  * @param {Record<string, StoredQueryConfig>} stored_queries
9
- * @returns {{ name: string, where: string }[]}
9
+ * @returns {{ name: string, where: string, description?: string }[]}
10
10
  */
11
11
  export function listQueries(stored_queries) {
12
12
  return Object.entries(stored_queries)
13
13
  .sort(([left_name], [right_name]) => left_name.localeCompare(right_name))
14
14
  .map(([name, stored_query]) => ({
15
+ description: stored_query.description,
15
16
  name,
16
17
  where: stored_query.where,
17
18
  }));
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @import { PatramDiagnostic } from './load-patram-config.types.ts';
2
+ * @import { PatramDiagnostic } from '../config/load-patram-config.types.ts';
3
3
  * @import { ResolvedOutputMode } from './output-view.types.ts';
4
4
  */
5
5
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @import { ResolvedOutputMode } from './output-view.types.ts';
3
- * @import { FieldDiscoveryResult, FieldDiscoverySuggestion } from './discover-fields.types.ts';
3
+ * @import { FieldDiscoveryResult, FieldDiscoverySuggestion } from '../scan/discover-fields.types.ts';
4
4
  */
5
5
 
6
6
  import { Ansis } from 'ansis';
@@ -135,7 +135,7 @@ function formatTextFieldSuggestion(field_suggestion, render_options) {
135
135
 
136
136
  /**
137
137
  * @param {string} section_title
138
- * @param {import('./discover-fields.types.ts').FieldDiscoveryEvidenceReference[]} evidence_references
138
+ * @param {import('../scan/discover-fields.types.ts').FieldDiscoveryEvidenceReference[]} evidence_references
139
139
  * @param {{ header: (value: string) => string, label: (value: string) => string }} render_options
140
140
  * @returns {string[]}
141
141
  */
@@ -168,7 +168,7 @@ function formatTextEvidenceSection(
168
168
  }
169
169
 
170
170
  /**
171
- * @param {import('./discover-fields.types.ts').FieldDiscoveryEvidenceReference} evidence_reference
171
+ * @param {import('../scan/discover-fields.types.ts').FieldDiscoveryEvidenceReference} evidence_reference
172
172
  * @returns {string}
173
173
  */
174
174
  function formatEvidenceReference(evidence_reference) {
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @import { ParsedCliArguments } from '../cli/arguments.types.ts';
3
+ * @import { ResolvedOutputMode, OutputView } from './output-view.types.ts';
4
+ */
5
+
6
+ import { renderJsonOutput } from './renderers/json.js';
7
+ import { renderPlainOutput } from './renderers/plain.js';
8
+ import { renderRichOutput } from './renderers/rich.js';
9
+
10
+ /**
11
+ * Shared command output views.
12
+ *
13
+ * Normalizes `query`, `queries`, and `show` results into renderer-specific
14
+ * output models.
15
+ *
16
+ * Kind: output
17
+ * Status: active
18
+ * Tracked in: ../../docs/plans/v0/source-anchor-dogfooding.md
19
+ * Decided by: ../../docs/decisions/cli-output-architecture.md
20
+ * @patram
21
+ * @see {@link ./show-document.js}
22
+ * @see {@link ../../docs/decisions/cli-output-architecture.md}
23
+ */
24
+
25
+ export {
26
+ createOutputView,
27
+ createRefsOutputView,
28
+ createShowOutputView,
29
+ } from './view-model/index.js';
30
+
31
+ /**
32
+ * Render one shared output view through the resolved renderer.
33
+ *
34
+ * @param {OutputView} output_view
35
+ * @param {ResolvedOutputMode} output_mode
36
+ * @param {ParsedCliArguments} parsed_arguments
37
+ * @returns {Promise<string>}
38
+ */
39
+ export async function renderOutputView(
40
+ output_view,
41
+ output_mode,
42
+ parsed_arguments,
43
+ ) {
44
+ if (output_mode.renderer_name === 'json') {
45
+ return renderJsonOutput(output_view);
46
+ }
47
+
48
+ if (output_mode.renderer_name === 'plain') {
49
+ return renderPlainOutput(output_view);
50
+ }
51
+
52
+ return renderRichOutput(output_view, {
53
+ color_enabled: output_mode.color_enabled,
54
+ color_mode: parsed_arguments.color_mode,
55
+ });
56
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @import { OutputNodeItem, OutputResolvedLinkItem, OutputStoredQueryItem, OutputView } from './output-view.types.ts';
2
+ * @import { OutputNodeItem, OutputResolvedLinkItem, OutputStoredQueryItem, OutputView } from '../output-view.types.ts';
3
3
  */
4
4
 
5
5
  /**
@@ -92,9 +92,6 @@ function renderJsonRefsOutput(output_view) {
92
92
  function renderJsonShowOutput(output_view) {
93
93
  return `${JSON.stringify(
94
94
  {
95
- document: output_view.document
96
- ? formatJsonNodeItem(output_view.document)
97
- : undefined,
98
95
  incoming_summary: output_view.incoming_summary,
99
96
  source: output_view.source,
100
97
  resolved_links: output_view.items.map(formatJsonResolvedLink),
@@ -144,13 +141,20 @@ function formatJsonNodeItem(output_item) {
144
141
 
145
142
  /**
146
143
  * @param {OutputStoredQueryItem} output_item
147
- * @returns {{ name: string, where: string }}
144
+ * @returns {{ name: string, where: string, description?: string }}
148
145
  */
149
146
  function formatJsonStoredQuery(output_item) {
150
- return {
147
+ /** @type {{ description?: string, name: string, where: string }} */
148
+ const stored_query = {
151
149
  name: output_item.name,
152
150
  where: output_item.where,
153
151
  };
152
+
153
+ if (output_item.description) {
154
+ stored_query.description = output_item.description;
155
+ }
156
+
157
+ return stored_query;
154
158
  }
155
159
 
156
160
  /**
@@ -1,16 +1,16 @@
1
1
  /**
2
- * @import { OutputNodeItem, OutputResolvedLinkItem, OutputStoredQueryItem, OutputView, QueryOutputView, RefsOutputView, ShowOutputView } from './output-view.types.ts';
2
+ * @import { OutputNodeItem, OutputResolvedLinkItem, OutputStoredQueryItem, OutputView, QueryOutputView, RefsOutputView, ShowOutputView } from '../output-view.types.ts';
3
3
  */
4
4
 
5
5
  import {
6
6
  formatOutputNodeMetadataRows,
7
7
  formatResolvedLinkMetadataRows,
8
- } from './format-output-metadata.js';
9
- import { formatNodeHeader } from './format-node-header.js';
10
- import { formatOutputItemBlock } from './format-output-item-block.js';
11
- import { layoutIncomingReferenceLines } from './layout-incoming-references.js';
12
- import { layoutIncomingSummaryLines } from './layout-incoming-summary-lines.js';
13
- import { layoutStoredQueries } from './layout-stored-queries.js';
8
+ } from '../format-output-metadata.js';
9
+ import { formatNodeHeader } from '../format-node-header.js';
10
+ import { formatOutputItemBlock } from '../format-output-item-block.js';
11
+ import { layoutIncomingReferenceLines } from '../layout-incoming-references.js';
12
+ import { layoutIncomingSummaryLines } from '../layout-incoming-summary-lines.js';
13
+ import { layoutStoredQueries } from '../layout-stored-queries.js';
14
14
 
15
15
  /**
16
16
  * Render the canonical plain output for one output view.
@@ -24,7 +24,7 @@ export function renderPlainOutput(output_view) {
24
24
  }
25
25
 
26
26
  if (output_view.command === 'queries') {
27
- return renderPlainStoredQueries(output_view.items);
27
+ return renderPlainStoredQueries(output_view);
28
28
  }
29
29
 
30
30
  if (output_view.command === 'refs') {
@@ -69,17 +69,23 @@ function renderPlainEmptyQuery(footer) {
69
69
  }
70
70
 
71
71
  /**
72
- * @param {OutputStoredQueryItem[]} output_items
72
+ * @param {Extract<OutputView, { command: 'queries' }>} output_view
73
73
  * @returns {string}
74
74
  */
75
- function renderPlainStoredQueries(output_items) {
76
- if (output_items.length === 0) {
75
+ function renderPlainStoredQueries(output_view) {
76
+ if (output_view.items.length === 0) {
77
77
  return '';
78
78
  }
79
79
 
80
- return `${layoutStoredQueries(output_items)
81
- .map(formatPlainStoredQueryLine)
82
- .join('\n')}\n`;
80
+ const output_lines = layoutStoredQueries(output_view.items).map(
81
+ formatPlainStoredQueryLine,
82
+ );
83
+
84
+ if (output_view.hints.length === 0) {
85
+ return `${output_lines.join('\n')}\n`;
86
+ }
87
+
88
+ return `${output_lines.join('\n')}\n${output_view.hints.join('\n')}\n`;
83
89
  }
84
90
 
85
91
  /**
@@ -88,29 +94,12 @@ function renderPlainStoredQueries(output_items) {
88
94
  */
89
95
  function renderPlainShowOutput(output_view) {
90
96
  const rendered_source = trimTrailingLineBreaks(output_view.rendered_source);
91
- const document_summary = output_view.document
92
- ? formatPlainNodeItem(output_view.document)
93
- : '';
94
97
  const incoming_summary = renderPlainIncomingSummary(output_view);
95
98
 
96
- if (
97
- document_summary.length === 0 &&
98
- output_view.items.length === 0 &&
99
- incoming_summary.length === 0
100
- ) {
99
+ if (output_view.items.length === 0 && incoming_summary.length === 0) {
101
100
  return `${rendered_source}\n`;
102
101
  }
103
-
104
- /** @type {string[]} */
105
- const summary_items = [];
106
-
107
- if (document_summary.length > 0) {
108
- summary_items.push(document_summary);
109
- }
110
-
111
- summary_items.push(...output_view.items.map(formatPlainResolvedLinkItem));
112
-
113
- const summary_blocks = summary_items.filter((summary_item) => summary_item);
102
+ const summary_blocks = output_view.items.map(formatPlainResolvedLinkItem);
114
103
 
115
104
  if (incoming_summary.length > 0) {
116
105
  summary_blocks.push(incoming_summary);
@@ -172,12 +161,24 @@ function formatPlainResolvedLinkItem(output_item) {
172
161
  * @returns {string}
173
162
  */
174
163
  function renderPlainIncomingSummary(output_view) {
164
+ if (!hasIncomingSummary(output_view.incoming_summary)) {
165
+ return '';
166
+ }
167
+
175
168
  const output_lines = layoutIncomingSummaryLines(output_view.incoming_summary);
176
169
  output_lines.push('', `Hint: patram refs ${output_view.path}`);
177
170
 
178
171
  return output_lines.join('\n');
179
172
  }
180
173
 
174
+ /**
175
+ * @param {Record<string, number>} incoming_summary
176
+ * @returns {boolean}
177
+ */
178
+ function hasIncomingSummary(incoming_summary) {
179
+ return Object.keys(incoming_summary).length > 0;
180
+ }
181
+
181
182
  /**
182
183
  * @param {string} value
183
184
  * @returns {string}
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @import { CliColorMode } from './parse-cli-arguments.types.ts';
3
- * @import { OutputNodeItem, OutputResolvedLinkItem, OutputStoredQueryItem, OutputView, QueryOutputView, RefsOutputView, ShowOutputView } from './output-view.types.ts';
2
+ * @import { CliColorMode } from '../../cli/arguments.types.ts';
3
+ * @import { OutputNodeItem, OutputResolvedLinkItem, OutputStoredQueryItem, OutputView, QueryOutputView, RefsOutputView, ShowOutputView } from '../output-view.types.ts';
4
4
  */
5
5
 
6
6
  import { Ansis } from 'ansis';
@@ -8,13 +8,13 @@ import { Ansis } from 'ansis';
8
8
  import {
9
9
  formatOutputNodeMetadataRows,
10
10
  formatResolvedLinkMetadataRows,
11
- } from './format-output-metadata.js';
12
- import { formatNodeHeader } from './format-node-header.js';
13
- import { formatOutputItemBlock } from './format-output-item-block.js';
14
- import { layoutIncomingReferenceLines } from './layout-incoming-references.js';
15
- import { layoutIncomingSummaryLines } from './layout-incoming-summary-lines.js';
16
- import { layoutStoredQueries } from './layout-stored-queries.js';
17
- import { renderRichSource } from './render-rich-source.js';
11
+ } from '../format-output-metadata.js';
12
+ import { formatNodeHeader } from '../format-node-header.js';
13
+ import { formatOutputItemBlock } from '../format-output-item-block.js';
14
+ import { layoutIncomingReferenceLines } from '../layout-incoming-references.js';
15
+ import { layoutIncomingSummaryLines } from '../layout-incoming-summary-lines.js';
16
+ import { layoutStoredQueries } from '../layout-stored-queries.js';
17
+ import { renderRichSource } from '../rich-source/render.js';
18
18
 
19
19
  const FULL_WIDTH_DIVIDER = ` ${'─'.repeat(78)} `;
20
20
 
@@ -33,7 +33,7 @@ export async function renderRichOutput(output_view, render_options) {
33
33
  }
34
34
 
35
35
  if (output_view.command === 'queries') {
36
- return renderRichStoredQueries(output_view.items, ansi);
36
+ return renderRichStoredQueries(output_view, ansi);
37
37
  }
38
38
 
39
39
  if (output_view.command === 'refs') {
@@ -83,18 +83,24 @@ function renderRichEmptyQuery(footer, ansi) {
83
83
  }
84
84
 
85
85
  /**
86
- * @param {OutputStoredQueryItem[]} output_items
86
+ * @param {Extract<OutputView, { command: 'queries' }>} output_view
87
87
  * @param {Ansis} ansi
88
88
  * @returns {string}
89
89
  */
90
- function renderRichStoredQueries(output_items, ansi) {
91
- if (output_items.length === 0) {
90
+ function renderRichStoredQueries(output_view, ansi) {
91
+ if (output_view.items.length === 0) {
92
92
  return '';
93
93
  }
94
94
 
95
- return `${layoutStoredQueries(output_items)
96
- .map((line_segments) => formatRichStoredQueryLine(line_segments, ansi))
97
- .join('\n')}\n`;
95
+ const output_lines = layoutStoredQueries(output_view.items).map(
96
+ (line_segments) => formatRichStoredQueryLine(line_segments, ansi),
97
+ );
98
+
99
+ if (output_view.hints.length === 0) {
100
+ return `${output_lines.join('\n')}\n`;
101
+ }
102
+
103
+ return `${output_lines.join('\n')}\n${output_view.hints.map((hint) => ansi.gray(hint)).join('\n')}\n`;
98
104
  }
99
105
 
100
106
  /**
@@ -107,20 +113,14 @@ async function renderRichShowOutput(output_view, render_options, ansi) {
107
113
  const rendered_source = trimTrailingLineBreaks(
108
114
  await renderRichSource(output_view, render_options),
109
115
  );
110
- const document_summary = output_view.document
111
- ? formatRichNodeItem(output_view.document, ansi)
112
- : '';
113
116
  const incoming_summary = renderRichIncomingSummary(output_view, ansi);
114
117
 
115
- /** @type {string[]} */
116
- const summary_items = [];
117
-
118
- if (document_summary.length > 0) {
119
- summary_items.push(document_summary);
118
+ if (output_view.items.length === 0 && incoming_summary.length === 0) {
119
+ return `${rendered_source}\n`;
120
120
  }
121
121
 
122
- summary_items.push(
123
- ...output_view.items.map((item) => formatRichResolvedLinkItem(item, ansi)),
122
+ const summary_items = output_view.items.map((item) =>
123
+ formatRichResolvedLinkItem(item, ansi),
124
124
  );
125
125
 
126
126
  if (incoming_summary.length > 0) {
@@ -165,7 +165,7 @@ function formatRichNodeItem(output_item, ansi) {
165
165
  }
166
166
 
167
167
  /**
168
- * @param {{ kind: 'field_name' | 'keyword' | 'literal' | 'name' | 'operator' | 'plain', text: string }[]} line_segments
168
+ * @param {{ kind: 'description' | 'field_name' | 'keyword' | 'literal' | 'name' | 'operator' | 'plain', text: string }[]} line_segments
169
169
  * @param {Ansis} ansi
170
170
  * @returns {string}
171
171
  */
@@ -195,18 +195,26 @@ function formatRichResolvedLinkItem(output_item, ansi) {
195
195
  * @returns {string}
196
196
  */
197
197
  function renderRichIncomingSummary(output_view, ansi) {
198
+ if (!hasIncomingSummary(output_view.incoming_summary)) {
199
+ return '';
200
+ }
201
+
198
202
  const output_lines = layoutIncomingSummaryLines(output_view.incoming_summary);
199
203
  output_lines[0] = ansi.bold(output_lines[0]);
200
204
 
201
- if (Object.keys(output_view.incoming_summary).length === 0) {
202
- output_lines[1] = ` ${ansi.gray('none')}`;
203
- }
204
-
205
205
  output_lines.push('', ansi.gray(`Hint: patram refs ${output_view.path}`));
206
206
 
207
207
  return output_lines.join('\n');
208
208
  }
209
209
 
210
+ /**
211
+ * @param {Record<string, number>} incoming_summary
212
+ * @returns {boolean}
213
+ */
214
+ function hasIncomingSummary(incoming_summary) {
215
+ return Object.keys(incoming_summary).length > 0;
216
+ }
217
+
210
218
  /**
211
219
  * @param {boolean} color_enabled
212
220
  * @returns {Ansis}
@@ -216,7 +224,7 @@ function createAnsi(color_enabled) {
216
224
  }
217
225
 
218
226
  /**
219
- * @param {{ kind: 'field_name' | 'keyword' | 'literal' | 'name' | 'operator' | 'plain', text: string }} line_segment
227
+ * @param {{ kind: 'description' | 'field_name' | 'keyword' | 'literal' | 'name' | 'operator' | 'plain', text: string }} line_segment
220
228
  * @param {Ansis} ansi
221
229
  * @returns {string}
222
230
  */
@@ -225,6 +233,10 @@ function styleStoredQuerySegment(line_segment, ansi) {
225
233
  return ansi.green(line_segment.text);
226
234
  }
227
235
 
236
+ if (line_segment.kind === 'description') {
237
+ return ansi.gray(line_segment.text);
238
+ }
239
+
228
240
  if (line_segment.kind === 'operator') {
229
241
  return ansi.gray(line_segment.text);
230
242
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @import { PatramDiagnostic } from './load-patram-config.types.ts';
2
+ * @import { PatramDiagnostic } from '../config/load-patram-config.types.ts';
3
3
  */
4
4
  import { access, stat } from 'node:fs/promises';
5
5
  import { dirname, relative, resolve } from 'node:path';
@@ -2,8 +2,8 @@
2
2
  /**
3
3
  * @import { ComarkElement, ComarkNode } from 'md4x';
4
4
  * @import { BundledLanguage } from 'shiki';
5
- * @import { CliColorMode } from './parse-cli-arguments.types.ts';
6
- * @import { OutputResolvedLinkItem, ShowOutputView } from './output-view.types.ts';
5
+ * @import { CliColorMode } from '../../cli/arguments.types.ts';
6
+ * @import { OutputResolvedLinkItem, ShowOutputView } from '../output-view.types.ts';
7
7
  */
8
8
 
9
9
  import { extname } from 'node:path';
@@ -969,8 +969,8 @@ function shouldRenderListItemGap(previous_item, next_item, has_blank_line_gap) {
969
969
  }
970
970
 
971
971
  return (
972
- isSimpleTopLevelListItem(previous_item) &&
973
- isSimpleTopLevelListItem(next_item)
972
+ isSingleParagraphTopLevelListItem(previous_item) &&
973
+ isSingleParagraphTopLevelListItem(next_item)
974
974
  );
975
975
  }
976
976
 
@@ -978,7 +978,7 @@ function shouldRenderListItemGap(previous_item, next_item, has_blank_line_gap) {
978
978
  * @param {ComarkElement} item_node
979
979
  * @returns {boolean}
980
980
  */
981
- function isSimpleTopLevelListItem(item_node) {
981
+ function isSingleParagraphTopLevelListItem(item_node) {
982
982
  const item_children = getElementChildren(item_node);
983
983
 
984
984
  if (item_children.length !== 1) {
@@ -994,7 +994,7 @@ function isSimpleTopLevelListItem(item_node) {
994
994
  return false;
995
995
  }
996
996
 
997
- return !extractInlineText(getElementChildren(paragraph_node)).includes('\n');
997
+ return true;
998
998
  }
999
999
 
1000
1000
  /**
@@ -1,16 +1,16 @@
1
1
  /* eslint-disable max-lines */
2
2
  /**
3
- * @import { BuildGraphResult, GraphNode } from './build-graph.types.ts';
4
- * @import { PatramClaim } from './parse-claims.types.ts';
5
- * @import { PatramDiagnostic } from './load-patram-config.types.ts';
3
+ * @import { BuildGraphResult, GraphNode } from '../graph/build-graph.types.ts';
4
+ * @import { PatramClaim } from '../parse/parse-claims.types.ts';
5
+ * @import { PatramDiagnostic } from '../config/load-patram-config.types.ts';
6
6
  */
7
7
 
8
8
  import { readFile } from 'node:fs/promises';
9
9
  import { posix, relative, resolve } from 'node:path';
10
10
 
11
- import { resolveDocumentNodeId } from './build-graph-identity.js';
12
- import { inspectReverseReferences } from './inspect-reverse-references.js';
13
- import { parseSourceFile } from './parse-claims.js';
11
+ import { resolveDocumentNodeId } from '../graph/build-graph-identity.js';
12
+ import { inspectReverseReferences } from '../graph/inspect-reverse-references.js';
13
+ import { parseSourceFile } from '../parse/parse-claims.js';
14
14
 
15
15
  /**
16
16
  * Show command document rendering.
@@ -20,12 +20,12 @@ import { parseSourceFile } from './parse-claims.js';
20
20
  *
21
21
  * Kind: output
22
22
  * Status: active
23
- * Tracked in: ../docs/plans/v0/source-anchor-dogfooding.md
24
- * Decided by: ../docs/decisions/show-output.md
25
- * Decided by: ../docs/decisions/source-rendering.md
23
+ * Tracked in: ../../docs/plans/v0/source-anchor-dogfooding.md
24
+ * Decided by: ../../docs/decisions/show-output.md
25
+ * Decided by: ../../docs/decisions/source-rendering.md
26
26
  * @patram
27
27
  * @see {@link ./render-output-view.js}
28
- * @see {@link ../docs/decisions/show-output.md}
28
+ * @see {@link ../../docs/decisions/show-output.md}
29
29
  */
30
30
 
31
31
  /**
@@ -107,7 +107,7 @@ export async function loadShowOutput(
107
107
  * @param {string} source_text
108
108
  * @param {PatramClaim[]} claims
109
109
  * @param {BuildGraphResult} graph
110
- * @param {import('./build-graph.types.ts').BuildGraphResult['document_node_ids']} document_node_ids
110
+ * @param {import('../graph/build-graph.types.ts').BuildGraphResult['document_node_ids']} document_node_ids
111
111
  * @param {Record<string, GraphNode>} graph_nodes
112
112
  * @returns {{ incoming_summary: Record<string, number>, path: string, rendered_source: string, resolved_links: Array<{ label: string, reference: number, target: { kind?: string, path: string, status?: string, title: string } }>, source: string }}
113
113
  */
@@ -219,7 +219,7 @@ function renderResolvedSourceLine(
219
219
  * @param {string} source_file_path
220
220
  * @param {PatramClaim} claim
221
221
  * @param {number} reference
222
- * @param {import('./build-graph.types.ts').BuildGraphResult['document_node_ids']} document_node_ids
222
+ * @param {import('../graph/build-graph.types.ts').BuildGraphResult['document_node_ids']} document_node_ids
223
223
  * @param {Record<string, GraphNode>} graph_nodes
224
224
  * @returns {{ label: string, reference: number, target: { kind?: string, path: string, status?: string, title: string } }}
225
225
  */