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
@@ -1,3 +1,4 @@
1
+ /* eslint-disable max-lines */
1
2
  /**
2
3
  * @import { CliColorMode } from '../../cli/arguments.types.ts';
3
4
  * @import { OutputNodeItem, OutputResolvedLinkItem, OutputStoredQueryItem, OutputView, QueryOutputView, RefsOutputView, ShowOutputView } from '../output-view.types.ts';
@@ -6,14 +7,27 @@
6
7
  import { Ansis } from 'ansis';
7
8
 
8
9
  import {
9
- formatOutputNodeMetadataRows,
10
- formatResolvedLinkMetadataRows,
10
+ formatOutputNodeStoredMetadataRow,
11
+ formatResolvedLinkStoredMetadataRow,
11
12
  } from '../format-output-metadata.js';
13
+ import {
14
+ formatCompactMetadataLabel,
15
+ formatCompactTitleRow,
16
+ getCompactLeftTitleWidth,
17
+ wrapCompactBodyText,
18
+ } from '../compact-layout.js';
12
19
  import { formatNodeHeader } from '../format-node-header.js';
13
- import { formatOutputItemBlock } from '../format-output-item-block.js';
14
- import { layoutIncomingReferenceLines } from '../layout-incoming-references.js';
20
+ import { formatStoredQueryBlock } from '../format-stored-query-block.js';
21
+ import {
22
+ collectIncomingRefHeaders,
23
+ createIncomingTreeRenderOptions,
24
+ layoutIncomingReferenceLines,
25
+ } from '../layout-incoming-references.js';
15
26
  import { layoutIncomingSummaryLines } from '../layout-incoming-summary-lines.js';
16
- import { layoutStoredQueries } from '../layout-stored-queries.js';
27
+ import {
28
+ formatResolvedLinkBodyLines,
29
+ formatResolvedLinkHeader,
30
+ } from '../resolved-link-layout.js';
17
31
  import { renderRichSource } from '../rich-source/render.js';
18
32
 
19
33
  const FULL_WIDTH_DIVIDER = ` ${'─'.repeat(78)} `;
@@ -22,22 +36,22 @@ const FULL_WIDTH_DIVIDER = ` ${'─'.repeat(78)} `;
22
36
  * Render styled rich output while preserving the plain layout.
23
37
  *
24
38
  * @param {OutputView} output_view
25
- * @param {{ color_mode: CliColorMode, color_enabled: boolean }} render_options
39
+ * @param {{ color_mode: CliColorMode, color_enabled: boolean, is_tty?: boolean, terminal_width?: number }} render_options
26
40
  * @returns {Promise<string>}
27
41
  */
