patram 0.11.0 → 0.12.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 (110) hide show
  1. package/bin/patram.js +4 -4
  2. package/lib/cli/commands/fields.js +0 -4
  3. package/lib/cli/commands/queries.js +10 -20
  4. package/lib/cli/commands/query.js +1 -8
  5. package/lib/cli/commands/refs.js +3 -10
  6. package/lib/cli/commands/show.js +1 -8
  7. package/lib/cli/help-metadata.js +71 -106
  8. package/lib/cli/main.js +10 -10
  9. package/lib/cli/parse-arguments-helpers.js +165 -59
  10. package/lib/cli/parse-arguments.js +4 -4
  11. package/lib/cli/render-help.js +2 -2
  12. package/lib/config/defaults.js +33 -25
  13. package/lib/config/load-patram-config.d.ts +8 -33
  14. package/lib/config/load-patram-config.js +9 -33
  15. package/lib/config/load-patram-config.types.d.ts +3 -40
  16. package/lib/config/manage-stored-queries-helpers.d.ts +4 -4
  17. package/lib/config/manage-stored-queries-helpers.js +91 -33
  18. package/lib/config/manage-stored-queries.d.ts +4 -4
  19. package/lib/config/manage-stored-queries.js +11 -5
  20. package/lib/config/patram-config.d.ts +34 -34
  21. package/lib/config/patram-config.js +3 -3
  22. package/lib/config/patram-config.types.d.ts +5 -11
  23. package/lib/config/resolve-patram-graph-config.d.ts +5 -1
  24. package/lib/config/resolve-patram-graph-config.js +3 -119
  25. package/lib/config/schema.d.ts +158 -269
  26. package/lib/config/schema.js +72 -210
  27. package/lib/config/validate-patram-config-value.js +6 -31
  28. package/lib/config/validation.d.ts +2 -12
  29. package/lib/config/validation.js +125 -483
  30. package/lib/find-close-match.d.ts +4 -1
  31. package/lib/graph/build-graph-identity.d.ts +1 -32
  32. package/lib/graph/build-graph-identity.js +5 -269
  33. package/lib/graph/build-graph.d.ts +13 -4
  34. package/lib/graph/build-graph.js +347 -488
  35. package/lib/graph/build-graph.types.d.ts +8 -9
  36. package/lib/graph/check-directive-metadata-helpers.d.ts +30 -0
  37. package/lib/graph/check-directive-metadata-helpers.js +126 -0
  38. package/lib/graph/check-directive-metadata.d.ts +8 -9
  39. package/lib/graph/check-directive-metadata.js +70 -561
  40. package/lib/graph/check-directive-path-target.d.ts +6 -13
  41. package/lib/graph/check-directive-path-target.js +26 -57
  42. package/lib/graph/check-directive-value.d.ts +1 -5
  43. package/lib/graph/check-directive-value.js +40 -180
  44. package/lib/graph/check-graph.d.ts +5 -5
  45. package/lib/graph/check-graph.js +8 -6
  46. package/lib/graph/document-node-identity.d.ts +23 -7
  47. package/lib/graph/document-node-identity.js +417 -160
  48. package/lib/graph/graph-node.d.ts +42 -0
  49. package/lib/graph/graph-node.js +83 -0
  50. package/lib/graph/inspect-reverse-references.js +16 -11
  51. package/lib/graph/load-project-graph.d.ts +7 -7
  52. package/lib/graph/load-project-graph.js +7 -7
  53. package/lib/graph/parse-where-clause.types.d.ts +3 -2
  54. package/lib/graph/query/cypher-reader.d.ts +59 -0
  55. package/lib/graph/query/cypher-reader.js +151 -0
  56. package/lib/graph/query/cypher-support.d.ts +79 -0
  57. package/lib/graph/query/cypher-support.js +213 -0
  58. package/lib/graph/query/cypher-tokenize.d.ts +13 -0
  59. package/lib/graph/query/cypher-tokenize.js +225 -0
  60. package/lib/graph/query/cypher.types.d.ts +43 -0
  61. package/lib/graph/query/execute.d.ts +7 -7
  62. package/lib/graph/query/execute.js +71 -33
  63. package/lib/graph/query/inspect.js +58 -24
  64. package/lib/graph/query/parse-cypher-patterns.d.ts +27 -0
  65. package/lib/graph/query/parse-cypher-patterns.js +382 -0
  66. package/lib/graph/query/parse-cypher.d.ts +7 -0
  67. package/lib/graph/query/parse-cypher.js +580 -0
  68. package/lib/graph/query/parse-query.d.ts +13 -0
  69. package/lib/graph/query/parse-query.js +97 -0
  70. package/lib/graph/query/resolve.js +77 -23
  71. package/lib/output/command-output.js +12 -5
  72. package/lib/output/compact-layout.js +221 -0
  73. package/lib/output/format-output-item-block.js +31 -1
  74. package/lib/output/format-output-metadata.js +16 -29
  75. package/lib/output/format-stored-query-block.js +95 -0
  76. package/lib/output/layout-incoming-references.js +101 -19
  77. package/lib/output/layout-stored-queries.js +23 -330
  78. package/lib/output/list-queries.js +1 -1
  79. package/lib/output/render-field-discovery.js +11 -2
  80. package/lib/output/render-output-view.js +9 -5
  81. package/lib/output/renderers/json.js +5 -26
  82. package/lib/output/renderers/plain.js +155 -35
  83. package/lib/output/renderers/rich.js +250 -36
  84. package/lib/output/resolved-link-layout.js +43 -0
  85. package/lib/output/rich-source/render.js +193 -35
  86. package/lib/output/show-document.js +25 -18
  87. package/lib/output/view-model/index.js +124 -103
  88. package/lib/parse/jsdoc/parse-jsdoc-blocks.js +1 -1
  89. package/lib/parse/jsdoc/parse-jsdoc-claims.js +12 -6
  90. package/lib/parse/markdown/parse-markdown-claims.js +99 -62
  91. package/lib/parse/markdown/parse-markdown-directives.d.ts +10 -6
  92. package/lib/parse/markdown/parse-markdown-directives.js +104 -18
  93. package/lib/parse/markdown/parse-markdown-prose.d.ts +27 -0
  94. package/lib/parse/markdown/parse-markdown-prose.js +243 -0
  95. package/lib/parse/parse-claims.d.ts +2 -6
  96. package/lib/parse/parse-claims.js +11 -53
  97. package/lib/parse/tagged-fenced/tagged-fenced-blocks.d.ts +4 -4
  98. package/lib/parse/tagged-fenced/tagged-fenced-blocks.js +4 -4
  99. package/lib/parse/yaml/parse-yaml-claims.js +4 -4
  100. package/lib/patram.d.ts +3 -5
  101. package/lib/patram.js +1 -1
  102. package/lib/scan/discover-fields.js +194 -55
  103. package/lib/scan/list-source-files.d.ts +4 -4
  104. package/lib/scan/list-source-files.js +4 -4
  105. package/package.json +1 -1
  106. package/lib/directive-validation-test-helpers.js +0 -87
  107. package/lib/graph/query/parse.d.ts +0 -75
  108. package/lib/graph/query/parse.js +0 -1064
  109. package/lib/output/derived-summary.js +0 -280
  110. package/lib/output/format-derived-summary-row.js +0 -9
