patram 0.10.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.
- package/bin/patram.js +4 -4
- package/lib/cli/arguments.types.d.ts +1 -0
- package/lib/cli/commands/check.js +27 -15
- package/lib/cli/commands/fields.js +0 -4
- package/lib/cli/commands/queries.js +179 -1
- package/lib/cli/commands/query.js +1 -8
- package/lib/cli/commands/refs.js +3 -10
- package/lib/cli/commands/show.js +1 -8
- package/lib/cli/help-metadata.js +106 -111
- package/lib/cli/main.js +10 -10
- package/lib/cli/parse-arguments-helpers.js +416 -66
- package/lib/cli/parse-arguments.js +4 -4
- package/lib/cli/render-help.js +10 -4
- package/lib/config/defaults.js +33 -25
- package/lib/config/load-patram-config.d.ts +19 -33
- package/lib/config/load-patram-config.js +18 -121
- package/lib/config/load-patram-config.types.d.ts +3 -40
- package/lib/config/manage-stored-queries-helpers.d.ts +69 -0
- package/lib/config/manage-stored-queries-helpers.js +320 -0
- package/lib/config/manage-stored-queries-jsonc.d.ts +31 -0
- package/lib/config/manage-stored-queries-jsonc.js +95 -0
- package/lib/config/manage-stored-queries.d.ts +77 -0
- package/lib/config/manage-stored-queries.js +300 -0
- package/lib/config/patram-config.d.ts +34 -34
- package/lib/config/patram-config.js +3 -3
- package/lib/config/patram-config.types.d.ts +5 -11
- package/lib/config/resolve-patram-graph-config.d.ts +5 -1
- package/lib/config/resolve-patram-graph-config.js +3 -119
- package/lib/config/schema.d.ts +158 -269
- package/lib/config/schema.js +72 -210
- package/lib/config/validate-patram-config-value.d.ts +13 -0
- package/lib/config/validate-patram-config-value.js +94 -0
- package/lib/config/validation.d.ts +2 -12
- package/lib/config/validation.js +125 -483
- package/lib/find-close-match.d.ts +4 -1
- package/lib/graph/build-graph-identity.d.ts +1 -32
- package/lib/graph/build-graph-identity.js +5 -269
- package/lib/graph/build-graph.d.ts +13 -4
- package/lib/graph/build-graph.js +347 -488
- package/lib/graph/build-graph.types.d.ts +8 -9
- package/lib/graph/check-directive-metadata-helpers.d.ts +30 -0
- package/lib/graph/check-directive-metadata-helpers.js +126 -0
- package/lib/graph/check-directive-metadata.d.ts +8 -9
- package/lib/graph/check-directive-metadata.js +70 -561
- package/lib/graph/check-directive-path-target.d.ts +6 -13
- package/lib/graph/check-directive-path-target.js +26 -57
- package/lib/graph/check-directive-value.d.ts +1 -5
- package/lib/graph/check-directive-value.js +40 -180
- package/lib/graph/check-graph.d.ts +5 -5
- package/lib/graph/check-graph.js +8 -6
- package/lib/graph/document-node-identity.d.ts +23 -7
- package/lib/graph/document-node-identity.js +417 -160
- package/lib/graph/graph-node.d.ts +42 -0
- package/lib/graph/graph-node.js +83 -0
- package/lib/graph/inspect-reverse-references.js +16 -11
- package/lib/graph/load-project-graph.d.ts +7 -7
- package/lib/graph/load-project-graph.js +7 -7
- package/lib/graph/parse-where-clause.types.d.ts +3 -2
- package/lib/graph/query/cypher-reader.d.ts +59 -0
- package/lib/graph/query/cypher-reader.js +151 -0
- package/lib/graph/query/cypher-support.d.ts +79 -0
- package/lib/graph/query/cypher-support.js +213 -0
- package/lib/graph/query/cypher-tokenize.d.ts +13 -0
- package/lib/graph/query/cypher-tokenize.js +225 -0
- package/lib/graph/query/cypher.types.d.ts +43 -0
- package/lib/graph/query/execute.d.ts +7 -7
- package/lib/graph/query/execute.js +71 -33
- package/lib/graph/query/inspect.js +58 -24
- package/lib/graph/query/parse-cypher-patterns.d.ts +27 -0
- package/lib/graph/query/parse-cypher-patterns.js +382 -0
- package/lib/graph/query/parse-cypher.d.ts +7 -0
- package/lib/graph/query/parse-cypher.js +580 -0
- package/lib/graph/query/parse-query.d.ts +13 -0
- package/lib/graph/query/parse-query.js +97 -0
- package/lib/graph/query/resolve.d.ts +6 -0
- package/lib/graph/query/resolve.js +81 -24
- package/lib/output/command-output.js +12 -5
- package/lib/output/compact-layout.js +221 -0
- package/lib/output/format-output-item-block.js +31 -1
- package/lib/output/format-output-metadata.js +16 -29
- package/lib/output/format-stored-query-block.js +95 -0
- package/lib/output/layout-incoming-references.js +101 -19
- package/lib/output/layout-stored-queries.js +23 -330
- package/lib/output/list-queries.js +1 -1
- package/lib/output/render-field-discovery.js +11 -2
- package/lib/output/render-output-view.js +9 -5
- package/lib/output/renderers/json.js +5 -26
- package/lib/output/renderers/plain.js +155 -35
- package/lib/output/renderers/rich.js +250 -36
- package/lib/output/resolve-check-target.js +120 -11
- package/lib/output/resolved-link-layout.js +43 -0
- package/lib/output/rich-source/render.js +193 -35
- package/lib/output/show-document.js +25 -18
- package/lib/output/view-model/index.js +124 -103
- package/lib/parse/jsdoc/parse-jsdoc-blocks.js +1 -1
- package/lib/parse/jsdoc/parse-jsdoc-claims.js +12 -6
- package/lib/parse/markdown/parse-markdown-claims.js +99 -62
- package/lib/parse/markdown/parse-markdown-directives.d.ts +10 -6
- package/lib/parse/markdown/parse-markdown-directives.js +104 -18
- package/lib/parse/markdown/parse-markdown-prose.d.ts +27 -0
- package/lib/parse/markdown/parse-markdown-prose.js +243 -0
- package/lib/parse/parse-claims.d.ts +2 -6
- package/lib/parse/parse-claims.js +11 -53
- package/lib/parse/tagged-fenced/tagged-fenced-blocks.d.ts +4 -4
- package/lib/parse/tagged-fenced/tagged-fenced-blocks.js +4 -4
- package/lib/parse/yaml/parse-yaml-claims.js +4 -4
- package/lib/patram.d.ts +9 -3
- package/lib/patram.js +1 -1
- package/lib/scan/discover-fields.js +194 -55
- package/lib/scan/list-source-files.d.ts +4 -4
- package/lib/scan/list-source-files.js +4 -4
- package/package.json +2 -1
- package/lib/directive-validation-test-helpers.js +0 -87
- package/lib/graph/query/parse.d.ts +0 -75
- package/lib/graph/query/parse.js +0 -1064
- package/lib/output/derived-summary.js +0 -280
- package/lib/output/format-derived-summary-row.js +0 -9
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @typedef {import('./arguments.types.ts').CliParseError} CliParseError
|
|
6
6
|
* @typedef {import('./arguments.types.ts').ParsedCliHelpRequest} ParsedCliHelpRequest
|
|
7
7
|
* @typedef {{ kind: string, name?: string, rawName?: string, value?: string | boolean }} CliOptionToken
|
|
8
|
-
* @typedef {{ color?: string, explain?: boolean, help?: boolean, json?: boolean, limit?: string, lint?: boolean, 'no-color'?: boolean, offset?: string, plain?: boolean, where?: string }} CliOptionValues
|
|
8
|
+
* @typedef {{ color?: string, cypher?: string, desc?: string, explain?: boolean, help?: boolean, json?: boolean, limit?: string, lint?: boolean, name?: string, 'no-color'?: boolean, offset?: string, plain?: boolean, where?: string }} CliOptionValues
|
|
9
9
|
* @typedef {{ option_tokens: CliOptionToken[], positionals: string[], values: CliOptionValues }} ParsedCommandLine
|
|
10
10
|
*/
|
|
11
11
|
|
|
@@ -23,11 +23,14 @@ import { findInvalidQueryPagination } from './query-pagination.js';
|
|
|
23
23
|
|
|
24
24
|
export const CLI_OPTIONS = /** @type {const} */ ({
|
|
25
25
|
color: { type: 'string' },
|
|
26
|
+
cypher: { type: 'string' },
|
|
27
|
+
desc: { type: 'string' },
|
|
26
28
|
explain: { type: 'boolean' },
|
|
27
29
|
help: { type: 'boolean' },
|
|
28
30
|
json: { type: 'boolean' },
|
|
29
31
|
limit: { type: 'string' },
|
|
30
32
|
lint: { type: 'boolean' },
|
|
33
|
+
name: { type: 'string' },
|
|
31
34
|
'no-color': { type: 'boolean' },
|
|
32
35
|
offset: { type: 'string' },
|
|
33
36
|
plain: { type: 'boolean' },
|
|
@@ -96,34 +99,15 @@ export function validateParsedCommand(command_name, command_line) {
|
|
|
96
99
|
const command_positionals = command_line.positionals.slice(1);
|
|
97
100
|
|
|
98
101
|
if (
|
|
99
|
-
command_name
|
|
100
|
-
command_line.values.where !== undefined &&
|
|
101
|
-
command_positionals.length === 0
|
|
102
|
+
hasAdHocQueryCommand(command_name, command_line.values, command_positionals)
|
|
102
103
|
) {
|
|
103
|
-
return (
|
|
104
|
-
createMessageParseError(
|
|
105
|
-
findInvalidQueryPagination(command_line.option_tokens),
|
|
106
|
-
) ??
|
|
107
|
-
findInvalidQueryMode(
|
|
108
|
-
command_name,
|
|
109
|
-
command_line.values,
|
|
110
|
-
command_positionals,
|
|
111
|
-
)
|
|
112
|
-
);
|
|
104
|
+
return validateAdHocQueryCommand(command_line, command_positionals);
|
|
113
105
|
}
|
|
114
106
|
|
|
115
|
-
return (
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
) ??
|
|
120
|
-
findInvalidQueryInspection(command_name, command_line.values) ??
|
|
121
|
-
findInvalidQueryMode(
|
|
122
|
-
command_name,
|
|
123
|
-
command_line.values,
|
|
124
|
-
command_positionals,
|
|
125
|
-
) ??
|
|
126
|
-
validateCommandPositionals(command_name, command_positionals)
|
|
107
|
+
return validateStandardCommand(
|
|
108
|
+
command_name,
|
|
109
|
+
command_line,
|
|
110
|
+
command_positionals,
|
|
127
111
|
);
|
|
128
112
|
}
|
|
129
113
|
|
|
@@ -154,17 +138,134 @@ export function buildCommandArguments(
|
|
|
154
138
|
command_positionals,
|
|
155
139
|
parsed_values,
|
|
156
140
|
) {
|
|
157
|
-
if (command_name === 'query'
|
|
158
|
-
return
|
|
141
|
+
if (command_name === 'query' || command_name === 'refs') {
|
|
142
|
+
return buildAdHocQueryArguments(
|
|
143
|
+
command_name,
|
|
144
|
+
command_positionals,
|
|
145
|
+
parsed_values,
|
|
146
|
+
);
|
|
159
147
|
}
|
|
160
148
|
|
|
161
|
-
if (command_name === '
|
|
162
|
-
return
|
|
149
|
+
if (command_name === 'queries') {
|
|
150
|
+
return buildStoredQueryArguments(command_positionals, parsed_values);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return command_positionals;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* @param {CliCommandName} command_name
|
|
158
|
+
* @param {CliOptionValues} parsed_values
|
|
159
|
+
* @param {string[]} command_positionals
|
|
160
|
+
* @returns {boolean}
|
|
161
|
+
*/
|
|
162
|
+
function hasAdHocQueryCommand(
|
|
163
|
+
command_name,
|
|
164
|
+
parsed_values,
|
|
165
|
+
command_positionals,
|
|
166
|
+
) {
|
|
167
|
+
return (
|
|
168
|
+
command_name === 'query' &&
|
|
169
|
+
parsed_values.cypher !== undefined &&
|
|
170
|
+
command_positionals.length === 0
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* @param {ParsedCommandLine} command_line
|
|
176
|
+
* @param {string[]} command_positionals
|
|
177
|
+
* @returns {CliParseError | null}
|
|
178
|
+
*/
|
|
179
|
+
function validateAdHocQueryCommand(command_line, command_positionals) {
|
|
180
|
+
return (
|
|
181
|
+
findInvalidCommandOption('query', command_line.option_tokens) ??
|
|
182
|
+
createMessageParseError(
|
|
183
|
+
findInvalidQueryPagination(command_line.option_tokens),
|
|
184
|
+
) ??
|
|
185
|
+
findInvalidQueryMode('query', command_line.values, command_positionals)
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* @param {CliCommandName} command_name
|
|
191
|
+
* @param {ParsedCommandLine} command_line
|
|
192
|
+
* @param {string[]} command_positionals
|
|
193
|
+
* @returns {CliParseError | null}
|
|
194
|
+
*/
|
|
195
|
+
function validateStandardCommand(
|
|
196
|
+
command_name,
|
|
197
|
+
command_line,
|
|
198
|
+
command_positionals,
|
|
199
|
+
) {
|
|
200
|
+
return (
|
|
201
|
+
findInvalidCommandOption(command_name, command_line.option_tokens) ??
|
|
202
|
+
createMessageParseError(
|
|
203
|
+
findInvalidQueryPagination(command_line.option_tokens),
|
|
204
|
+
) ??
|
|
205
|
+
findInvalidQueryInspection(command_name, command_line.values) ??
|
|
206
|
+
findInvalidQueryMode(
|
|
207
|
+
command_name,
|
|
208
|
+
command_line.values,
|
|
209
|
+
command_positionals,
|
|
210
|
+
) ??
|
|
211
|
+
findInvalidQueriesMutation(
|
|
212
|
+
command_name,
|
|
213
|
+
command_line.values,
|
|
214
|
+
command_positionals,
|
|
215
|
+
) ??
|
|
216
|
+
validateCommandPositionals(command_name, command_positionals)
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* @param {'query' | 'refs'} command_name
|
|
222
|
+
* @param {string[]} command_positionals
|
|
223
|
+
* @param {CliOptionValues} parsed_values
|
|
224
|
+
* @returns {string[]}
|
|
225
|
+
*/
|
|
226
|
+
function buildAdHocQueryArguments(
|
|
227
|
+
command_name,
|
|
228
|
+
command_positionals,
|
|
229
|
+
parsed_values,
|
|
230
|
+
) {
|
|
231
|
+
if (parsed_values.cypher !== undefined) {
|
|
232
|
+
return command_name === 'query'
|
|
233
|
+
? ['--cypher', parsed_values.cypher]
|
|
234
|
+
: [command_positionals[0], '--cypher', parsed_values.cypher];
|
|
163
235
|
}
|
|
164
236
|
|
|
165
237
|
return command_positionals;
|
|
166
238
|
}
|
|
167
239
|
|
|
240
|
+
/**
|
|
241
|
+
* @param {string[]} command_positionals
|
|
242
|
+
* @param {CliOptionValues} parsed_values
|
|
243
|
+
* @returns {string[]}
|
|
244
|
+
*/
|
|
245
|
+
function buildStoredQueryArguments(command_positionals, parsed_values) {
|
|
246
|
+
/** @type {string[]} */
|
|
247
|
+
const command_arguments = [...command_positionals];
|
|
248
|
+
|
|
249
|
+
appendOptionValue(command_arguments, '--name', parsed_values.name);
|
|
250
|
+
appendOptionValue(command_arguments, '--cypher', parsed_values.cypher);
|
|
251
|
+
appendOptionValue(command_arguments, '--desc', parsed_values.desc);
|
|
252
|
+
|
|
253
|
+
return command_arguments;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* @param {string[]} command_arguments
|
|
258
|
+
* @param {string} option_name
|
|
259
|
+
* @param {string | undefined} option_value
|
|
260
|
+
*/
|
|
261
|
+
function appendOptionValue(command_arguments, option_name, option_value) {
|
|
262
|
+
if (option_value === undefined) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
command_arguments.push(option_name, option_value);
|
|
267
|
+
}
|
|
268
|
+
|
|
168
269
|
/**
|
|
169
270
|
* @param {string | undefined} help_target
|
|
170
271
|
* @returns {CliParseError}
|
|
@@ -305,24 +406,10 @@ function findInvalidCommandOption(command_name, option_tokens) {
|
|
|
305
406
|
*/
|
|
306
407
|
function findMissingOptionValue(option_tokens) {
|
|
307
408
|
for (const token of option_tokens) {
|
|
308
|
-
|
|
309
|
-
return {
|
|
310
|
-
argument_label: "<name> or --where '<clause>'",
|
|
311
|
-
code: 'missing_required_argument',
|
|
312
|
-
command_name: 'query',
|
|
313
|
-
};
|
|
314
|
-
}
|
|
409
|
+
const missing_value_error = findMissingOptionValueError(token);
|
|
315
410
|
|
|
316
|
-
if (
|
|
317
|
-
return
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
if (token.name === 'limit' && typeof token.value !== 'string') {
|
|
321
|
-
return createMessageParseError('Limit requires a value.');
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (token.name === 'color' && typeof token.value !== 'string') {
|
|
325
|
-
return createMessageParseError('Color requires a value.');
|
|
411
|
+
if (missing_value_error) {
|
|
412
|
+
return missing_value_error;
|
|
326
413
|
}
|
|
327
414
|
}
|
|
328
415
|
|
|
@@ -356,14 +443,38 @@ function findInvalidQueryMode(
|
|
|
356
443
|
) {
|
|
357
444
|
if (
|
|
358
445
|
command_name === 'query' &&
|
|
359
|
-
parsed_values.
|
|
446
|
+
parsed_values.cypher !== undefined &&
|
|
360
447
|
command_positionals.length > 0
|
|
361
448
|
) {
|
|
362
449
|
return createMessageParseError(
|
|
363
|
-
'Query accepts either "--
|
|
450
|
+
'Query accepts either "--cypher" or a stored query name.',
|
|
364
451
|
);
|
|
365
452
|
}
|
|
366
453
|
|
|
454
|
+
if (command_name === 'query' && parsed_values.where !== undefined) {
|
|
455
|
+
return {
|
|
456
|
+
code: 'option_not_valid_for_command',
|
|
457
|
+
command_name: 'query',
|
|
458
|
+
token: '--where',
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (command_name === 'queries' && parsed_values.where !== undefined) {
|
|
463
|
+
return {
|
|
464
|
+
code: 'option_not_valid_for_command',
|
|
465
|
+
command_name: 'queries',
|
|
466
|
+
token: '--where',
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (command_name === 'refs' && parsed_values.where !== undefined) {
|
|
471
|
+
return {
|
|
472
|
+
code: 'option_not_valid_for_command',
|
|
473
|
+
command_name: 'refs',
|
|
474
|
+
token: '--where',
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
|
|
367
478
|
return null;
|
|
368
479
|
}
|
|
369
480
|
|
|
@@ -386,6 +497,42 @@ function findInvalidQueryInspection(command_name, parsed_values) {
|
|
|
386
497
|
return null;
|
|
387
498
|
}
|
|
388
499
|
|
|
500
|
+
/**
|
|
501
|
+
* @param {CliCommandName} command_name
|
|
502
|
+
* @param {CliOptionValues} parsed_values
|
|
503
|
+
* @param {string[]} command_positionals
|
|
504
|
+
* @returns {CliParseError | null}
|
|
505
|
+
*/
|
|
506
|
+
function findInvalidQueriesMutation(
|
|
507
|
+
command_name,
|
|
508
|
+
parsed_values,
|
|
509
|
+
command_positionals,
|
|
510
|
+
) {
|
|
511
|
+
if (command_name !== 'queries' || command_positionals.length === 0) {
|
|
512
|
+
return null;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const subcommand_name = command_positionals[0];
|
|
516
|
+
|
|
517
|
+
if (
|
|
518
|
+
subcommand_name !== 'add' &&
|
|
519
|
+
subcommand_name !== 'remove' &&
|
|
520
|
+
subcommand_name !== 'update'
|
|
521
|
+
) {
|
|
522
|
+
return createUnexpectedArgumentError('queries', subcommand_name);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (subcommand_name === 'add') {
|
|
526
|
+
return validateQueriesAddMutation(parsed_values, command_positionals);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (subcommand_name === 'remove') {
|
|
530
|
+
return validateQueriesRemoveMutation(parsed_values, command_positionals);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
return validateQueriesUpdateMutation(parsed_values, command_positionals);
|
|
534
|
+
}
|
|
535
|
+
|
|
389
536
|
/**
|
|
390
537
|
* @param {CliCommandName} command_name
|
|
391
538
|
* @param {string[]} command_positionals
|
|
@@ -394,24 +541,18 @@ function findInvalidQueryInspection(command_name, parsed_values) {
|
|
|
394
541
|
function validateCommandPositionals(command_name, command_positionals) {
|
|
395
542
|
const command_definition = getCommandDefinition(command_name);
|
|
396
543
|
|
|
544
|
+
if (allowsQueriesMutationPositionals(command_name, command_positionals)) {
|
|
545
|
+
return null;
|
|
546
|
+
}
|
|
547
|
+
|
|
397
548
|
if (command_positionals.length < command_definition.min_positionals) {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
command_name: 'query',
|
|
403
|
-
};
|
|
404
|
-
}
|
|
549
|
+
const missing_argument_error = createMissingArgumentError(
|
|
550
|
+
command_name,
|
|
551
|
+
command_definition.missing_argument_label,
|
|
552
|
+
);
|
|
405
553
|
|
|
406
|
-
if (
|
|
407
|
-
|
|
408
|
-
command_definition.missing_argument_label
|
|
409
|
-
) {
|
|
410
|
-
return {
|
|
411
|
-
argument_label: command_definition.missing_argument_label,
|
|
412
|
-
code: 'missing_required_argument',
|
|
413
|
-
command_name,
|
|
414
|
-
};
|
|
554
|
+
if (missing_argument_error) {
|
|
555
|
+
return missing_argument_error;
|
|
415
556
|
}
|
|
416
557
|
|
|
417
558
|
return createMessageParseError(
|
|
@@ -428,7 +569,7 @@ function validateCommandPositionals(command_name, command_positionals) {
|
|
|
428
569
|
|
|
429
570
|
if (command_name === 'query' && command_positionals.length === 0) {
|
|
430
571
|
return {
|
|
431
|
-
argument_label: "<name> or --
|
|
572
|
+
argument_label: "<name> or --cypher '<query>'",
|
|
432
573
|
code: 'missing_required_argument',
|
|
433
574
|
command_name: 'query',
|
|
434
575
|
};
|
|
@@ -443,14 +584,223 @@ function validateCommandPositionals(command_name, command_positionals) {
|
|
|
443
584
|
*/
|
|
444
585
|
function isKnownCommandOptionName(option_name) {
|
|
445
586
|
return (
|
|
587
|
+
option_name === 'desc' ||
|
|
588
|
+
option_name === 'cypher' ||
|
|
446
589
|
option_name === 'explain' ||
|
|
447
590
|
option_name === 'limit' ||
|
|
448
591
|
option_name === 'lint' ||
|
|
592
|
+
option_name === 'name' ||
|
|
449
593
|
option_name === 'offset' ||
|
|
594
|
+
option_name === 'query' ||
|
|
450
595
|
option_name === 'where'
|
|
451
596
|
);
|
|
452
597
|
}
|
|
453
598
|
|
|
599
|
+
/**
|
|
600
|
+
* @param {CliOptionToken} option_token
|
|
601
|
+
* @returns {CliParseError | null}
|
|
602
|
+
*/
|
|
603
|
+
function findMissingOptionValueError(option_token) {
|
|
604
|
+
if (typeof option_token.value === 'string') {
|
|
605
|
+
return null;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
if (option_token.name === 'where') {
|
|
609
|
+
return createMessageParseError('Where requires a value.');
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
if (option_token.name === 'cypher') {
|
|
613
|
+
return {
|
|
614
|
+
argument_label: "<name> or --cypher '<query>'",
|
|
615
|
+
code: 'missing_required_argument',
|
|
616
|
+
command_name: 'query',
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
const message = getMissingOptionValueMessage(option_token.name);
|
|
621
|
+
|
|
622
|
+
if (!message) {
|
|
623
|
+
return null;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
return createMessageParseError(message);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* @param {string | undefined} option_name
|
|
631
|
+
* @returns {string | null}
|
|
632
|
+
*/
|
|
633
|
+
function getMissingOptionValueMessage(option_name) {
|
|
634
|
+
/** @type {Record<string, string>} */
|
|
635
|
+
const option_messages = {
|
|
636
|
+
color: 'Color requires a value.',
|
|
637
|
+
cypher: 'Cypher requires a value.',
|
|
638
|
+
desc: 'Desc requires a value.',
|
|
639
|
+
limit: 'Limit requires a value.',
|
|
640
|
+
name: 'Name requires a value.',
|
|
641
|
+
offset: 'Offset requires a value.',
|
|
642
|
+
query: 'Query requires a value.',
|
|
643
|
+
where: 'Where requires a value.',
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
if (!option_name || !Object.hasOwn(option_messages, option_name)) {
|
|
647
|
+
return null;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
return option_messages[option_name];
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* @param {CliOptionValues} parsed_values
|
|
655
|
+
* @param {string[]} command_positionals
|
|
656
|
+
* @returns {CliParseError | null}
|
|
657
|
+
*/
|
|
658
|
+
function validateQueriesAddMutation(parsed_values, command_positionals) {
|
|
659
|
+
const positional_error = validateQueriesMutationPositionals(
|
|
660
|
+
command_positionals,
|
|
661
|
+
'Queries add requires a stored query name.',
|
|
662
|
+
);
|
|
663
|
+
|
|
664
|
+
if (positional_error) {
|
|
665
|
+
return positional_error;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
if (parsed_values.name !== undefined) {
|
|
669
|
+
return createMessageParseError('Queries add does not accept "--name".');
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
if (parsed_values.cypher === undefined) {
|
|
673
|
+
return createMessageParseError('Queries add requires "--cypher <query>".');
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
return null;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* @param {CliOptionValues} parsed_values
|
|
681
|
+
* @param {string[]} command_positionals
|
|
682
|
+
* @returns {CliParseError | null}
|
|
683
|
+
*/
|
|
684
|
+
function validateQueriesRemoveMutation(parsed_values, command_positionals) {
|
|
685
|
+
const positional_error = validateQueriesMutationPositionals(
|
|
686
|
+
command_positionals,
|
|
687
|
+
'Queries remove requires a stored query name.',
|
|
688
|
+
);
|
|
689
|
+
|
|
690
|
+
if (positional_error) {
|
|
691
|
+
return positional_error;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
if (
|
|
695
|
+
parsed_values.desc !== undefined ||
|
|
696
|
+
parsed_values.cypher !== undefined ||
|
|
697
|
+
parsed_values.name !== undefined ||
|
|
698
|
+
parsed_values.where !== undefined
|
|
699
|
+
) {
|
|
700
|
+
return createMessageParseError(
|
|
701
|
+
'Queries remove does not accept mutation options.',
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
return null;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* @param {CliOptionValues} parsed_values
|
|
710
|
+
* @param {string[]} command_positionals
|
|
711
|
+
* @returns {CliParseError | null}
|
|
712
|
+
*/
|
|
713
|
+
function validateQueriesUpdateMutation(parsed_values, command_positionals) {
|
|
714
|
+
const positional_error = validateQueriesMutationPositionals(
|
|
715
|
+
command_positionals,
|
|
716
|
+
'Queries update requires a stored query name.',
|
|
717
|
+
);
|
|
718
|
+
|
|
719
|
+
if (positional_error) {
|
|
720
|
+
return positional_error;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
if (
|
|
724
|
+
parsed_values.desc === undefined &&
|
|
725
|
+
parsed_values.cypher === undefined &&
|
|
726
|
+
parsed_values.name === undefined
|
|
727
|
+
) {
|
|
728
|
+
return createMessageParseError(
|
|
729
|
+
'Queries update requires at least one of "--name", "--cypher", or "--desc".',
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
return null;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* @param {string[]} command_positionals
|
|
738
|
+
* @param {string} missing_name_message
|
|
739
|
+
* @returns {CliParseError | null}
|
|
740
|
+
*/
|
|
741
|
+
function validateQueriesMutationPositionals(
|
|
742
|
+
command_positionals,
|
|
743
|
+
missing_name_message,
|
|
744
|
+
) {
|
|
745
|
+
if (command_positionals.length < 2) {
|
|
746
|
+
return createMessageParseError(missing_name_message);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
if (command_positionals.length > 2) {
|
|
750
|
+
return createUnexpectedArgumentError('queries', command_positionals[2]);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
return null;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* @param {CliCommandName} command_name
|
|
758
|
+
* @param {string[]} command_positionals
|
|
759
|
+
* @returns {boolean}
|
|
760
|
+
*/
|
|
761
|
+
function allowsQueriesMutationPositionals(command_name, command_positionals) {
|
|
762
|
+
if (command_name !== 'queries' || command_positionals.length === 0) {
|
|
763
|
+
return false;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
const subcommand_name = command_positionals[0];
|
|
767
|
+
|
|
768
|
+
return (
|
|
769
|
+
subcommand_name === 'add' ||
|
|
770
|
+
subcommand_name === 'remove' ||
|
|
771
|
+
subcommand_name === 'update'
|
|
772
|
+
);
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* @param {CliCommandName} command_name
|
|
777
|
+
* @param {string | null} missing_argument_label
|
|
778
|
+
* @returns {CliParseError | null}
|
|
779
|
+
*/
|
|
780
|
+
function createMissingArgumentError(command_name, missing_argument_label) {
|
|
781
|
+
if (!missing_argument_label) {
|
|
782
|
+
return null;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
if (command_name === 'query') {
|
|
786
|
+
return {
|
|
787
|
+
argument_label: missing_argument_label,
|
|
788
|
+
code: 'missing_required_argument',
|
|
789
|
+
command_name: 'query',
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
if (command_name === 'refs' || command_name === 'show') {
|
|
794
|
+
return {
|
|
795
|
+
argument_label: missing_argument_label,
|
|
796
|
+
code: 'missing_required_argument',
|
|
797
|
+
command_name,
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
return null;
|
|
802
|
+
}
|
|
803
|
+
|
|
454
804
|
/**
|
|
455
805
|
* @param {'help' | CliCommandName} command_name
|
|
456
806
|
* @param {string | undefined} token
|
|
@@ -34,10 +34,10 @@ import { buildQueryPagination } from './query-pagination.js';
|
|
|
34
34
|
* Normalizes raw argv into one validated Patram command plus shared output and
|
|
35
35
|
* pagination options.
|
|
36
36
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
37
|
+
* kind: cli
|
|
38
|
+
* status: active
|
|
39
|
+
* tracked_in: ../../docs/plans/v0/source-anchor-dogfooding.md
|
|
40
|
+
* decided_by: ../../docs/decisions/cli-argument-parser.md
|
|
41
41
|
* @patram
|
|
42
42
|
* @see {@link ./main.js}
|
|
43
43
|
* @see {@link ../../docs/decisions/cli-argument-parser.md}
|
package/lib/cli/render-help.js
CHANGED
|
@@ -85,6 +85,7 @@ export function renderCliParseError(parse_error) {
|
|
|
85
85
|
if (parse_error.code === 'unknown_stored_query') {
|
|
86
86
|
return renderUnknownStoredQueryError(
|
|
87
87
|
parse_error.name,
|
|
88
|
+
parse_error.next_path,
|
|
88
89
|
parse_error.suggestion,
|
|
89
90
|
);
|
|
90
91
|
}
|
|
@@ -100,7 +101,7 @@ export function renderInvalidWhereDiagnostic(diagnostic) {
|
|
|
100
101
|
const diagnostic_line = formatDiagnostic(diagnostic);
|
|
101
102
|
|
|
102
103
|
return joinOutputLines([
|
|
103
|
-
'Invalid
|
|
104
|
+
'Invalid query:',
|
|
104
105
|
` ${diagnostic_line}`,
|
|
105
106
|
'',
|
|
106
107
|
'Next:',
|
|
@@ -156,7 +157,7 @@ function renderCommandHelp(command_name) {
|
|
|
156
157
|
) {
|
|
157
158
|
output_lines.push(
|
|
158
159
|
'',
|
|
159
|
-
'
|
|
160
|
+
'Query syntax:',
|
|
160
161
|
...indentLines(command_definition.syntax_lines),
|
|
161
162
|
);
|
|
162
163
|
}
|
|
@@ -359,10 +360,15 @@ function renderUnexpectedArgumentError(command_name, invalid_token) {
|
|
|
359
360
|
|
|
360
361
|
/**
|
|
361
362
|
* @param {string} stored_query_name
|
|
363
|
+
* @param {string | undefined} next_path
|
|
362
364
|
* @param {string | undefined} suggestion
|
|
363
365
|
* @returns {string}
|
|
364
366
|
*/
|
|
365
|
-
function renderUnknownStoredQueryError(
|
|
367
|
+
function renderUnknownStoredQueryError(
|
|
368
|
+
stored_query_name,
|
|
369
|
+
next_path,
|
|
370
|
+
suggestion,
|
|
371
|
+
) {
|
|
366
372
|
if (suggestion) {
|
|
367
373
|
return joinOutputLines([
|
|
368
374
|
`Unknown stored query: ${stored_query_name}`,
|
|
@@ -371,7 +377,7 @@ function renderUnknownStoredQueryError(stored_query_name, suggestion) {
|
|
|
371
377
|
` ${suggestion}`,
|
|
372
378
|
'',
|
|
373
379
|
'Next:',
|
|
374
|
-
` patram query ${suggestion}`,
|
|
380
|
+
` ${next_path ?? `patram query ${suggestion}`}`,
|
|
375
381
|
]);
|
|
376
382
|
}
|
|
377
383
|
|