28
42
  export async function renderRichOutput(output_view, render_options) {
29
43
  const ansi = createAnsi(render_options.color_enabled);
30
44
 
31
45
  if (output_view.command === 'query') {
32
- return renderRichQueryOutput(output_view, ansi);
46
+ return renderRichQueryOutput(output_view, render_options, ansi);
33
47
  }
34
48
 
35
49
  if (output_view.command === 'queries') {
36
- return renderRichStoredQueries(output_view, ansi);
50
+ return renderRichStoredQueries(output_view, render_options, ansi);
37
51
  }
38
52
 
39
53
  if (output_view.command === 'refs') {
40
- return renderRichRefsOutput(output_view, ansi);
54
+ return renderRichRefsOutput(output_view, render_options, ansi);
41
55
  }
42
56
  if (output_view.command === 'show') {
43
57
  return renderRichShowOutput(output_view, render_options, ansi);
@@ -48,10 +62,11 @@ export async function renderRichOutput(output_view, render_options) {
48
62
 
49
63
  /**
50
64
  * @param {QueryOutputView} output_view
65
+ * @param {{ is_tty?: boolean, terminal_width?: number }} render_options
51
66
  * @param {Ansis} ansi
52
67
  * @returns {string}
53
68
  */
54
- function renderRichQueryOutput(output_view, ansi) {
69
+ function renderRichQueryOutput(output_view, render_options, ansi) {
55
70
  const footer = renderRichQueryFooter(
56
71
  output_view.summary,
57
72
  output_view.hints,
@@ -62,11 +77,21 @@ function renderRichQueryOutput(output_view, ansi) {
62
77
  return renderRichEmptyQuery(footer, ansi);
63
78
  }
64
79
 
80
+ const left_title_width = getCompactLeftTitleWidth(
81
+ output_view.items.map((output_item) => formatNodeHeader(output_item)),
82
+ );
83
+ const output_blocks = output_view.items.map((output_item) =>
84
+ formatRichNodeItem(output_item, ansi, {
85
+ ...render_options,
86
+ left_title_width,
87
+ }),
88
+ );
89
+
65
90
  if (footer.length === 0) {
66
- return `${output_view.items.map((item) => formatRichNodeItem(item, ansi)).join('\n\n')}\n`;
91
+ return `${output_blocks.join('\n\n')}\n`;
67
92
  }
68
93
 
69
- return `${output_view.items.map((item) => formatRichNodeItem(item, ansi)).join('\n\n')}\n\n${footer}\n`;
94
+ return `${output_blocks.join('\n\n')}\n\n${footer}\n`;
70
95
  }
71
96
 
72
97
  /**
@@ -84,28 +109,29 @@ function renderRichEmptyQuery(footer, ansi) {
84
109
 
85
110
  /**
86
111
  * @param {Extract<OutputView, { command: 'queries' }>} output_view
112
+ * @param {{ is_tty?: boolean, terminal_width?: number }} render_options
87
113
  * @param {Ansis} ansi
88
114
  * @returns {string}
89
115
  */
90
- function renderRichStoredQueries(output_view, ansi) {
116
+ function renderRichStoredQueries(output_view, render_options, ansi) {
91
117
  if (output_view.items.length === 0) {
92
118
  return '';
93
119
  }
94
120
 
95
- const output_lines = layoutStoredQueries(output_view.items).map(
96
- (line_segments) => formatRichStoredQueryLine(line_segments, ansi),
121
+ const output_blocks = output_view.items.map((output_item) =>
122
+ formatRichStoredQueryBlock(output_item, ansi, render_options),
97
123
  );
98
124
 
99
125
  if (output_view.hints.length === 0) {
100
- return `${output_lines.join('\n')}\n`;
126
+ return `${output_blocks.join('\n')}\n`;
101
127
  }
102
128
 
103
- return `${output_lines.join('\n')}\n${output_view.hints.map((hint) => ansi.gray(hint)).join('\n')}\n`;
129
+ return `${output_blocks.join('\n')}\n${output_view.hints.map((hint) => ansi.gray(hint)).join('\n')}\n`;
104
130
  }
105
131
 
106
132
  /**
107
133
  * @param {ShowOutputView} output_view
108
- * @param {{ color_mode: CliColorMode, color_enabled: boolean }} render_options
134
+ * @param {{ color_mode: CliColorMode, color_enabled: boolean, is_tty?: boolean, terminal_width?: number }} render_options
109
135
  * @param {Ansis} ansi
110
136
  * @returns {Promise<string>}
111
137
  */
@@ -119,8 +145,15 @@ async function renderRichShowOutput(output_view, render_options, ansi) {
119
145
  return `${rendered_source}\n`;
120
146
  }
121
147
 
148
+ const left_title_width = getCompactLeftTitleWidth(
149
+ output_view.items.map(formatResolvedLinkHeader),
150
+ );
122
151
  const summary_items = output_view.items.map((item) =>
123
- formatRichResolvedLinkItem(item, ansi),
152
+ formatRichResolvedLinkItem(item, ansi, {
153
+ is_tty: render_options.is_tty,
154
+ left_title_width,
155
+ terminal_width: render_options.terminal_width,
156
+ }),
124
157
  );
125
158
 
126
159
  if (incoming_summary.length > 0) {
@@ -132,14 +165,26 @@ async function renderRichShowOutput(output_view, render_options, ansi) {
132
165
 
133
166
  /**
134
167
  * @param {RefsOutputView} output_view
168
+ * @param {{ is_tty?: boolean, terminal_width?: number }} render_options
135
169
  * @param {Ansis} ansi
136
170
  * @returns {string}
137
171
  */
138
- function renderRichRefsOutput(output_view, ansi) {
139
- const node_summary = formatRichNodeItem(output_view.node, ansi);
172
+ function renderRichRefsOutput(output_view, render_options, ansi) {
173
+ const left_title_width = getCompactLeftTitleWidth(
174
+ collectIncomingRefHeaders(output_view),
175
+ );
176
+ const incoming_render_options =
177
+ createIncomingTreeRenderOptions(render_options);
178
+ const node_summary = formatRichNodeItem(output_view.node, ansi, {
179
+ ...render_options,
180
+ left_title_width,
181
+ });
140
182
  const output_lines = layoutIncomingReferenceLines(output_view.incoming, {
141
- format_node_header(output_item) {
142
- return ansi.green(formatNodeHeader(output_item));
183
+ format_node_block(output_item) {
184
+ return formatRichNodeItem(output_item, ansi, {
185
+ ...incoming_render_options,
186
+ left_title_width,
187
+ });
143
188
  },
144
189
  format_relation_header(relation_name, relation_count) {
145
190
  return `${ansi.bold(relation_name)} ${ansi.gray(`(${relation_count})`)}`;
@@ -154,14 +199,44 @@ function renderRichRefsOutput(output_view, ansi) {
154
199
  /**
155
200
  * @param {OutputNodeItem} output_item
156
201
  * @param {Ansis} ansi
202
+ * @param {{ is_tty?: boolean, left_title_width: number, terminal_width?: number }} render_options
157
203
  * @returns {string}
158
204
  */
159
- function formatRichNodeItem(output_item, ansi) {
160
- return formatOutputItemBlock({
161
- header: ansi.green(formatNodeHeader(output_item)),
162
- metadata_rows: formatOutputNodeMetadataRows(output_item),
163
- title: output_item.title,
164
- });
205
+ function formatRichNodeItem(output_item, ansi, render_options) {
206
+ const metadata_label = formatStoredMetadataLabel(
207
+ formatOutputNodeStoredMetadataRow(output_item),
208
+ );
209
+ /** @type {string[]} */
210
+ const output_lines = [
211
+ formatCompactTitleRow({
212
+ format_left(text) {
213
+ return ansi.green(text);
214
+ },
215
+ format_right(text) {
216
+ return formatRichCompactMetadataLabel(text, ansi);
217
+ },
218
+ is_tty: render_options.is_tty,
219
+ left_title: formatNodeHeader(output_item),
220
+ left_title_width: render_options.left_title_width,
221
+ right_title: metadata_label,
222
+ terminal_width: render_options.terminal_width,
223
+ }),
224
+ ];
225
+
226
+ output_lines.push(` ${output_item.title}`);
227
+
228
+ if (output_item.description) {
229
+ for (const description_line of wrapCompactBodyText(
230
+ output_item.description,
231
+ render_options,
232
+ )) {
233
+ output_lines.push(
234
+ formatRichDescriptionLine(description_line, ' ', ansi),
235
+ );
236
+ }
237
+ }
238
+
239
+ return output_lines.join('\n');
165
240
  }
166
241
 
167
242
  /**
@@ -176,19 +251,72 @@ function formatRichStoredQueryLine(line_segments, ansi) {
176
251
  }
177
252
 
178
253
  /**
179
- * @param {OutputResolvedLinkItem} output_item
254
+ * @param {OutputStoredQueryItem} output_item
180
255
  * @param {Ansis} ansi
256
+ * @param {{ is_tty?: boolean, terminal_width?: number }} render_options
181
257
  * @returns {string}
182
258
  */
183
- function formatRichResolvedLinkItem(output_item, ansi) {
184
- return formatOutputItemBlock({
185
- header: `${ansi.gray(`[${output_item.reference}]`)} ${ansi.green(`${output_item.target.kind} ${output_item.target.path ?? output_item.target.id}`)}`,
186
- metadata_rows: formatResolvedLinkMetadataRows(output_item.target),
187
- metadata_indent: ' ',
188
- title: output_item.target.title,
259
+ function formatRichStoredQueryBlock(output_item, ansi, render_options) {
260
+ return formatStoredQueryBlock(output_item, render_options, {
261
+ format_description(text) {
262
+ return ansi.gray(text);
263
+ },
264
+ format_line(line_segments) {
265
+ return formatRichStoredQueryLine(line_segments, ansi);
266
+ },
267
+ format_name(text) {
268
+ return ansi.green(text);
269
+ },
189
270
  });
190
271
  }
191
272
 
273
+ /**
274
+ * @param {OutputResolvedLinkItem} output_item
275
+ * @param {Ansis} ansi
276
+ * @param {{ is_tty?: boolean, left_title_width: number, terminal_width?: number }} render_options
277
+ * @returns {string}
278
+ */
279
+ function formatRichResolvedLinkItem(output_item, ansi, render_options) {
280
+ const metadata_label = formatStoredMetadataLabel(
281
+ formatResolvedLinkStoredMetadataRow(output_item.target),
282
+ );
283
+ /** @type {string[]} */
284
+ const output_lines = [
285
+ formatCompactTitleRow({
286
+ format_left(text) {
287
+ const closing_bracket_index = text.indexOf(']');
288
+
289
+ if (closing_bracket_index === -1) {
290
+ return ansi.green(text);
291
+ }
292
+
293
+ const reference_token = text.slice(0, closing_bracket_index + 1);
294
+ const header_suffix = text.slice(closing_bracket_index + 1);
295
+
296
+ return `${ansi.gray(reference_token)}${ansi.green(header_suffix)}`;
297
+ },
298
+ format_right(text) {
299
+ return formatRichCompactMetadataLabel(text, ansi);
300
+ },
301
+ is_tty: render_options.is_tty,
302
+ left_title: formatResolvedLinkHeader(output_item),
303
+ left_title_width: render_options.left_title_width,
304
+ right_title: metadata_label,
305
+ terminal_width: render_options.terminal_width,
306
+ }),
307
+ ];
308
+
309
+ output_lines.push(
310
+ ...formatRichResolvedLinkBodyLines(output_item, ansi, {
311
+ body_indent: ' ',
312
+ is_tty: render_options.is_tty,
313
+ terminal_width: render_options.terminal_width,
314
+ }),
315
+ );
316
+
317
+ return output_lines.join('\n');
318
+ }
319
+
192
320
  /**
193
321
  * @param {ShowOutputView} output_view
194
322
  * @param {Ansis} ansi
@@ -223,6 +351,92 @@ function createAnsi(color_enabled) {
223
351
  return new Ansis(color_enabled ? 3 : 0);
224
352
  }
225
353
 
354
+ /**
355
+ * @param {string | undefined} metadata_row
356
+ * @returns {string | undefined}
357
+ */
358
+ function formatStoredMetadataLabel(metadata_row) {
359
+ if (!metadata_row) {
360
+ return undefined;
361
+ }
362
+
363
+ return formatCompactMetadataLabel([metadata_row]);
364
+ }
365
+
366
+ /**
367
+ * @param {string} metadata_label
368
+ * @param {Ansis} ansi
369
+ * @returns {string}
370
+ */
371
+ function formatRichCompactMetadataLabel(metadata_label, ansi) {
372
+ return [...metadata_label]
373
+ .map((character) =>
374
+ character === '(' ||
375
+ character === ')' ||
376
+ character === ',' ||
377
+ character === '='
378
+ ? ansi.gray(character)
379
+ : character,
380
+ )
381
+ .join('');
382
+ }
383
+
384
+ /**
385
+ * @param {string} description_line
386
+ * @param {string} indent
387
+ * @param {Ansis} ansi
388
+ * @returns {string}
389
+ */
390
+ function formatRichDescriptionLine(description_line, indent, ansi) {
391
+ if (description_line.length === 0) {
392
+ return '';
393
+ }
394
+
395
+ return `${indent}${ansi.gray(description_line)}`;
396
+ }
397
+
398
+ /**
399
+ * @param {OutputResolvedLinkItem} output_item
400
+ * @param {Ansis} ansi
401
+ * @param {{ body_indent?: string, is_tty?: boolean, terminal_width?: number }} render_options
402
+ * @returns {string[]}
403
+ */
404
+ function formatRichResolvedLinkBodyLines(output_item, ansi, render_options) {
405
+ const body_indent = render_options.body_indent ?? ' ';
406
+ const body_lines = formatResolvedLinkBodyLines(output_item, render_options);
407
+
408
+ if (body_lines.length <= 1) {
409
+ return body_lines;
410
+ }
411
+
412
+ return [
413
+ body_lines[0],
414
+ ...body_lines
415
+ .slice(1)
416
+ .map((line) =>
417
+ formatRichIndentedDescriptionLine(line, body_indent, ansi),
418
+ ),
419
+ ];
420
+ }
421
+
422
+ /**
423
+ * @param {string} line
424
+ * @param {string} indent
425
+ * @param {Ansis} ansi
426
+ * @returns {string}
427
+ */
428
+ function formatRichIndentedDescriptionLine(line, indent, ansi) {
429
+ if (line.length === 0) {
430
+ return '';
431
+ }
432
+
433
+ if (!line.startsWith(indent)) {
434
+ return ansi.gray(line);
435
+ }
436
+
437
+ return `${indent}${ansi.gray(line.slice(indent.length))}`;
438
+ }
439
+
226
440
  /**
227
441
  * @param {{ kind: 'description' | 'field_name' | 'keyword' | 'literal' | 'name' | 'operator' | 'plain', text: string }} line_segment
228
442
  * @param {Ansis} ansi
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @import { OutputResolvedLinkItem } from './output-view.types.ts';
3
+ */
4
+
5
+ import { wrapCompactBodyText } from './compact-layout.js';
6
+
7
+ /**
8
+ * @param {OutputResolvedLinkItem} output_item
9
+ * @returns {string}
10
+ */
11
+ export function formatResolvedLinkHeader(output_item) {
12
+ return `[${output_item.reference}] ${output_item.target.kind} ${output_item.target.path ?? output_item.target.id}`;
13
+ }
14
+
15
+ /**
16
+ * @param {OutputResolvedLinkItem} output_item
17
+ * @param {{ body_indent?: string, is_tty?: boolean, terminal_width?: number }} render_options
18
+ * @returns {string[]}
19
+ */
20
+ export function formatResolvedLinkBodyLines(output_item, render_options = {}) {
21
+ const body_indent = render_options.body_indent ?? ' ';
22
+ /** @type {string[]} */
23
+ const output_lines = [`${body_indent}${output_item.target.title}`];
24
+
25
+ if (!output_item.target.description) {
26
+ return output_lines;
27
+ }
28
+
29
+ for (const description_line of wrapCompactBodyText(
30
+ output_item.target.description,
31
+ {
32
+ body_indent,
33
+ is_tty: render_options.is_tty,
34
+ terminal_width: render_options.terminal_width,
35
+ },
36
+ )) {
37
+ output_lines.push(
38
+ description_line.length > 0 ? `${body_indent}${description_line}` : '',
39
+ );
40
+ }
41
+
42
+ return output_lines;
43
+ }