@@ -103,7 +103,7 @@ function renderJsonShowOutput(output_view) {
103
103
 
104
104
  /**
105
105
  * @param {OutputNodeItem} output_item
106
- * @returns {{ '$class': string, '$id': string, '$path'?: string, derived?: Record<string, boolean | number | string | null>, derived_summary?: string, fields: Record<string, string | string[]>, title: string }}
106
+ * @returns {{ '$class': string, '$id': string, '$path'?: string, fields: Record<string, string | string[]>, title: string }}
107
107
  */
108
108
  function formatJsonQueryItem(output_item) {
109
109
  return formatJsonNodeItem(output_item);
@@ -111,10 +111,10 @@ function formatJsonQueryItem(output_item) {
111
111
 
112
112
  /**
113
113
  * @param {OutputNodeItem} output_item
114
- * @returns {{ '$class': string, '$id': string, '$path'?: string, derived?: Record<string, boolean | number | string | null>, derived_summary?: string, fields: Record<string, string | string[]>, title: string }}
114
+ * @returns {{ '$class': string, '$id': string, '$path'?: string, fields: Record<string, string | string[]>, title: string }}
115
115
  */
116
116
  function formatJsonNodeItem(output_item) {
117
- /** @type {{ '$class': string, '$id': string, '$path'?: string, derived?: Record<string, boolean | number | string | null>, derived_summary?: string, fields: Record<string, string | string[]>, title: string }} */
117
+ /** @type {{ '$class': string, '$id': string, '$path'?: string, fields: Record<string, string | string[]>, title: string }} */
118
118
  const query_item = {
119
119
  $class: output_item.node_kind,
120
120
  $id: output_item.id,
@@ -126,16 +126,6 @@ function formatJsonNodeItem(output_item) {
126
126
  query_item.$path = output_item.path;
127
127
  }
128
128
 
129
- if (output_item.derived_summary) {
130
- query_item.derived_summary = output_item.derived_summary.name;
131
- query_item.derived = Object.fromEntries(
132
- output_item.derived_summary.fields.map((field) => [
133
- field.name,
134
- field.value,
135
- ]),
136
- );
137
- }
138
-
139
129
  return query_item;
140
130
  }
141
131
 
@@ -159,10 +149,10 @@ function formatJsonStoredQuery(output_item) {
159
149
 
160
150
  /**
161
151
  * @param {OutputResolvedLinkItem} output_item
162
- * @returns {{ label: string, reference: number, target: { '$class': string, '$id': string, '$path'?: string, derived?: Record<string, boolean | number | string | null>, derived_summary?: string, fields: Record<string, string | string[]>, title: string } }}
152
+ * @returns {{ label: string, reference: number, target: { '$class': string, '$id': string, '$path'?: string, fields: Record<string, string | string[]>, title: string } }}
163
153
  */
164
154
  function formatJsonResolvedLink(output_item) {
165
- /** @type {{ label: string, reference: number, target: { '$class': string, '$id': string, '$path'?: string, derived?: Record<string, boolean | number | string | null>, derived_summary?: string, fields: Record<string, string | string[]>, title: string } }} */
155
+ /** @type {{ label: string, reference: number, target: { '$class': string, '$id': string, '$path'?: string, fields: Record<string, string | string[]>, title: string } }} */
166
156
  const resolved_link = {
167
157
  reference: output_item.reference,
168
158
  label: output_item.label,
@@ -178,16 +168,5 @@ function formatJsonResolvedLink(output_item) {
178
168
  resolved_link.target.$path = output_item.target.path;
179
169
  }
180
170
 
181
- if (output_item.target.derived_summary) {
182
- resolved_link.target.derived_summary =
183
- output_item.target.derived_summary.name;
184
- resolved_link.target.derived = Object.fromEntries(
185
- output_item.target.derived_summary.fields.map((field) => [
186
- field.name,
187
- field.value,
188
- ]),
189
- );
190
- }
191
-
192
171
  return resolved_link;
193
172
  }
@@ -1,38 +1,53 @@
1
+ /* eslint-disable max-lines */
1
2
  /**
2
3
  * @import { OutputNodeItem, OutputResolvedLinkItem, OutputStoredQueryItem, OutputView, QueryOutputView, RefsOutputView, ShowOutputView } from '../output-view.types.ts';
3
4
  */
4
5
 
5
6
  import {
6
- formatOutputNodeMetadataRows,
7
- formatResolvedLinkMetadataRows,
7
+ formatOutputNodeStoredMetadataRow,
8
+ formatResolvedLinkStoredMetadataRow,
8
9
  } from '../format-output-metadata.js';
10
+ import {
11
+ formatCompactMetadataLabel,
12
+ formatCompactTitleRow,
13
+ getCompactLeftTitleWidth,
14
+ wrapCompactBodyText,
15
+ } from '../compact-layout.js';
9
16
  import { formatNodeHeader } from '../format-node-header.js';
10
- import { formatOutputItemBlock } from '../format-output-item-block.js';
11
- import { layoutIncomingReferenceLines } from '../layout-incoming-references.js';
17
+ import { formatStoredQueryBlock } from '../format-stored-query-block.js';
18
+ import {
19
+ collectIncomingRefHeaders,
20
+ createIncomingTreeRenderOptions,
21
+ layoutIncomingReferenceLines,
22
+ } from '../layout-incoming-references.js';
12
23
  import { layoutIncomingSummaryLines } from '../layout-incoming-summary-lines.js';
13
- import { layoutStoredQueries } from '../layout-stored-queries.js';
24
+ import {
25
+ formatResolvedLinkBodyLines,
26
+ formatResolvedLinkHeader,
27
+ } from '../resolved-link-layout.js';
14
28
 
15
29
  /**
16
30
  * Render the canonical plain output for one output view.
17
31
  *
18
32
  * @param {OutputView} output_view
33
+ * @param {{ is_tty?: boolean, terminal_width?: number }=} render_options
19
34
  * @returns {string}
20
35
  */
21
- export function renderPlainOutput(output_view) {
36
+ export function renderPlainOutput(output_view, render_options = {}) {
22
37
  if (output_view.command === 'query') {
23
- return renderPlainQueryOutput(output_view);
38
+ return renderPlainQueryOutput(output_view, render_options);
24
39
  }
25
40
 
26
41
  if (output_view.command === 'queries') {
27
- return renderPlainStoredQueries(output_view);
42
+ return renderPlainStoredQueries(output_view, render_options);
28
43
  }
29
44
 
30
45
  if (output_view.command === 'refs') {
31
- return renderPlainRefsOutput(output_view);
46
+ return renderPlainRefsOutput(output_view, render_options);
32
47
  }
33
48
 
34
49
  if (output_view.command === 'show') {
35
- return renderPlainShowOutput(output_view);
50
+ return renderPlainShowOutput(output_view, render_options);
36
51
  }
37
52
 
38
53
  throw new Error('Unsupported output view command.');
@@ -40,20 +55,31 @@ export function renderPlainOutput(output_view) {
40
55
 
41
56
  /**
42
57
  * @param {QueryOutputView} output_view
58
+ * @param {{ is_tty?: boolean, terminal_width?: number }} render_options
43
59
  * @returns {string}
44
60
  */
45
- function renderPlainQueryOutput(output_view) {
61
+ function renderPlainQueryOutput(output_view, render_options) {
46
62
  const footer = renderPlainQueryFooter(output_view.summary, output_view.hints);
47
63
 
48
64
  if (output_view.items.length === 0) {
49
65
  return renderPlainEmptyQuery(footer);
50
66
  }
51
67
 
68
+ const left_title_width = getCompactLeftTitleWidth(
69
+ output_view.items.map((output_item) => formatNodeHeader(output_item)),
70
+ );
71
+ const output_blocks = output_view.items.map((output_item) =>
72
+ formatPlainNodeItem(output_item, {
73
+ ...render_options,
74
+ left_title_width,
75
+ }),
76
+ );
77
+
52
78
  if (footer.length === 0) {
53
- return `${output_view.items.map(formatPlainNodeItem).join('\n\n')}\n`;
79
+ return `${output_blocks.join('\n\n')}\n`;
54
80
  }
55
81
 
56
- return `${output_view.items.map(formatPlainNodeItem).join('\n\n')}\n\n${footer}\n`;
82
+ return `${output_blocks.join('\n\n')}\n\n${footer}\n`;
57
83
  }
58
84
 
59
85
  /**
@@ -70,36 +96,46 @@ function renderPlainEmptyQuery(footer) {
70
96
 
71
97
  /**
72
98
  * @param {Extract<OutputView, { command: 'queries' }>} output_view
99
+ * @param {{ is_tty?: boolean, terminal_width?: number }} render_options
73
100
  * @returns {string}
74
101
  */
75
- function renderPlainStoredQueries(output_view) {
102
+ function renderPlainStoredQueries(output_view, render_options) {
76
103
  if (output_view.items.length === 0) {
77
104
  return '';
78
105
  }
79
106
 
80
- const output_lines = layoutStoredQueries(output_view.items).map(
81
- formatPlainStoredQueryLine,
107
+ const output_blocks = output_view.items.map((output_item) =>
108
+ formatPlainStoredQueryBlock(output_item, render_options),
82
109
  );
83
110
 
84
111
  if (output_view.hints.length === 0) {
85
- return `${output_lines.join('\n')}\n`;
112
+ return `${output_blocks.join('\n')}\n`;
86
113
  }
87
114
 
88
- return `${output_lines.join('\n')}\n${output_view.hints.join('\n')}\n`;
115
+ return `${output_blocks.join('\n')}\n${output_view.hints.join('\n')}\n`;
89
116
  }
90
117
 
91
118
  /**
92
119
  * @param {ShowOutputView} output_view
120
+ * @param {{ is_tty?: boolean, terminal_width?: number }} render_options
93
121
  * @returns {string}
94
122
  */
95
- function renderPlainShowOutput(output_view) {
123
+ function renderPlainShowOutput(output_view, render_options) {
96
124
  const rendered_source = trimTrailingLineBreaks(output_view.rendered_source);
97
125
  const incoming_summary = renderPlainIncomingSummary(output_view);
98
126
 
99
127
  if (output_view.items.length === 0 && incoming_summary.length === 0) {
100
128
  return `${rendered_source}\n`;
101
129
  }
102
- const summary_blocks = output_view.items.map(formatPlainResolvedLinkItem);
130
+ const left_title_width = getCompactLeftTitleWidth(
131
+ output_view.items.map(formatResolvedLinkHeader),
132
+ );
133
+ const summary_blocks = output_view.items.map((output_item) =>
134
+ formatPlainResolvedLinkItem(output_item, {
135
+ ...render_options,
136
+ left_title_width,
137
+ }),
138
+ );
103
139
 
104
140
  if (incoming_summary.length > 0) {
105
141
  summary_blocks.push(incoming_summary);
@@ -110,11 +146,27 @@ function renderPlainShowOutput(output_view) {
110
146
 
111
147
  /**
112
148
  * @param {RefsOutputView} output_view
149
+ * @param {{ is_tty?: boolean, terminal_width?: number }} render_options
113
150
  * @returns {string}
114
151
  */
115
- function renderPlainRefsOutput(output_view) {
116
- const node_summary = formatPlainNodeItem(output_view.node);
117
- const output_lines = layoutIncomingReferenceLines(output_view.incoming);
152
+ function renderPlainRefsOutput(output_view, render_options) {
153
+ const left_title_width = getCompactLeftTitleWidth(
154
+ collectIncomingRefHeaders(output_view),
155
+ );
156
+ const incoming_render_options =
157
+ createIncomingTreeRenderOptions(render_options);
158
+ const node_summary = formatPlainNodeItem(output_view.node, {
159
+ ...render_options,
160
+ left_title_width,
161
+ });
162
+ const output_lines = layoutIncomingReferenceLines(output_view.incoming, {
163
+ format_node_block(output_item) {
164
+ return formatPlainNodeItem(output_item, {
165
+ ...incoming_render_options,
166
+ left_title_width,
167
+ });
168
+ },
169
+ });
118
170
 
119
171
  if (output_lines.length === 0) {
120
172
  return `${node_summary}\n\nNo incoming references.\n`;
@@ -125,13 +177,51 @@ function renderPlainRefsOutput(output_view) {
125
177
 
126
178
  /**
127
179
  * @param {OutputNodeItem} output_item
180
+ * @param {{ is_tty?: boolean, left_title_width: number, terminal_width?: number }} render_options
128
181
  * @returns {string}
129
182
  */
130
- function formatPlainNodeItem(output_item) {
131
- return formatOutputItemBlock({
132
- header: formatNodeHeader(output_item),
133
- metadata_rows: formatOutputNodeMetadataRows(output_item),
134
- title: output_item.title,
183
+ function formatPlainNodeItem(output_item, render_options) {
184
+ const metadata_label = formatStoredMetadataLabel(
185
+ formatOutputNodeStoredMetadataRow(output_item),
186
+ );
187
+ /** @type {string[]} */
188
+ const output_lines = [
189
+ formatCompactTitleRow({
190
+ is_tty: render_options.is_tty,
191
+ left_title: formatNodeHeader(output_item),
192
+ left_title_width: render_options.left_title_width,
193
+ right_title: metadata_label,
194
+ terminal_width: render_options.terminal_width,
195
+ }),
196
+ ];
197
+
198
+ output_lines.push(` ${output_item.title}`);
199
+
200
+ if (output_item.description) {
201
+ for (const description_line of wrapCompactBodyText(
202
+ output_item.description,
203
+ render_options,
204
+ )) {
205
+ output_lines.push(
206
+ description_line.length > 0 ? ` ${description_line}` : '',
207
+ );
208
+ }
209
+ }
210
+
211
+ return output_lines.join('\n');
212
+ }
213
+
214
+ /**
215
+ * @param {OutputStoredQueryItem} output_item
216
+ * @param {{ is_tty?: boolean, terminal_width?: number }} render_options
217
+ * @returns {string}
218
+ */
219
+ function formatPlainStoredQueryBlock(output_item, render_options) {
220
+ return formatStoredQueryBlock(output_item, render_options, {
221
+ format_line: formatPlainStoredQueryLine,
222
+ format_name(text) {
223
+ return text;
224
+ },
135
225
  });
136
226
  }
137
227
 
@@ -145,15 +235,33 @@ function formatPlainStoredQueryLine(line_segments) {
145
235
 
146
236
  /**
147
237
  * @param {OutputResolvedLinkItem} output_item
238
+ * @param {{ is_tty?: boolean, left_title_width: number, terminal_width?: number }} render_options
148
239
  * @returns {string}
149
240
  */
150
- function formatPlainResolvedLinkItem(output_item) {
151
- return formatOutputItemBlock({
152
- header: `[${output_item.reference}] ${output_item.target.kind} ${output_item.target.path ?? output_item.target.id}`,
153
- metadata_rows: formatResolvedLinkMetadataRows(output_item.target),
154
- metadata_indent: ' ',
155
- title: output_item.target.title,
156
- });
241
+ function formatPlainResolvedLinkItem(output_item, render_options) {
242
+ const metadata_label = formatStoredMetadataLabel(
243
+ formatResolvedLinkStoredMetadataRow(output_item.target),
244
+ );
245
+ /** @type {string[]} */
246
+ const output_lines = [
247
+ formatCompactTitleRow({
248
+ is_tty: render_options.is_tty,
249
+ left_title: formatResolvedLinkHeader(output_item),
250
+ left_title_width: render_options.left_title_width,
251
+ right_title: metadata_label,
252
+ terminal_width: render_options.terminal_width,
253
+ }),
254
+ ];
255
+
256
+ output_lines.push(
257
+ ...formatResolvedLinkBodyLines(output_item, {
258
+ body_indent: ' ',
259
+ is_tty: render_options.is_tty,
260
+ terminal_width: render_options.terminal_width,
261
+ }),
262
+ );
263
+
264
+ return output_lines.join('\n');
157
265
  }
158
266
 
159
267
  /**
@@ -179,6 +287,18 @@ function hasIncomingSummary(incoming_summary) {
179
287
  return Object.keys(incoming_summary).length > 0;
180
288
  }
181
289
 
290
+ /**
291
+ * @param {string | undefined} metadata_row
292
+ * @returns {string | undefined}
293
+ */
294
+ function formatStoredMetadataLabel(metadata_row) {
295
+ if (!metadata_row) {
296
+ return undefined;
297
+ }
298
+
299
+ return formatCompactMetadataLabel([metadata_row]);
300
+ }
301
+
182
302
  /**
183
303
  * @param {string} value
184
304
  * @returns {string}