patram 0.1.1 → 0.2.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.
- package/lib/build-graph-identity.js +39 -7
- package/lib/build-graph.js +14 -1
- package/lib/cli-help-metadata.js +552 -0
- package/lib/derived-summary.js +278 -0
- package/lib/format-derived-summary-row.js +9 -0
- package/lib/format-node-header.js +19 -0
- package/lib/format-output-item-block.js +22 -0
- package/lib/format-output-metadata.js +62 -0
- package/lib/layout-stored-queries.js +150 -2
- package/lib/load-patram-config.js +401 -2
- package/lib/load-patram-config.types.ts +31 -0
- package/lib/output-view.types.ts +15 -0
- package/lib/parse-cli-arguments-helpers.js +263 -90
- package/lib/parse-cli-arguments.js +160 -8
- package/lib/parse-cli-arguments.types.ts +48 -3
- package/lib/parse-where-clause.js +604 -209
- package/lib/parse-where-clause.types.ts +70 -0
- package/lib/patram-cli.js +144 -17
- package/lib/patram.js +6 -0
- package/lib/query-graph.js +231 -119
- package/lib/query-inspection.js +523 -0
- package/lib/render-check-output.js +1 -1
- package/lib/render-cli-help.js +419 -0
- package/lib/render-json-output.js +57 -4
- package/lib/render-output-view.js +37 -8
- package/lib/render-plain-output.js +31 -86
- package/lib/render-rich-output.js +34 -87
- package/lib/resolve-where-clause.js +18 -3
- package/lib/tagged-fenced-block-error.js +17 -0
- package/lib/tagged-fenced-block-markdown.js +111 -0
- package/lib/tagged-fenced-block-metadata.js +97 -0
- package/lib/tagged-fenced-block-parser.js +292 -0
- package/lib/tagged-fenced-blocks.js +100 -0
- package/lib/tagged-fenced-blocks.types.ts +38 -0
- package/package.json +8 -3
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
/* eslint-disable max-lines */
|
|
2
|
+
/**
|
|
3
|
+
* @import {
|
|
4
|
+
* CliCommandName,
|
|
5
|
+
* CliHelpTopicName,
|
|
6
|
+
* CliParseError,
|
|
7
|
+
* ParsedCliHelpRequest,
|
|
8
|
+
* } from './parse-cli-arguments.types.ts';
|
|
9
|
+
* @import { PatramDiagnostic } from './load-patram-config.types.ts';
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
getCommandDefinition,
|
|
14
|
+
getHelpTopicDefinition,
|
|
15
|
+
getRootHelpDefinition,
|
|
16
|
+
listCommandNames,
|
|
17
|
+
listHelpTopicNames,
|
|
18
|
+
} from './cli-help-metadata.js';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {ParsedCliHelpRequest} help_request
|
|
22
|
+
* @returns {string}
|
|
23
|
+
*/
|
|
24
|
+
export function renderHelpRequest(help_request) {
|
|
25
|
+
if (help_request.target_kind === 'root') {
|
|
26
|
+
return renderRootHelp();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (help_request.target_kind === 'command') {
|
|
30
|
+
return renderCommandHelp(
|
|
31
|
+
/** @type {CliCommandName} */ (help_request.target_name),
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return renderHelpTopic(
|
|
36
|
+
/** @type {CliHelpTopicName} */ (help_request.target_name),
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {CliParseError} parse_error
|
|
42
|
+
* @returns {string}
|
|
43
|
+
*/
|
|
44
|
+
export function renderCliParseError(parse_error) {
|
|
45
|
+
if (parse_error.code === 'unknown_command') {
|
|
46
|
+
return renderUnknownCommandError(parse_error.token, parse_error.suggestion);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (parse_error.code === 'unknown_help_target') {
|
|
50
|
+
return renderUnknownHelpTargetError(
|
|
51
|
+
parse_error.token,
|
|
52
|
+
parse_error.suggestion,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (parse_error.code === 'unknown_option') {
|
|
57
|
+
return renderUnknownOptionError(
|
|
58
|
+
parse_error.token,
|
|
59
|
+
parse_error.command_name,
|
|
60
|
+
parse_error.suggestion,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (parse_error.code === 'option_not_valid_for_command') {
|
|
65
|
+
return renderInvalidCommandOptionError(
|
|
66
|
+
parse_error.command_name,
|
|
67
|
+
parse_error.token,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (parse_error.code === 'missing_required_argument') {
|
|
72
|
+
return renderMissingRequiredArgumentError(
|
|
73
|
+
parse_error.command_name,
|
|
74
|
+
parse_error.argument_label,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return `${parse_error.message}\n`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @param {PatramDiagnostic} diagnostic
|
|
83
|
+
* @returns {string}
|
|
84
|
+
*/
|
|
85
|
+
export function renderInvalidWhereDiagnostic(diagnostic) {
|
|
86
|
+
const diagnostic_line = formatDiagnostic(diagnostic);
|
|
87
|
+
|
|
88
|
+
return joinOutputLines([
|
|
89
|
+
'Invalid where clause:',
|
|
90
|
+
` ${diagnostic_line}`,
|
|
91
|
+
'',
|
|
92
|
+
'Next:',
|
|
93
|
+
' patram help query-language',
|
|
94
|
+
]);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @returns {string}
|
|
99
|
+
*/
|
|
100
|
+
function renderRootHelp() {
|
|
101
|
+
const root_help = getRootHelpDefinition();
|
|
102
|
+
|
|
103
|
+
return joinOutputLines([
|
|
104
|
+
'Usage:',
|
|
105
|
+
...indentLines(root_help.usage_lines),
|
|
106
|
+
'',
|
|
107
|
+
root_help.summary,
|
|
108
|
+
'',
|
|
109
|
+
'Commands:',
|
|
110
|
+
...listCommandNames().map((command_name) =>
|
|
111
|
+
formatSummaryLine(
|
|
112
|
+
command_name,
|
|
113
|
+
getCommandDefinition(command_name).root_summary,
|
|
114
|
+
),
|
|
115
|
+
),
|
|
116
|
+
'',
|
|
117
|
+
'Global options:',
|
|
118
|
+
...indentLines(root_help.global_options),
|
|
119
|
+
'',
|
|
120
|
+
'Next:',
|
|
121
|
+
' patram help <command>',
|
|
122
|
+
]);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @param {CliCommandName} command_name
|
|
127
|
+
* @returns {string}
|
|
128
|
+
*/
|
|
129
|
+
function renderCommandHelp(command_name) {
|
|
130
|
+
const command_definition = getCommandDefinition(command_name);
|
|
131
|
+
/** @type {string[]} */
|
|
132
|
+
const output_lines = [
|
|
133
|
+
'Usage:',
|
|
134
|
+
...indentLines(command_definition.usage_lines),
|
|
135
|
+
'',
|
|
136
|
+
command_definition.summary,
|
|
137
|
+
];
|
|
138
|
+
|
|
139
|
+
if (
|
|
140
|
+
command_definition.syntax_lines &&
|
|
141
|
+
command_definition.syntax_lines.length
|
|
142
|
+
) {
|
|
143
|
+
output_lines.push(
|
|
144
|
+
'',
|
|
145
|
+
'Where clause:',
|
|
146
|
+
...indentLines(command_definition.syntax_lines),
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
output_lines.push(
|
|
151
|
+
'',
|
|
152
|
+
'Options:',
|
|
153
|
+
...command_definition.options.map((option) =>
|
|
154
|
+
formatSummaryLine(
|
|
155
|
+
option.label,
|
|
156
|
+
option.description,
|
|
157
|
+
command_definition.option_column_width,
|
|
158
|
+
),
|
|
159
|
+
),
|
|
160
|
+
'',
|
|
161
|
+
'Examples:',
|
|
162
|
+
...indentLines(command_definition.examples),
|
|
163
|
+
'',
|
|
164
|
+
'Related:',
|
|
165
|
+
...indentLines(
|
|
166
|
+
command_definition.related.map(
|
|
167
|
+
(related_name) => `patram ${related_name}`,
|
|
168
|
+
),
|
|
169
|
+
),
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
if (command_definition.help_topics.length > 0) {
|
|
173
|
+
output_lines.push(
|
|
174
|
+
'',
|
|
175
|
+
'Help topics:',
|
|
176
|
+
...indentLines(
|
|
177
|
+
command_definition.help_topics.map(
|
|
178
|
+
(help_topic_name) => `patram help ${help_topic_name}`,
|
|
179
|
+
),
|
|
180
|
+
),
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return joinOutputLines(output_lines);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* @param {CliHelpTopicName} help_topic_name
|
|
189
|
+
* @returns {string}
|
|
190
|
+
*/
|
|
191
|
+
function renderHelpTopic(help_topic_name) {
|
|
192
|
+
const help_topic = getHelpTopicDefinition(help_topic_name);
|
|
193
|
+
|
|
194
|
+
return joinOutputLines([
|
|
195
|
+
help_topic.lead,
|
|
196
|
+
'',
|
|
197
|
+
'Usage:',
|
|
198
|
+
...indentLines(help_topic.usage_lines),
|
|
199
|
+
'',
|
|
200
|
+
'Fields:',
|
|
201
|
+
...indentLines(help_topic.terms),
|
|
202
|
+
'',
|
|
203
|
+
'Relations:',
|
|
204
|
+
...help_topic.relation_terms.map((relation_term) =>
|
|
205
|
+
formatSummaryLine(
|
|
206
|
+
relation_term.label,
|
|
207
|
+
relation_term.description,
|
|
208
|
+
getSummaryColumnWidth(help_topic.relation_terms, 23),
|
|
209
|
+
),
|
|
210
|
+
),
|
|
211
|
+
'',
|
|
212
|
+
'Operators:',
|
|
213
|
+
...help_topic.operators.map((operator) =>
|
|
214
|
+
formatSummaryLine(
|
|
215
|
+
operator.label,
|
|
216
|
+
operator.description,
|
|
217
|
+
getSummaryColumnWidth(help_topic.operators, 7),
|
|
218
|
+
),
|
|
219
|
+
),
|
|
220
|
+
'',
|
|
221
|
+
'Examples:',
|
|
222
|
+
...indentLines(help_topic.examples),
|
|
223
|
+
]);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* @param {string} invalid_token
|
|
228
|
+
* @param {CliCommandName | undefined} suggestion
|
|
229
|
+
* @returns {string}
|
|
230
|
+
*/
|
|
231
|
+
function renderUnknownCommandError(invalid_token, suggestion) {
|
|
232
|
+
if (suggestion) {
|
|
233
|
+
return joinOutputLines([
|
|
234
|
+
`Unknown command: ${invalid_token}`,
|
|
235
|
+
'',
|
|
236
|
+
'Did you mean:',
|
|
237
|
+
` ${suggestion}`,
|
|
238
|
+
'',
|
|
239
|
+
'Next:',
|
|
240
|
+
` patram help ${suggestion}`,
|
|
241
|
+
]);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return joinOutputLines([
|
|
245
|
+
`Unknown command: ${invalid_token}`,
|
|
246
|
+
'',
|
|
247
|
+
'Commands:',
|
|
248
|
+
...indentLines(listCommandNames()),
|
|
249
|
+
'',
|
|
250
|
+
'Next:',
|
|
251
|
+
' patram --help',
|
|
252
|
+
]);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* @param {string} invalid_token
|
|
257
|
+
* @param {CliCommandName | undefined} command_name
|
|
258
|
+
* @param {string | undefined} suggestion
|
|
259
|
+
* @returns {string}
|
|
260
|
+
*/
|
|
261
|
+
function renderUnknownOptionError(invalid_token, command_name, suggestion) {
|
|
262
|
+
if (suggestion) {
|
|
263
|
+
return joinOutputLines([
|
|
264
|
+
`Unknown option: ${invalid_token}`,
|
|
265
|
+
'',
|
|
266
|
+
'Did you mean:',
|
|
267
|
+
` ${suggestion}`,
|
|
268
|
+
'',
|
|
269
|
+
'Next:',
|
|
270
|
+
` ${renderCommandHelpPath(command_name)}`,
|
|
271
|
+
]);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/** @type {string[]} */
|
|
275
|
+
const output_lines = [`Unknown option: ${invalid_token}`];
|
|
276
|
+
|
|
277
|
+
if (command_name) {
|
|
278
|
+
output_lines.push(
|
|
279
|
+
'',
|
|
280
|
+
'Usage:',
|
|
281
|
+
...indentLines(getCommandDefinition(command_name).usage_lines),
|
|
282
|
+
'',
|
|
283
|
+
'Next:',
|
|
284
|
+
` ${renderCommandHelpPath(command_name)}`,
|
|
285
|
+
);
|
|
286
|
+
} else {
|
|
287
|
+
output_lines.push('', 'Next:', ' patram --help');
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return joinOutputLines(output_lines);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* @param {CliCommandName} command_name
|
|
295
|
+
* @param {string} invalid_token
|
|
296
|
+
* @returns {string}
|
|
297
|
+
*/
|
|
298
|
+
function renderInvalidCommandOptionError(command_name, invalid_token) {
|
|
299
|
+
return joinOutputLines([
|
|
300
|
+
`Option not valid for command: ${invalid_token}`,
|
|
301
|
+
'',
|
|
302
|
+
'Usage:',
|
|
303
|
+
...indentLines(getCommandDefinition(command_name).usage_lines),
|
|
304
|
+
'',
|
|
305
|
+
'Next:',
|
|
306
|
+
` ${renderCommandHelpPath(command_name)}`,
|
|
307
|
+
]);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* @param {'query' | 'show'} command_name
|
|
312
|
+
* @param {string} argument_label
|
|
313
|
+
* @returns {string}
|
|
314
|
+
*/
|
|
315
|
+
function renderMissingRequiredArgumentError(command_name, argument_label) {
|
|
316
|
+
const command_definition = getCommandDefinition(command_name);
|
|
317
|
+
|
|
318
|
+
return joinOutputLines([
|
|
319
|
+
`Missing required argument: ${argument_label}`,
|
|
320
|
+
'',
|
|
321
|
+
'Usage:',
|
|
322
|
+
...indentLines(command_definition.missing_usage_lines),
|
|
323
|
+
'',
|
|
324
|
+
'Examples:',
|
|
325
|
+
...indentLines(command_definition.missing_argument_examples),
|
|
326
|
+
]);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* @param {string} invalid_token
|
|
331
|
+
* @param {CliCommandName | CliHelpTopicName | undefined} suggestion
|
|
332
|
+
* @returns {string}
|
|
333
|
+
*/
|
|
334
|
+
function renderUnknownHelpTargetError(invalid_token, suggestion) {
|
|
335
|
+
if (suggestion) {
|
|
336
|
+
return joinOutputLines([
|
|
337
|
+
`Unknown help topic or command: ${invalid_token}`,
|
|
338
|
+
'',
|
|
339
|
+
'Did you mean:',
|
|
340
|
+
` ${suggestion}`,
|
|
341
|
+
'',
|
|
342
|
+
'Next:',
|
|
343
|
+
` patram help ${suggestion}`,
|
|
344
|
+
]);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return joinOutputLines([
|
|
348
|
+
`Unknown help topic or command: ${invalid_token}`,
|
|
349
|
+
'',
|
|
350
|
+
'Help topics:',
|
|
351
|
+
...indentLines(listHelpTopicNames()),
|
|
352
|
+
'',
|
|
353
|
+
'Commands:',
|
|
354
|
+
...indentLines(listCommandNames()),
|
|
355
|
+
'',
|
|
356
|
+
'Next:',
|
|
357
|
+
' patram help query',
|
|
358
|
+
]);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* @param {PatramDiagnostic} diagnostic
|
|
363
|
+
* @returns {string}
|
|
364
|
+
*/
|
|
365
|
+
function formatDiagnostic(diagnostic) {
|
|
366
|
+
return `${diagnostic.path}:${diagnostic.line}:${diagnostic.column} ${diagnostic.level} ${diagnostic.code} ${diagnostic.message}`;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* @param {string | undefined} command_name
|
|
371
|
+
* @returns {string}
|
|
372
|
+
*/
|
|
373
|
+
function renderCommandHelpPath(command_name) {
|
|
374
|
+
if (!command_name) {
|
|
375
|
+
return 'patram --help';
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return `patram help ${command_name}`;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* @param {string[]} lines
|
|
383
|
+
* @returns {string[]}
|
|
384
|
+
*/
|
|
385
|
+
function indentLines(lines) {
|
|
386
|
+
return lines.map((line) => ` ${line}`);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* @param {string} label
|
|
391
|
+
* @param {string} description
|
|
392
|
+
* @param {number} width
|
|
393
|
+
* @returns {string}
|
|
394
|
+
*/
|
|
395
|
+
function formatSummaryLine(label, description, width = 9) {
|
|
396
|
+
return ` ${label.padEnd(width)}${description}`;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* @param {{ label: string }[]} items
|
|
401
|
+
* @param {number} minimum_width
|
|
402
|
+
* @returns {number}
|
|
403
|
+
*/
|
|
404
|
+
function getSummaryColumnWidth(items, minimum_width) {
|
|
405
|
+
const longest_label = items.reduce(
|
|
406
|
+
(current_width, item) => Math.max(current_width, item.label.length),
|
|
407
|
+
0,
|
|
408
|
+
);
|
|
409
|
+
|
|
410
|
+
return Math.max(minimum_width, longest_label + 2);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* @param {string[]} output_lines
|
|
415
|
+
* @returns {string}
|
|
416
|
+
*/
|
|
417
|
+
function joinOutputLines(output_lines) {
|
|
418
|
+
return `${output_lines.join('\n')}\n`;
|
|
419
|
+
}
|
|
@@ -39,6 +39,9 @@ export function renderJsonOutput(output_view) {
|
|
|
39
39
|
if (output_view.command === 'show') {
|
|
40
40
|
return `${JSON.stringify(
|
|
41
41
|
{
|
|
42
|
+
document: output_view.document
|
|
43
|
+
? formatJsonShowDocument(output_view.document)
|
|
44
|
+
: undefined,
|
|
42
45
|
source: output_view.source,
|
|
43
46
|
resolved_links: output_view.items.map(formatJsonResolvedLink),
|
|
44
47
|
},
|
|
@@ -52,10 +55,10 @@ export function renderJsonOutput(output_view) {
|
|
|
52
55
|
|
|
53
56
|
/**
|
|
54
57
|
* @param {OutputNodeItem} output_item
|
|
55
|
-
* @returns {{ id: string, kind: string, title: string, path: string, status?: string }}
|
|
58
|
+
* @returns {{ derived?: Record<string, boolean | number | string | null>, derived_summary?: string, id: string, kind: string, title: string, path: string, status?: string }}
|
|
56
59
|
*/
|
|
57
60
|
function formatJsonQueryItem(output_item) {
|
|
58
|
-
/** @type {{ id: string, kind: string, title: string, path: string, status?: string }} */
|
|
61
|
+
/** @type {{ derived?: Record<string, boolean | number | string | null>, derived_summary?: string, id: string, kind: string, title: string, path: string, status?: string }} */
|
|
59
62
|
const query_item = {
|
|
60
63
|
id: output_item.id,
|
|
61
64
|
kind: output_item.node_kind,
|
|
@@ -67,6 +70,16 @@ function formatJsonQueryItem(output_item) {
|
|
|
67
70
|
query_item.status = output_item.status;
|
|
68
71
|
}
|
|
69
72
|
|
|
73
|
+
if (output_item.derived_summary) {
|
|
74
|
+
query_item.derived_summary = output_item.derived_summary.name;
|
|
75
|
+
query_item.derived = Object.fromEntries(
|
|
76
|
+
output_item.derived_summary.fields.map((field) => [
|
|
77
|
+
field.name,
|
|
78
|
+
field.value,
|
|
79
|
+
]),
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
70
83
|
return query_item;
|
|
71
84
|
}
|
|
72
85
|
|
|
@@ -83,10 +96,10 @@ function formatJsonStoredQuery(output_item) {
|
|
|
83
96
|
|
|
84
97
|
/**
|
|
85
98
|
* @param {OutputResolvedLinkItem} output_item
|
|
86
|
-
* @returns {{ label: string, reference: number, target: { kind?: string, path: string, status?: string, title: string } }}
|
|
99
|
+
* @returns {{ label: string, reference: number, target: { derived?: Record<string, boolean | number | string | null>, derived_summary?: string, kind?: string, path: string, status?: string, title: string } }}
|
|
87
100
|
*/
|
|
88
101
|
function formatJsonResolvedLink(output_item) {
|
|
89
|
-
/** @type {{ label: string, reference: number, target: { kind?: string, path: string, status?: string, title: string } }} */
|
|
102
|
+
/** @type {{ label: string, reference: number, target: { derived?: Record<string, boolean | number | string | null>, derived_summary?: string, kind?: string, path: string, status?: string, title: string } }} */
|
|
90
103
|
const resolved_link = {
|
|
91
104
|
reference: output_item.reference,
|
|
92
105
|
label: output_item.label,
|
|
@@ -104,5 +117,45 @@ function formatJsonResolvedLink(output_item) {
|
|
|
104
117
|
resolved_link.target.status = output_item.target.status;
|
|
105
118
|
}
|
|
106
119
|
|
|
120
|
+
if (output_item.target.derived_summary) {
|
|
121
|
+
resolved_link.target.derived_summary =
|
|
122
|
+
output_item.target.derived_summary.name;
|
|
123
|
+
resolved_link.target.derived = Object.fromEntries(
|
|
124
|
+
output_item.target.derived_summary.fields.map((field) => [
|
|
125
|
+
field.name,
|
|
126
|
+
field.value,
|
|
127
|
+
]),
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
107
131
|
return resolved_link;
|
|
108
132
|
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @param {OutputNodeItem} output_item
|
|
136
|
+
* @returns {{ derived?: Record<string, boolean | number | string | null>, derived_summary?: string, kind: string, title: string, path: string, status?: string }}
|
|
137
|
+
*/
|
|
138
|
+
function formatJsonShowDocument(output_item) {
|
|
139
|
+
/** @type {{ derived?: Record<string, boolean | number | string | null>, derived_summary?: string, kind: string, title: string, path: string, status?: string }} */
|
|
140
|
+
const document_summary = {
|
|
141
|
+
kind: output_item.node_kind,
|
|
142
|
+
path: output_item.path,
|
|
143
|
+
title: output_item.title,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
if (output_item.status) {
|
|
147
|
+
document_summary.status = output_item.status;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (output_item.derived_summary) {
|
|
151
|
+
document_summary.derived_summary = output_item.derived_summary.name;
|
|
152
|
+
document_summary.derived = Object.fromEntries(
|
|
153
|
+
output_item.derived_summary.fields.map((field) => [
|
|
154
|
+
field.name,
|
|
155
|
+
field.value,
|
|
156
|
+
]),
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return document_summary;
|
|
161
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** @import * as $k$$l$output$j$view$k$types$k$ts from './output-view.types.ts'; */
|
|
2
2
|
/**
|
|
3
|
-
* @import { GraphNode } from './build-graph.types.ts';
|
|
3
|
+
* @import { BuildGraphResult, GraphNode } from './build-graph.types.ts';
|
|
4
|
+
* @import { DerivedSummaryEvaluator } from './derived-summary.js';
|
|
4
5
|
* @import { ParsedCliArguments } from './parse-cli-arguments.types.ts';
|
|
5
6
|
* @import { OutputStoredQueryItem, OutputView, ResolvedOutputMode, ShowOutputView } from './output-view.types.ts';
|
|
6
7
|
*/
|
|
@@ -29,7 +30,7 @@ import { renderRichOutput } from './render-rich-output.js';
|
|
|
29
30
|
*
|
|
30
31
|
* @param {'query' | 'queries'} command_name
|
|
31
32
|
* @param {GraphNode[] | { name: string, where: string }[]} command_items
|
|
32
|
-
* @param {{ hints?: string[], limit?: number, offset?: number, total_count?: number }=} command_options
|
|
33
|
+
* @param {{ derived_summary_evaluator?: DerivedSummaryEvaluator, hints?: string[], limit?: number, offset?: number, total_count?: number }=} command_options
|
|
33
34
|
* @returns {OutputView}
|
|
34
35
|
*/
|
|
35
36
|
export function createOutputView(command_name, command_items, command_options) {
|
|
@@ -53,17 +54,36 @@ export function createOutputView(command_name, command_items, command_options) {
|
|
|
53
54
|
* Create a shared output view for the show command.
|
|
54
55
|
*
|
|
55
56
|
* @param {{ path: string, rendered_source: string, resolved_links: Array<{ label: string, reference: number, target: { kind?: string, path: string, status?: string, title: string } }>, source: string }} show_output
|
|
57
|
+
* @param {{ derived_summary_evaluator?: DerivedSummaryEvaluator, graph_nodes?: BuildGraphResult['nodes'] }=} command_options
|
|
56
58
|
* @returns {ShowOutputView}
|
|
57
59
|
*/
|
|
58
|
-
export function createShowOutputView(show_output) {
|
|
60
|
+
export function createShowOutputView(show_output, command_options = {}) {
|
|
61
|
+
const shown_document_node =
|
|
62
|
+
command_options.graph_nodes?.[`doc:${show_output.path}`];
|
|
63
|
+
|
|
59
64
|
return {
|
|
60
65
|
command: 'show',
|
|
66
|
+
document: shown_document_node
|
|
67
|
+
? createOutputNodeItem(
|
|
68
|
+
shown_document_node,
|
|
69
|
+
command_options.derived_summary_evaluator?.evaluate(
|
|
70
|
+
shown_document_node,
|
|
71
|
+
) ?? null,
|
|
72
|
+
)
|
|
73
|
+
: undefined,
|
|
61
74
|
hints: [],
|
|
62
75
|
items: show_output.resolved_links.map((resolved_link) => ({
|
|
63
76
|
kind: 'resolved_link',
|
|
64
77
|
label: resolved_link.label,
|
|
65
78
|
reference: resolved_link.reference,
|
|
66
|
-
target: createResolvedLinkTarget(
|
|
79
|
+
target: createResolvedLinkTarget(
|
|
80
|
+
resolved_link.target,
|
|
81
|
+
command_options.graph_nodes?.[`doc:${resolved_link.target.path}`]
|
|
82
|
+
? (command_options.derived_summary_evaluator?.evaluate(
|
|
83
|
+
command_options.graph_nodes[`doc:${resolved_link.target.path}`],
|
|
84
|
+
) ?? null)
|
|
85
|
+
: null,
|
|
86
|
+
),
|
|
67
87
|
})),
|
|
68
88
|
path: show_output.path,
|
|
69
89
|
rendered_source: show_output.rendered_source,
|
|
@@ -104,7 +124,7 @@ export async function renderOutputView(
|
|
|
104
124
|
|
|
105
125
|
/**
|
|
106
126
|
* @param {GraphNode[]} graph_nodes
|
|
107
|
-
* @param {{ hints?: string[], limit?: number, offset?: number, total_count?: number }=} command_options
|
|
127
|
+
* @param {{ derived_summary_evaluator?: DerivedSummaryEvaluator, hints?: string[], limit?: number, offset?: number, total_count?: number }=} command_options
|
|
108
128
|
* @returns {OutputView}
|
|
109
129
|
*/
|
|
110
130
|
function createQueryOutputView(graph_nodes, command_options = {}) {
|
|
@@ -115,7 +135,12 @@ function createQueryOutputView(graph_nodes, command_options = {}) {
|
|
|
115
135
|
hints:
|
|
116
136
|
command_options.hints ??
|
|
117
137
|
(total_count === 0 ? ['Try: patram query --where "kind=task"'] : []),
|
|
118
|
-
items: graph_nodes.map(
|
|
138
|
+
items: graph_nodes.map((graph_node) =>
|
|
139
|
+
createOutputNodeItem(
|
|
140
|
+
graph_node,
|
|
141
|
+
command_options.derived_summary_evaluator?.evaluate(graph_node) ?? null,
|
|
142
|
+
),
|
|
143
|
+
),
|
|
119
144
|
summary: {
|
|
120
145
|
count: graph_nodes.length,
|
|
121
146
|
kind: 'result_list',
|
|
@@ -148,9 +173,10 @@ function createStoredQueriesOutputView(stored_queries) {
|
|
|
148
173
|
|
|
149
174
|
/**
|
|
150
175
|
* @param {GraphNode} graph_node
|
|
176
|
+
* @param {import('./output-view.types.ts').OutputDerivedSummary | null} derived_summary
|
|
151
177
|
* @returns {$k$$l$output$j$view$k$types$k$ts.OutputNodeItem}
|
|
152
178
|
*/
|
|
153
|
-
function createOutputNodeItem(graph_node) {
|
|
179
|
+
function createOutputNodeItem(graph_node, derived_summary) {
|
|
154
180
|
const title =
|
|
155
181
|
graph_node.title ?? graph_node.label ?? graph_node.path ?? graph_node.key;
|
|
156
182
|
|
|
@@ -161,6 +187,7 @@ function createOutputNodeItem(graph_node) {
|
|
|
161
187
|
}
|
|
162
188
|
|
|
163
189
|
return {
|
|
190
|
+
derived_summary: derived_summary ?? undefined,
|
|
164
191
|
id: graph_node.id,
|
|
165
192
|
kind: 'node',
|
|
166
193
|
node_kind: graph_node.kind,
|
|
@@ -172,11 +199,13 @@ function createOutputNodeItem(graph_node) {
|
|
|
172
199
|
|
|
173
200
|
/**
|
|
174
201
|
* @param {{ kind?: string, path: string, status?: string, title: string }} target
|
|
202
|
+
* @param {import('./output-view.types.ts').OutputDerivedSummary | null} derived_summary
|
|
175
203
|
* @returns {$k$$l$output$j$view$k$types$k$ts.OutputResolvedLinkTarget}
|
|
176
204
|
*/
|
|
177
|
-
function createResolvedLinkTarget(target) {
|
|
205
|
+
function createResolvedLinkTarget(target, derived_summary) {
|
|
178
206
|
/** @type {$k$$l$output$j$view$k$types$k$ts.OutputResolvedLinkTarget} */
|
|
179
207
|
const resolved_target = {
|
|
208
|
+
derived_summary: derived_summary ?? undefined,
|
|
180
209
|
path: target.path,
|
|
181
210
|
title: target.title,
|
|
182
211
|
};
|