patram 0.9.0 → 0.11.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/cli/arguments.types.d.ts +64 -0
- package/lib/cli/commands/check.js +27 -15
- package/lib/cli/commands/queries.js +189 -1
- package/lib/cli/commands/query.js +6 -3
- package/lib/cli/help-metadata.js +45 -110
- package/lib/cli/parse-arguments-helpers.js +295 -39
- package/lib/cli/render-help.js +87 -0
- package/lib/config/load-patram-config.d.ts +11 -0
- package/lib/config/load-patram-config.js +9 -88
- package/lib/config/manage-stored-queries-helpers.d.ts +69 -0
- package/lib/config/manage-stored-queries-helpers.js +262 -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 +294 -0
- package/lib/config/schema.d.ts +2 -0
- package/lib/config/schema.js +4 -0
- package/lib/config/validate-patram-config-value.d.ts +13 -0
- package/lib/config/validate-patram-config-value.js +119 -0
- package/lib/find-close-match.d.ts +8 -0
- package/lib/find-close-match.js +98 -0
- package/lib/graph/query/resolve.d.ts +9 -5
- package/lib/graph/query/resolve.js +41 -4
- package/lib/output/layout-stored-queries.js +18 -2
- package/lib/output/list-queries.js +2 -1
- package/lib/output/renderers/json.js +9 -5
- package/lib/output/renderers/plain.js +15 -26
- package/lib/output/renderers/rich.js +22 -26
- package/lib/output/resolve-check-target.js +120 -11
- package/lib/output/view-model/index.js +5 -18
- package/lib/patram.d.ts +8 -0
- package/lib/scan/discover-fields.js +136 -10
- package/package.json +2 -1
|
@@ -10,7 +10,7 @@ const MIN_TERM_COLUMN_WIDTH = 20;
|
|
|
10
10
|
const STORED_QUERY_COLUMN_GAP = 2;
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* @typedef {'field_name' | 'keyword' | 'literal' | 'name' | 'operator' | 'plain'} StoredQuerySegmentKind
|
|
13
|
+
* @typedef {'description' | 'field_name' | 'keyword' | 'literal' | 'name' | 'operator' | 'plain'} StoredQuerySegmentKind
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -56,7 +56,8 @@ function layoutStoredQuery(output_item, name_column_width, term_column_width) {
|
|
|
56
56
|
name_column_width + STORED_QUERY_COLUMN_GAP,
|
|
57
57
|
);
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
/** @type {StoredQuerySegment[][]} */
|
|
60
|
+
const output_lines = term_lines.map((line_segments, line_index) => {
|
|
60
61
|
if (line_index === 0) {
|
|
61
62
|
return [
|
|
62
63
|
{
|
|
@@ -79,6 +80,21 @@ function layoutStoredQuery(output_item, name_column_width, term_column_width) {
|
|
|
79
80
|
...line_segments,
|
|
80
81
|
];
|
|
81
82
|
});
|
|
83
|
+
|
|
84
|
+
if (output_item.description) {
|
|
85
|
+
for (const description_line of output_item.description.split('\n')) {
|
|
86
|
+
output_lines.push([
|
|
87
|
+
{
|
|
88
|
+
kind: 'description',
|
|
89
|
+
text: `${' '.repeat(name_column_width + STORED_QUERY_COLUMN_GAP)}${description_line}`,
|
|
90
|
+
},
|
|
91
|
+
]);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
output_lines.push([]);
|
|
96
|
+
|
|
97
|
+
return output_lines;
|
|
82
98
|
}
|
|
83
99
|
|
|
84
100
|
/**
|
|
@@ -6,12 +6,13 @@
|
|
|
6
6
|
* List stored queries in stable name order.
|
|
7
7
|
*
|
|
8
8
|
* @param {Record<string, StoredQueryConfig>} stored_queries
|
|
9
|
-
* @returns {{ name: string, where: string }[]}
|
|
9
|
+
* @returns {{ name: string, where: string, description?: string }[]}
|
|
10
10
|
*/
|
|
11
11
|
export function listQueries(stored_queries) {
|
|
12
12
|
return Object.entries(stored_queries)
|
|
13
13
|
.sort(([left_name], [right_name]) => left_name.localeCompare(right_name))
|
|
14
14
|
.map(([name, stored_query]) => ({
|
|
15
|
+
description: stored_query.description,
|
|
15
16
|
name,
|
|
16
17
|
where: stored_query.where,
|
|
17
18
|
}));
|
|
@@ -92,9 +92,6 @@ function renderJsonRefsOutput(output_view) {
|
|
|
92
92
|
function renderJsonShowOutput(output_view) {
|
|
93
93
|
return `${JSON.stringify(
|
|
94
94
|
{
|
|
95
|
-
document: output_view.document
|
|
96
|
-
? formatJsonNodeItem(output_view.document)
|
|
97
|
-
: undefined,
|
|
98
95
|
incoming_summary: output_view.incoming_summary,
|
|
99
96
|
source: output_view.source,
|
|
100
97
|
resolved_links: output_view.items.map(formatJsonResolvedLink),
|
|
@@ -144,13 +141,20 @@ function formatJsonNodeItem(output_item) {
|
|
|
144
141
|
|
|
145
142
|
/**
|
|
146
143
|
* @param {OutputStoredQueryItem} output_item
|
|
147
|
-
* @returns {{ name: string, where: string }}
|
|
144
|
+
* @returns {{ name: string, where: string, description?: string }}
|
|
148
145
|
*/
|
|
149
146
|
function formatJsonStoredQuery(output_item) {
|
|
150
|
-
|
|
147
|
+
/** @type {{ description?: string, name: string, where: string }} */
|
|
148
|
+
const stored_query = {
|
|
151
149
|
name: output_item.name,
|
|
152
150
|
where: output_item.where,
|
|
153
151
|
};
|
|
152
|
+
|
|
153
|
+
if (output_item.description) {
|
|
154
|
+
stored_query.description = output_item.description;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return stored_query;
|
|
154
158
|
}
|
|
155
159
|
|
|
156
160
|
/**
|
|
@@ -24,7 +24,7 @@ export function renderPlainOutput(output_view) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
if (output_view.command === 'queries') {
|
|
27
|
-
return renderPlainStoredQueries(output_view
|
|
27
|
+
return renderPlainStoredQueries(output_view);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
if (output_view.command === 'refs') {
|
|
@@ -69,17 +69,23 @@ function renderPlainEmptyQuery(footer) {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
|
-
* @param {
|
|
72
|
+
* @param {Extract<OutputView, { command: 'queries' }>} output_view
|
|
73
73
|
* @returns {string}
|
|
74
74
|
*/
|
|
75
|
-
function renderPlainStoredQueries(
|
|
76
|
-
if (
|
|
75
|
+
function renderPlainStoredQueries(output_view) {
|
|
76
|
+
if (output_view.items.length === 0) {
|
|
77
77
|
return '';
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
const output_lines = layoutStoredQueries(output_view.items).map(
|
|
81
|
+
formatPlainStoredQueryLine,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
if (output_view.hints.length === 0) {
|
|
85
|
+
return `${output_lines.join('\n')}\n`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return `${output_lines.join('\n')}\n${output_view.hints.join('\n')}\n`;
|
|
83
89
|
}
|
|
84
90
|
|
|
85
91
|
/**
|
|
@@ -88,29 +94,12 @@ function renderPlainStoredQueries(output_items) {
|
|
|
88
94
|
*/
|
|
89
95
|
function renderPlainShowOutput(output_view) {
|
|
90
96
|
const rendered_source = trimTrailingLineBreaks(output_view.rendered_source);
|
|
91
|
-
const document_summary = output_view.document
|
|
92
|
-
? formatPlainNodeItem(output_view.document)
|
|
93
|
-
: '';
|
|
94
97
|
const incoming_summary = renderPlainIncomingSummary(output_view);
|
|
95
98
|
|
|
96
|
-
if (
|
|
97
|
-
document_summary.length === 0 &&
|
|
98
|
-
output_view.items.length === 0 &&
|
|
99
|
-
incoming_summary.length === 0
|
|
100
|
-
) {
|
|
99
|
+
if (output_view.items.length === 0 && incoming_summary.length === 0) {
|
|
101
100
|
return `${rendered_source}\n`;
|
|
102
101
|
}
|
|
103
|
-
|
|
104
|
-
/** @type {string[]} */
|
|
105
|
-
const summary_items = [];
|
|
106
|
-
|
|
107
|
-
if (document_summary.length > 0) {
|
|
108
|
-
summary_items.push(document_summary);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
summary_items.push(...output_view.items.map(formatPlainResolvedLinkItem));
|
|
112
|
-
|
|
113
|
-
const summary_blocks = summary_items.filter((summary_item) => summary_item);
|
|
102
|
+
const summary_blocks = output_view.items.map(formatPlainResolvedLinkItem);
|
|
114
103
|
|
|
115
104
|
if (incoming_summary.length > 0) {
|
|
116
105
|
summary_blocks.push(incoming_summary);
|
|
@@ -33,7 +33,7 @@ export async function renderRichOutput(output_view, render_options) {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
if (output_view.command === 'queries') {
|
|
36
|
-
return renderRichStoredQueries(output_view
|
|
36
|
+
return renderRichStoredQueries(output_view, ansi);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
if (output_view.command === 'refs') {
|
|
@@ -83,18 +83,24 @@ function renderRichEmptyQuery(footer, ansi) {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
/**
|
|
86
|
-
* @param {
|
|
86
|
+
* @param {Extract<OutputView, { command: 'queries' }>} output_view
|
|
87
87
|
* @param {Ansis} ansi
|
|
88
88
|
* @returns {string}
|
|
89
89
|
*/
|
|
90
|
-
function renderRichStoredQueries(
|
|
91
|
-
if (
|
|
90
|
+
function renderRichStoredQueries(output_view, ansi) {
|
|
91
|
+
if (output_view.items.length === 0) {
|
|
92
92
|
return '';
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
const output_lines = layoutStoredQueries(output_view.items).map(
|
|
96
|
+
(line_segments) => formatRichStoredQueryLine(line_segments, ansi),
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
if (output_view.hints.length === 0) {
|
|
100
|
+
return `${output_lines.join('\n')}\n`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return `${output_lines.join('\n')}\n${output_view.hints.map((hint) => ansi.gray(hint)).join('\n')}\n`;
|
|
98
104
|
}
|
|
99
105
|
|
|
100
106
|
/**
|
|
@@ -107,28 +113,14 @@ async function renderRichShowOutput(output_view, render_options, ansi) {
|
|
|
107
113
|
const rendered_source = trimTrailingLineBreaks(
|
|
108
114
|
await renderRichSource(output_view, render_options),
|
|
109
115
|
);
|
|
110
|
-
const document_summary = output_view.document
|
|
111
|
-
? formatRichNodeItem(output_view.document, ansi)
|
|
112
|
-
: '';
|
|
113
116
|
const incoming_summary = renderRichIncomingSummary(output_view, ansi);
|
|
114
117
|
|
|
115
|
-
if (
|
|
116
|
-
document_summary.length === 0 &&
|
|
117
|
-
output_view.items.length === 0 &&
|
|
118
|
-
incoming_summary.length === 0
|
|
119
|
-
) {
|
|
118
|
+
if (output_view.items.length === 0 && incoming_summary.length === 0) {
|
|
120
119
|
return `${rendered_source}\n`;
|
|
121
120
|
}
|
|
122
121
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (document_summary.length > 0) {
|
|
127
|
-
summary_items.push(document_summary);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
summary_items.push(
|
|
131
|
-
...output_view.items.map((item) => formatRichResolvedLinkItem(item, ansi)),
|
|
122
|
+
const summary_items = output_view.items.map((item) =>
|
|
123
|
+
formatRichResolvedLinkItem(item, ansi),
|
|
132
124
|
);
|
|
133
125
|
|
|
134
126
|
if (incoming_summary.length > 0) {
|
|
@@ -173,7 +165,7 @@ function formatRichNodeItem(output_item, ansi) {
|
|
|
173
165
|
}
|
|
174
166
|
|
|
175
167
|
/**
|
|
176
|
-
* @param {{ kind: 'field_name' | 'keyword' | 'literal' | 'name' | 'operator' | 'plain', text: string }[]} line_segments
|
|
168
|
+
* @param {{ kind: 'description' | 'field_name' | 'keyword' | 'literal' | 'name' | 'operator' | 'plain', text: string }[]} line_segments
|
|
177
169
|
* @param {Ansis} ansi
|
|
178
170
|
* @returns {string}
|
|
179
171
|
*/
|
|
@@ -232,7 +224,7 @@ function createAnsi(color_enabled) {
|
|
|
232
224
|
}
|
|
233
225
|
|
|
234
226
|
/**
|
|
235
|
-
* @param {{ kind: 'field_name' | 'keyword' | 'literal' | 'name' | 'operator' | 'plain', text: string }} line_segment
|
|
227
|
+
* @param {{ kind: 'description' | 'field_name' | 'keyword' | 'literal' | 'name' | 'operator' | 'plain', text: string }} line_segment
|
|
236
228
|
* @param {Ansis} ansi
|
|
237
229
|
* @returns {string}
|
|
238
230
|
*/
|
|
@@ -241,6 +233,10 @@ function styleStoredQuerySegment(line_segment, ansi) {
|
|
|
241
233
|
return ansi.green(line_segment.text);
|
|
242
234
|
}
|
|
243
235
|
|
|
236
|
+
if (line_segment.kind === 'description') {
|
|
237
|
+
return ansi.gray(line_segment.text);
|
|
238
|
+
}
|
|
239
|
+
|
|
244
240
|
if (line_segment.kind === 'operator') {
|
|
245
241
|
return ansi.gray(line_segment.text);
|
|
246
242
|
}
|
|
@@ -21,7 +21,7 @@ const CONFIG_FILE_NAME = '.patram.json';
|
|
|
21
21
|
* @param {string | undefined} target_argument
|
|
22
22
|
* @returns {Promise<ResolvedCheckTarget>}
|
|
23
23
|
*/
|
|
24
|
-
|
|
24
|
+
async function resolveCheckTarget(target_argument) {
|
|
25
25
|
if (target_argument === undefined) {
|
|
26
26
|
return {
|
|
27
27
|
project_directory: process.cwd(),
|
|
@@ -35,23 +35,19 @@ export async function resolveCheckTarget(target_argument) {
|
|
|
35
35
|
? absolute_target_path
|
|
36
36
|
: dirname(absolute_target_path);
|
|
37
37
|
const project_directory = await findProjectDirectory(target_directory);
|
|
38
|
-
|
|
39
38
|
if (target_stats.isFile()) {
|
|
40
39
|
const target_path = normalizeRepoRelativePath(
|
|
41
40
|
relative(project_directory, absolute_target_path),
|
|
42
41
|
);
|
|
43
|
-
|
|
44
42
|
return {
|
|
45
43
|
project_directory,
|
|
46
44
|
target_kind: 'file',
|
|
47
45
|
target_path,
|
|
48
46
|
};
|
|
49
47
|
}
|
|
50
|
-
|
|
51
48
|
const target_path = normalizeRepoRelativePath(
|
|
52
49
|
relative(project_directory, absolute_target_path),
|
|
53
50
|
);
|
|
54
|
-
|
|
55
51
|
if (target_path.length === 0) {
|
|
56
52
|
return {
|
|
57
53
|
project_directory,
|
|
@@ -65,7 +61,36 @@ export async function resolveCheckTarget(target_argument) {
|
|
|
65
61
|
target_path,
|
|
66
62
|
};
|
|
67
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* @param {string[]} target_arguments
|
|
66
|
+
* @returns {Promise<ResolvedCheckTarget[]>}
|
|
67
|
+
*/
|
|
68
|
+
export async function resolveCheckTargets(target_arguments) {
|
|
69
|
+
if (target_arguments.length === 0) {
|
|
70
|
+
return [await resolveCheckTarget(undefined)];
|
|
71
|
+
}
|
|
68
72
|
|
|
73
|
+
return Promise.all(
|
|
74
|
+
target_arguments.map((target_argument) =>
|
|
75
|
+
resolveCheckTarget(target_argument),
|
|
76
|
+
),
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
/** @param {ResolvedCheckTarget[]} resolved_targets
|
|
80
|
+
* @returns {string | null}
|
|
81
|
+
*/
|
|
82
|
+
export function resolveCheckTargetProjectDirectory(resolved_targets) {
|
|
83
|
+
const project_directory = resolved_targets[0]?.project_directory;
|
|
84
|
+
if (!project_directory) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
for (const resolved_target of resolved_targets) {
|
|
88
|
+
if (resolved_target.project_directory !== project_directory) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return project_directory;
|
|
93
|
+
}
|
|
69
94
|
/**
|
|
70
95
|
* Select the source files covered by one resolved `check` target.
|
|
71
96
|
*
|
|
@@ -73,10 +98,7 @@ export async function resolveCheckTarget(target_argument) {
|
|
|
73
98
|
* @param {ResolvedCheckTarget} resolved_target
|
|
74
99
|
* @returns {string[]}
|
|
75
100
|
*/
|
|
76
|
-
|
|
77
|
-
source_file_paths,
|
|
78
|
-
resolved_target,
|
|
79
|
-
) {
|
|
101
|
+
function selectCheckTargetSourceFiles(source_file_paths, resolved_target) {
|
|
80
102
|
if (resolved_target.target_kind === 'project') {
|
|
81
103
|
return source_file_paths;
|
|
82
104
|
}
|
|
@@ -91,7 +113,22 @@ export function selectCheckTargetSourceFiles(
|
|
|
91
113
|
isPathInsideDirectory(source_file_path, resolved_target.target_path),
|
|
92
114
|
);
|
|
93
115
|
}
|
|
94
|
-
|
|
116
|
+
/**
|
|
117
|
+
* @param {string[]} source_file_paths
|
|
118
|
+
* @param {ResolvedCheckTarget[]} resolved_targets
|
|
119
|
+
* @returns {string[]}
|
|
120
|
+
*/
|
|
121
|
+
export function selectCheckTargetsSourceFiles(
|
|
122
|
+
source_file_paths,
|
|
123
|
+
resolved_targets,
|
|
124
|
+
) {
|
|
125
|
+
return selectCheckTargetValues(
|
|
126
|
+
source_file_paths,
|
|
127
|
+
resolved_targets,
|
|
128
|
+
selectCheckTargetSourceFiles,
|
|
129
|
+
(source_file_path) => source_file_path,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
95
132
|
/**
|
|
96
133
|
* Filter diagnostics to one resolved `check` target.
|
|
97
134
|
*
|
|
@@ -99,7 +136,7 @@ export function selectCheckTargetSourceFiles(
|
|
|
99
136
|
* @param {ResolvedCheckTarget} resolved_target
|
|
100
137
|
* @returns {PatramDiagnostic[]}
|
|
101
138
|
*/
|
|
102
|
-
|
|
139
|
+
function selectCheckTargetDiagnostics(diagnostics, resolved_target) {
|
|
103
140
|
if (resolved_target.target_kind === 'project') {
|
|
104
141
|
return diagnostics;
|
|
105
142
|
}
|
|
@@ -115,6 +152,20 @@ export function selectCheckTargetDiagnostics(diagnostics, resolved_target) {
|
|
|
115
152
|
);
|
|
116
153
|
}
|
|
117
154
|
|
|
155
|
+
/**
|
|
156
|
+
* @param {PatramDiagnostic[]} diagnostics
|
|
157
|
+
* @param {ResolvedCheckTarget[]} resolved_targets
|
|
158
|
+
* @returns {PatramDiagnostic[]}
|
|
159
|
+
*/
|
|
160
|
+
export function selectCheckTargetsDiagnostics(diagnostics, resolved_targets) {
|
|
161
|
+
return selectCheckTargetValues(
|
|
162
|
+
diagnostics,
|
|
163
|
+
resolved_targets,
|
|
164
|
+
selectCheckTargetDiagnostics,
|
|
165
|
+
createDiagnosticKey,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
118
169
|
/**
|
|
119
170
|
* @param {string} start_directory
|
|
120
171
|
* @returns {Promise<string>}
|
|
@@ -155,6 +206,49 @@ async function hasConfigFile(directory_path) {
|
|
|
155
206
|
return true;
|
|
156
207
|
}
|
|
157
208
|
|
|
209
|
+
/**
|
|
210
|
+
* @template ValueType
|
|
211
|
+
* @param {ValueType[]} values
|
|
212
|
+
* @param {ResolvedCheckTarget[]} resolved_targets
|
|
213
|
+
* @param {(values: ValueType[], resolved_target: ResolvedCheckTarget) => ValueType[]} select_values
|
|
214
|
+
* @param {(value: ValueType) => string} get_value_key
|
|
215
|
+
* @returns {ValueType[]}
|
|
216
|
+
*/
|
|
217
|
+
function selectCheckTargetValues(
|
|
218
|
+
values,
|
|
219
|
+
resolved_targets,
|
|
220
|
+
select_values,
|
|
221
|
+
get_value_key,
|
|
222
|
+
) {
|
|
223
|
+
if (
|
|
224
|
+
resolved_targets.some(
|
|
225
|
+
(resolved_target) => resolved_target.target_kind === 'project',
|
|
226
|
+
)
|
|
227
|
+
) {
|
|
228
|
+
return values;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** @type {Set<string>} */
|
|
232
|
+
const selected_keys = new Set();
|
|
233
|
+
/** @type {ValueType[]} */
|
|
234
|
+
const selected_values = [];
|
|
235
|
+
|
|
236
|
+
for (const resolved_target of resolved_targets) {
|
|
237
|
+
for (const value of select_values(values, resolved_target)) {
|
|
238
|
+
const value_key = get_value_key(value);
|
|
239
|
+
|
|
240
|
+
if (selected_keys.has(value_key)) {
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
selected_keys.add(value_key);
|
|
245
|
+
selected_values.push(value);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return selected_values;
|
|
250
|
+
}
|
|
251
|
+
|
|
158
252
|
/**
|
|
159
253
|
* @param {string} source_path
|
|
160
254
|
* @param {string} directory_path
|
|
@@ -175,6 +269,21 @@ function normalizeRepoRelativePath(source_path) {
|
|
|
175
269
|
return source_path.replaceAll('\\', '/');
|
|
176
270
|
}
|
|
177
271
|
|
|
272
|
+
/**
|
|
273
|
+
* @param {PatramDiagnostic} diagnostic
|
|
274
|
+
* @returns {string}
|
|
275
|
+
*/
|
|
276
|
+
function createDiagnosticKey(diagnostic) {
|
|
277
|
+
return [
|
|
278
|
+
diagnostic.path,
|
|
279
|
+
diagnostic.line,
|
|
280
|
+
diagnostic.column,
|
|
281
|
+
diagnostic.level,
|
|
282
|
+
diagnostic.code,
|
|
283
|
+
diagnostic.message,
|
|
284
|
+
].join(':');
|
|
285
|
+
}
|
|
286
|
+
|
|
178
287
|
/**
|
|
179
288
|
* @param {unknown} error
|
|
180
289
|
* @returns {error is NodeJS.ErrnoException}
|
|
@@ -12,7 +12,7 @@ import { resolveDocumentNodeId } from '../../graph/build-graph-identity.js';
|
|
|
12
12
|
* Create a shared output view from one command result.
|
|
13
13
|
*
|
|
14
14
|
* @param {'query' | 'queries'} command_name
|
|
15
|
-
* @param {GraphNode[] | { name: string, where: string }[]} command_items
|
|
15
|
+
* @param {GraphNode[] | { name: string, where: string, description?: string }[]} command_items
|
|
16
16
|
* @param {{ derived_summary_evaluator?: DerivedSummaryEvaluator, hints?: string[], limit?: number, offset?: number, repo_config?: PatramRepoConfig, total_count?: number }=} command_options
|
|
17
17
|
* @returns {OutputView}
|
|
18
18
|
*/
|
|
@@ -41,23 +41,8 @@ export function createOutputView(command_name, command_items, command_options) {
|
|
|
41
41
|
* @returns {ShowOutputView}
|
|
42
42
|
*/
|
|
43
43
|
export function createShowOutputView(show_output, command_options = {}) {
|
|
44
|
-
const shown_document_node = resolveDocumentGraphNode(
|
|
45
|
-
command_options.graph_nodes,
|
|
46
|
-
command_options.document_node_ids,
|
|
47
|
-
show_output.path,
|
|
48
|
-
);
|
|
49
|
-
|
|
50
44
|
return {
|
|
51
45
|
command: 'show',
|
|
52
|
-
document: shown_document_node
|
|
53
|
-
? createOutputNodeItem(
|
|
54
|
-
shown_document_node,
|
|
55
|
-
command_options.derived_summary_evaluator?.evaluate(
|
|
56
|
-
shown_document_node,
|
|
57
|
-
) ?? null,
|
|
58
|
-
command_options.repo_config?.fields ?? {},
|
|
59
|
-
)
|
|
60
|
-
: undefined,
|
|
61
46
|
hints: [],
|
|
62
47
|
incoming_summary: show_output.incoming_summary,
|
|
63
48
|
items: show_output.resolved_links.map((resolved_link) =>
|
|
@@ -144,17 +129,19 @@ function createQueryOutputView(graph_nodes, command_options = {}) {
|
|
|
144
129
|
}
|
|
145
130
|
|
|
146
131
|
/**
|
|
147
|
-
* @param {{ name: string, where: string }[]} stored_queries
|
|
132
|
+
* @param {{ name: string, where: string, description?: string }[]} stored_queries
|
|
148
133
|
* @returns {OutputView}
|
|
149
134
|
*/
|
|
150
135
|
function createStoredQueriesOutputView(stored_queries) {
|
|
151
136
|
return {
|
|
152
137
|
command: 'queries',
|
|
153
|
-
hints:
|
|
138
|
+
hints:
|
|
139
|
+
stored_queries.length === 0 ? [] : ['Hint: patram help query-language'],
|
|
154
140
|
items: stored_queries.map((stored_query) => ({
|
|
155
141
|
kind: 'stored_query',
|
|
156
142
|
name: stored_query.name,
|
|
157
143
|
where: stored_query.where,
|
|
144
|
+
description: stored_query.description,
|
|
158
145
|
})),
|
|
159
146
|
summary: {
|
|
160
147
|
count: stored_queries.length,
|
package/lib/patram.d.ts
CHANGED
|
@@ -48,6 +48,8 @@ export type PatramParsedTerm =
|
|
|
48
48
|
import('./graph/parse-where-clause.types.d.ts').ParsedTerm;
|
|
49
49
|
export type PatramParsedExpression =
|
|
50
50
|
import('./graph/parse-where-clause.types.d.ts').ParsedExpression;
|
|
51
|
+
export type PatramParseResult =
|
|
52
|
+
import('./graph/parse-where-clause.types.d.ts').ParseWhereClauseResult;
|
|
51
53
|
export type PatramParseWhereClauseResult =
|
|
52
54
|
import('./graph/parse-where-clause.types.d.ts').ParseWhereClauseResult;
|
|
53
55
|
export type PatramQuerySource =
|
|
@@ -59,6 +61,12 @@ export type PatramQuerySource =
|
|
|
59
61
|
name: string;
|
|
60
62
|
};
|
|
61
63
|
|
|
64
|
+
export interface PatramQueryGraphOptions {
|
|
65
|
+
bindings?: Record<string, string>;
|
|
66
|
+
limit?: number;
|
|
67
|
+
offset?: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
62
70
|
export interface PatramProjectGraphResult {
|
|
63
71
|
claims: import('./parse/parse-claims.types.d.ts').PatramClaim[];
|
|
64
72
|
config: import('./config/load-patram-config.types.d.ts').PatramRepoConfig;
|