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.
- package/bin/patram.js +4 -4
- package/lib/cli/commands/fields.js +0 -4
- package/lib/cli/commands/queries.js +10 -20
- 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 +71 -106
- package/lib/cli/main.js +10 -10
- package/lib/cli/parse-arguments-helpers.js +165 -59
- package/lib/cli/parse-arguments.js +4 -4
- package/lib/cli/render-help.js +2 -2
- package/lib/config/defaults.js +33 -25
- package/lib/config/load-patram-config.d.ts +8 -33
- package/lib/config/load-patram-config.js +9 -33
- package/lib/config/load-patram-config.types.d.ts +3 -40
- package/lib/config/manage-stored-queries-helpers.d.ts +4 -4
- package/lib/config/manage-stored-queries-helpers.js +91 -33
- package/lib/config/manage-stored-queries.d.ts +4 -4
- package/lib/config/manage-stored-queries.js +11 -5
- 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.js +6 -31
- 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.js +77 -23
- 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/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 +3 -5
- 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 +1 -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
|
@@ -1,38 +1,34 @@
|
|
|
1
|
-
/* eslint-disable max-lines */
|
|
2
1
|
/**
|
|
3
2
|
* @import { BuildGraphResult } from './build-graph.types.ts';
|
|
4
|
-
* @import {
|
|
3
|
+
* @import { PatramDiagnostic, PatramRepoConfig } from '../config/load-patram-config.types.ts';
|
|
5
4
|
* @import { PatramClaim } from '../parse/parse-claims.types.ts';
|
|
6
|
-
* @import { MappingDefinition } from '../config/patram-config.types.ts';
|
|
7
5
|
*/
|
|
8
6
|
|
|
9
7
|
import {
|
|
10
8
|
collectDocumentEntityKeys,
|
|
11
9
|
collectDocumentNodeReferences,
|
|
12
10
|
normalizeRepoRelativePath,
|
|
13
|
-
resolveDocumentNodeId,
|
|
14
11
|
} from './build-graph-identity.js';
|
|
15
12
|
import { checkDirectiveValue } from './check-directive-value.js';
|
|
16
13
|
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
collectRequiredFieldDiagnostics,
|
|
15
|
+
collectTypePlacementDiagnostics,
|
|
16
|
+
groupDirectiveClaimsByDocument,
|
|
17
|
+
resolveDocumentType,
|
|
18
|
+
} from './check-directive-metadata-helpers.js';
|
|
19
|
+
import { createOriginDiagnostic } from './directive-diagnostics.js';
|
|
22
20
|
|
|
23
21
|
/**
|
|
24
|
-
*
|
|
22
|
+
* Validate declared metadata fields and typed document placement.
|
|
25
23
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* @see {@link ../../docs/decisions/directive-type-validation.md}
|
|
24
|
+
* kind: graph
|
|
25
|
+
* status: active
|
|
26
|
+
* tracked_in: ../../docs/plans/v2/types-and-fields-config.md
|
|
27
|
+
* decided_by: ../../docs/decisions/types-and-fields-config.md
|
|
31
28
|
* @patram
|
|
32
|
-
* @see {@link ./check-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
/**
|
|
29
|
+
* @see {@link ./check-directive-value.js}
|
|
30
|
+
* @see {@link ../../docs/decisions/types-and-fields-config.md}
|
|
31
|
+
*
|
|
36
32
|
* @param {BuildGraphResult} graph
|
|
37
33
|
* @param {PatramRepoConfig} repo_config
|
|
38
34
|
* @param {PatramClaim[]} claims
|
|
@@ -45,17 +41,13 @@ export function checkDirectiveMetadata(
|
|
|
45
41
|
claims,
|
|
46
42
|
existing_file_paths,
|
|
47
43
|
) {
|
|
48
|
-
if (claims.length === 0
|
|
44
|
+
if (claims.length === 0) {
|
|
49
45
|
return [];
|
|
50
46
|
}
|
|
51
47
|
|
|
52
|
-
const
|
|
53
|
-
const document_entity_keys = collectDocumentEntityKeys(
|
|
54
|
-
graph_config.mappings,
|
|
55
|
-
claims,
|
|
56
|
-
);
|
|
48
|
+
const document_entity_keys = collectDocumentEntityKeys(repo_config, claims);
|
|
57
49
|
const document_node_references = collectDocumentNodeReferences(
|
|
58
|
-
|
|
50
|
+
repo_config,
|
|
59
51
|
claims,
|
|
60
52
|
);
|
|
61
53
|
const document_paths = new Set(
|
|
@@ -74,16 +66,16 @@ export function checkDirectiveMetadata(
|
|
|
74
66
|
continue;
|
|
75
67
|
}
|
|
76
68
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
69
|
+
diagnostics.push(
|
|
70
|
+
...checkDocumentDirectiveMetadata(
|
|
71
|
+
graph,
|
|
72
|
+
repo_config,
|
|
73
|
+
document_path,
|
|
74
|
+
document_claims,
|
|
75
|
+
document_entity_keys,
|
|
76
|
+
document_node_references,
|
|
77
|
+
document_paths,
|
|
78
|
+
),
|
|
87
79
|
);
|
|
88
80
|
}
|
|
89
81
|
|
|
@@ -91,60 +83,17 @@ export function checkDirectiveMetadata(
|
|
|
91
83
|
}
|
|
92
84
|
|
|
93
85
|
/**
|
|
94
|
-
* @param {PatramRepoConfig} repo_config
|
|
95
|
-
* @returns {boolean}
|
|
96
|
-
*/
|
|
97
|
-
function hasDirectiveValidationConfig(repo_config) {
|
|
98
|
-
return (
|
|
99
|
-
repo_config.fields !== undefined ||
|
|
100
|
-
hasMarkdownStyleValidationConfig(repo_config) ||
|
|
101
|
-
hasConfiguredClassSchemas(repo_config) ||
|
|
102
|
-
hasPathTargetDirectiveMappings(repo_config)
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* @param {PatramClaim[]} claims
|
|
108
|
-
* @returns {Map<string, PatramClaim[]>}
|
|
109
|
-
*/
|
|
110
|
-
function groupDirectiveClaimsByDocument(claims) {
|
|
111
|
-
/** @type {Map<string, PatramClaim[]>} */
|
|
112
|
-
const directive_claims_by_document = new Map();
|
|
113
|
-
|
|
114
|
-
for (const claim of claims) {
|
|
115
|
-
if (claim.type !== 'directive') {
|
|
116
|
-
continue;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const document_path = normalizeRepoRelativePath(claim.origin.path);
|
|
120
|
-
let document_claims = directive_claims_by_document.get(document_path);
|
|
121
|
-
|
|
122
|
-
if (!document_claims) {
|
|
123
|
-
document_claims = [];
|
|
124
|
-
directive_claims_by_document.set(document_path, document_claims);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
document_claims.push(claim);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return directive_claims_by_document;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* @param {PatramDiagnostic[]} diagnostics
|
|
135
86
|
* @param {BuildGraphResult} graph
|
|
136
|
-
* @param {Record<string, MappingDefinition>} mappings
|
|
137
87
|
* @param {PatramRepoConfig} repo_config
|
|
138
88
|
* @param {string} document_path
|
|
139
89
|
* @param {PatramClaim[]} document_claims
|
|
140
90
|
* @param {Map<string, string>} document_entity_keys
|
|
141
91
|
* @param {Map<string, import('./document-node-identity.js').DocumentNodeReference>} document_node_references
|
|
142
92
|
* @param {Set<string>} document_paths
|
|
93
|
+
* @returns {PatramDiagnostic[]}
|
|
143
94
|
*/
|
|
144
|
-
function
|
|
145
|
-
diagnostics,
|
|
95
|
+
function checkDocumentDirectiveMetadata(
|
|
146
96
|
graph,
|
|
147
|
-
mappings,
|
|
148
97
|
repo_config,
|
|
149
98
|
document_path,
|
|
150
99
|
document_claims,
|
|
@@ -152,27 +101,26 @@ function collectDocumentDiagnostics(
|
|
|
152
101
|
document_node_references,
|
|
153
102
|
document_paths,
|
|
154
103
|
) {
|
|
155
|
-
const
|
|
156
|
-
const schema_definition = repo_config.classes?.[document_kind]?.schema;
|
|
104
|
+
const document_type = resolveDocumentType(graph, document_path);
|
|
157
105
|
/** @type {Map<string, number>} */
|
|
158
106
|
const directive_counts = new Map();
|
|
159
|
-
/** @type {
|
|
160
|
-
const
|
|
107
|
+
/** @type {PatramDiagnostic[]} */
|
|
108
|
+
const diagnostics = [];
|
|
161
109
|
|
|
162
110
|
for (const claim of document_claims) {
|
|
163
111
|
if (!claim.name) {
|
|
164
112
|
continue;
|
|
165
113
|
}
|
|
166
114
|
|
|
115
|
+
directive_counts.set(
|
|
116
|
+
claim.name,
|
|
117
|
+
(directive_counts.get(claim.name) ?? 0) + 1,
|
|
118
|
+
);
|
|
167
119
|
diagnostics.push(
|
|
168
120
|
...collectClaimDiagnostics(
|
|
169
121
|
claim,
|
|
170
|
-
mappings,
|
|
171
122
|
repo_config,
|
|
172
|
-
|
|
173
|
-
schema_definition,
|
|
174
|
-
directive_counts,
|
|
175
|
-
seen_markdown_styles,
|
|
123
|
+
document_type,
|
|
176
124
|
document_entity_keys,
|
|
177
125
|
document_node_references,
|
|
178
126
|
document_paths,
|
|
@@ -181,24 +129,28 @@ function collectDocumentDiagnostics(
|
|
|
181
129
|
}
|
|
182
130
|
|
|
183
131
|
diagnostics.push(
|
|
184
|
-
...
|
|
132
|
+
...collectRequiredFieldDiagnostics(
|
|
185
133
|
repo_config,
|
|
186
134
|
document_path,
|
|
187
|
-
|
|
188
|
-
schema_definition,
|
|
135
|
+
document_type,
|
|
189
136
|
directive_counts,
|
|
190
137
|
),
|
|
191
138
|
);
|
|
139
|
+
diagnostics.push(
|
|
140
|
+
...collectTypePlacementDiagnostics(
|
|
141
|
+
repo_config,
|
|
142
|
+
document_path,
|
|
143
|
+
document_type,
|
|
144
|
+
),
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
return diagnostics;
|
|
192
148
|
}
|
|
193
149
|
|
|
194
150
|
/**
|
|
195
151
|
* @param {PatramClaim} claim
|
|
196
|
-
* @param {Record<string, MappingDefinition>} mappings
|
|
197
152
|
* @param {PatramRepoConfig} repo_config
|
|
198
|
-
* @param {string}
|
|
199
|
-
* @param {MetadataSchemaConfig | undefined} schema_definition
|
|
200
|
-
* @param {Map<string, number>} directive_counts
|
|
201
|
-
* @param {Set<string>} seen_markdown_styles
|
|
153
|
+
* @param {string} document_type
|
|
202
154
|
* @param {Map<string, string>} document_entity_keys
|
|
203
155
|
* @param {Map<string, import('./document-node-identity.js').DocumentNodeReference>} document_node_references
|
|
204
156
|
* @param {Set<string>} document_paths
|
|
@@ -206,12 +158,8 @@ function collectDocumentDiagnostics(
|
|
|
206
158
|
*/
|
|
207
159
|
function collectClaimDiagnostics(
|
|
208
160
|
claim,
|
|
209
|
-
mappings,
|
|
210
161
|
repo_config,
|
|
211
|
-
|
|
212
|
-
schema_definition,
|
|
213
|
-
directive_counts,
|
|
214
|
-
seen_markdown_styles,
|
|
162
|
+
document_type,
|
|
215
163
|
document_entity_keys,
|
|
216
164
|
document_node_references,
|
|
217
165
|
document_paths,
|
|
@@ -220,484 +168,45 @@ function collectClaimDiagnostics(
|
|
|
220
168
|
return [];
|
|
221
169
|
}
|
|
222
170
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
claim.name,
|
|
226
|
-
mapping_definition,
|
|
227
|
-
);
|
|
228
|
-
const has_node_mapping = mapping_definition?.node !== undefined;
|
|
229
|
-
const next_count = (directive_counts.get(claim.name) ?? 0) + 1;
|
|
230
|
-
|
|
231
|
-
directive_counts.set(claim.name, next_count);
|
|
232
|
-
|
|
233
|
-
return [
|
|
234
|
-
...collectPresenceDiagnostics(
|
|
235
|
-
claim,
|
|
236
|
-
claim.name,
|
|
237
|
-
validation_field_name,
|
|
238
|
-
isEmitOnlyDirective(mapping_definition),
|
|
239
|
-
has_node_mapping,
|
|
240
|
-
repo_config,
|
|
241
|
-
document_kind,
|
|
242
|
-
schema_definition,
|
|
243
|
-
next_count,
|
|
244
|
-
),
|
|
245
|
-
...collectMarkdownStyleDiagnostics(
|
|
246
|
-
claim,
|
|
247
|
-
document_kind,
|
|
248
|
-
schema_definition,
|
|
249
|
-
seen_markdown_styles,
|
|
250
|
-
),
|
|
251
|
-
...checkDirectiveValue(
|
|
171
|
+
if (claim.name === 'title' || claim.name === 'description') {
|
|
172
|
+
return checkDirectiveValue(
|
|
252
173
|
claim,
|
|
253
174
|
claim.name,
|
|
254
|
-
mappings,
|
|
255
175
|
repo_config,
|
|
256
|
-
schema_definition?.fields[claim.name],
|
|
257
176
|
document_entity_keys,
|
|
258
177
|
document_node_references,
|
|
259
178
|
document_paths,
|
|
260
|
-
)
|
|
261
|
-
];
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* @param {PatramRepoConfig} repo_config
|
|
266
|
-
* @returns {boolean}
|
|
267
|
-
*/
|
|
268
|
-
function hasConfiguredClassSchemas(repo_config) {
|
|
269
|
-
for (const class_definition of Object.values(repo_config.classes ?? {})) {
|
|
270
|
-
if (class_definition.schema) {
|
|
271
|
-
return true;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
return false;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* @param {PatramRepoConfig} repo_config
|
|
280
|
-
* @returns {boolean}
|
|
281
|
-
*/
|
|
282
|
-
function hasMarkdownStyleValidationConfig(repo_config) {
|
|
283
|
-
for (const class_definition of Object.values(repo_config.classes ?? {})) {
|
|
284
|
-
const schema_definition = class_definition.schema;
|
|
285
|
-
|
|
286
|
-
if (!schema_definition) {
|
|
287
|
-
continue;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
if (
|
|
291
|
-
schema_definition.markdown_styles !== undefined ||
|
|
292
|
-
schema_definition.mixed_styles !== undefined
|
|
293
|
-
) {
|
|
294
|
-
return true;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
for (const field_rule of Object.values(schema_definition.fields)) {
|
|
298
|
-
if (field_rule.markdown_styles !== undefined) {
|
|
299
|
-
return true;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
return false;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* @param {PatramRepoConfig} repo_config
|
|
309
|
-
* @returns {boolean}
|
|
310
|
-
*/
|
|
311
|
-
function hasPathTargetDirectiveMappings(repo_config) {
|
|
312
|
-
for (const [mapping_name, mapping_definition] of Object.entries(
|
|
313
|
-
repo_config.mappings ?? {},
|
|
314
|
-
)) {
|
|
315
|
-
if (
|
|
316
|
-
mapping_name.includes('.directive.') &&
|
|
317
|
-
mapping_definition.emit?.target === 'path'
|
|
318
|
-
) {
|
|
319
|
-
return true;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
return false;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* @param {PatramRepoConfig} repo_config
|
|
328
|
-
* @param {string} document_path
|
|
329
|
-
* @param {string} document_kind
|
|
330
|
-
* @param {MetadataSchemaConfig | undefined} schema_definition
|
|
331
|
-
* @param {Map<string, number>} directive_counts
|
|
332
|
-
* @returns {PatramDiagnostic[]}
|
|
333
|
-
*/
|
|
334
|
-
function collectDocumentSummaryDiagnostics(
|
|
335
|
-
repo_config,
|
|
336
|
-
document_path,
|
|
337
|
-
document_kind,
|
|
338
|
-
schema_definition,
|
|
339
|
-
directive_counts,
|
|
340
|
-
) {
|
|
341
|
-
return [
|
|
342
|
-
...collectMissingDirectiveDiagnostics(
|
|
343
|
-
document_path,
|
|
344
|
-
document_kind,
|
|
345
|
-
schema_definition,
|
|
346
|
-
directive_counts,
|
|
347
|
-
),
|
|
348
|
-
...collectPlacementDiagnostics(
|
|
349
|
-
repo_config,
|
|
350
|
-
document_path,
|
|
351
|
-
document_kind,
|
|
352
|
-
schema_definition,
|
|
353
|
-
),
|
|
354
|
-
];
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* @param {PatramClaim} claim
|
|
359
|
-
* @param {string} directive_name
|
|
360
|
-
* @param {string} validation_field_name
|
|
361
|
-
* @param {boolean} emit_only
|
|
362
|
-
* @param {boolean} has_node_mapping
|
|
363
|
-
* @param {PatramRepoConfig} repo_config
|
|
364
|
-
* @param {string} document_kind
|
|
365
|
-
* @param {MetadataSchemaConfig | undefined} schema_definition
|
|
366
|
-
* @param {number} directive_count
|
|
367
|
-
* @returns {PatramDiagnostic[]}
|
|
368
|
-
*/
|
|
369
|
-
function collectPresenceDiagnostics(
|
|
370
|
-
claim,
|
|
371
|
-
directive_name,
|
|
372
|
-
validation_field_name,
|
|
373
|
-
emit_only,
|
|
374
|
-
has_node_mapping,
|
|
375
|
-
repo_config,
|
|
376
|
-
document_kind,
|
|
377
|
-
schema_definition,
|
|
378
|
-
directive_count,
|
|
379
|
-
) {
|
|
380
|
-
const presence_context = resolveDirectivePresenceContext(
|
|
381
|
-
validation_field_name,
|
|
382
|
-
emit_only,
|
|
383
|
-
has_node_mapping,
|
|
384
|
-
repo_config,
|
|
385
|
-
schema_definition,
|
|
386
|
-
);
|
|
387
|
-
|
|
388
|
-
if (presence_context === null) {
|
|
389
|
-
return [];
|
|
179
|
+
);
|
|
390
180
|
}
|
|
391
181
|
|
|
392
|
-
const
|
|
182
|
+
const field_definition = repo_config.fields?.[claim.name];
|
|
393
183
|
|
|
394
|
-
if (
|
|
184
|
+
if (!field_definition) {
|
|
395
185
|
return [
|
|
396
186
|
createOriginDiagnostic(
|
|
397
187
|
claim,
|
|
398
|
-
'directive.
|
|
399
|
-
`Directive "${
|
|
188
|
+
'directive.unknown_field',
|
|
189
|
+
`Directive "${claim.name}" is not declared in config.`,
|
|
400
190
|
),
|
|
401
191
|
];
|
|
402
192
|
}
|
|
403
193
|
|
|
404
|
-
if (field_definition
|
|
405
|
-
return [
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
return [
|
|
409
|
-
createOriginDiagnostic(
|
|
410
|
-
claim,
|
|
411
|
-
'directive.duplicate',
|
|
412
|
-
`Directive "${directive_name}" must appear at most once for class "${document_kind}".`,
|
|
413
|
-
),
|
|
414
|
-
];
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
/**
|
|
418
|
-
* @param {{ presence: 'required' | 'optional' | 'forbidden' } | undefined} directive_rule
|
|
419
|
-
* @param {MetadataSchemaConfig | undefined} schema_definition
|
|
420
|
-
* @returns {boolean}
|
|
421
|
-
*/
|
|
422
|
-
function isForbiddenDirective(directive_rule, schema_definition) {
|
|
423
|
-
return (
|
|
424
|
-
directive_rule?.presence === 'forbidden' ||
|
|
425
|
-
(directive_rule === undefined &&
|
|
426
|
-
schema_definition?.unknown_fields === 'error')
|
|
427
|
-
);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* @param {string} validation_field_name
|
|
432
|
-
* @param {boolean} emit_only
|
|
433
|
-
* @param {boolean} has_node_mapping
|
|
434
|
-
* @param {PatramRepoConfig} repo_config
|
|
435
|
-
* @param {MetadataSchemaConfig | undefined} schema_definition
|
|
436
|
-
* @returns {{ directive_rule: ClassFieldRuleConfig | undefined, field_definition: MetadataFieldConfig | undefined } | null}
|
|
437
|
-
*/
|
|
438
|
-
function resolveDirectivePresenceContext(
|
|
439
|
-
validation_field_name,
|
|
440
|
-
emit_only,
|
|
441
|
-
has_node_mapping,
|
|
442
|
-
repo_config,
|
|
443
|
-
schema_definition,
|
|
444
|
-
) {
|
|
445
|
-
if (emit_only) {
|
|
446
|
-
return null;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
const directive_rule = schema_definition?.fields[validation_field_name];
|
|
450
|
-
const field_definition = getDirectiveFieldDefinition(
|
|
451
|
-
repo_config,
|
|
452
|
-
validation_field_name,
|
|
453
|
-
);
|
|
454
|
-
|
|
455
|
-
if (
|
|
456
|
-
!has_node_mapping &&
|
|
457
|
-
directive_rule === undefined &&
|
|
458
|
-
field_definition === undefined
|
|
459
|
-
) {
|
|
460
|
-
return null;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
return {
|
|
464
|
-
directive_rule,
|
|
465
|
-
field_definition,
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* @param {PatramRepoConfig} repo_config
|
|
471
|
-
* @param {string} validation_field_name
|
|
472
|
-
* @returns {MetadataFieldConfig | undefined}
|
|
473
|
-
*/
|
|
474
|
-
function getDirectiveFieldDefinition(repo_config, validation_field_name) {
|
|
475
|
-
if (
|
|
476
|
-
validation_field_name.startsWith('$') ||
|
|
477
|
-
validation_field_name === 'title'
|
|
478
|
-
) {
|
|
479
|
-
return undefined;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
return repo_config.fields?.[validation_field_name];
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
/**
|
|
486
|
-
* @param {BuildGraphResult} graph
|
|
487
|
-
* @param {string} document_path
|
|
488
|
-
* @returns {string}
|
|
489
|
-
*/
|
|
490
|
-
function resolveDocumentKind(graph, document_path) {
|
|
491
|
-
const document_node_id = resolveDocumentNodeId(
|
|
492
|
-
graph.document_node_ids,
|
|
493
|
-
document_path,
|
|
494
|
-
);
|
|
495
|
-
|
|
496
|
-
return (
|
|
497
|
-
graph.nodes[document_node_id]?.$class ??
|
|
498
|
-
graph.nodes[document_node_id]?.kind ??
|
|
499
|
-
'document'
|
|
500
|
-
);
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
/**
|
|
504
|
-
* @param {Record<string, MappingDefinition>} mappings
|
|
505
|
-
* @param {PatramClaim} claim
|
|
506
|
-
* @returns {MappingDefinition | null}
|
|
507
|
-
*/
|
|
508
|
-
function resolveDirectiveMapping(mappings, claim) {
|
|
509
|
-
if (!claim.name || !claim.parser) {
|
|
510
|
-
return null;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
return mappings[`${claim.parser}.directive.${claim.name}`] ?? null;
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
/**
|
|
517
|
-
* @param {string} directive_name
|
|
518
|
-
* @param {MappingDefinition | null} mapping_definition
|
|
519
|
-
* @returns {string}
|
|
520
|
-
*/
|
|
521
|
-
function getDirectiveValidationFieldName(directive_name, mapping_definition) {
|
|
522
|
-
if (mapping_definition?.node?.field) {
|
|
523
|
-
return mapping_definition.node.field;
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
return directive_name;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
/**
|
|
530
|
-
* @param {MappingDefinition | null} mapping_definition
|
|
531
|
-
* @returns {boolean}
|
|
532
|
-
*/
|
|
533
|
-
function isEmitOnlyDirective(mapping_definition) {
|
|
534
|
-
return (
|
|
535
|
-
mapping_definition?.emit !== undefined &&
|
|
536
|
-
mapping_definition.node === undefined
|
|
537
|
-
);
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
/**
|
|
541
|
-
* @param {string} document_path
|
|
542
|
-
* @param {string} document_kind
|
|
543
|
-
* @param {MetadataSchemaConfig | undefined} schema_definition
|
|
544
|
-
* @param {Map<string, number>} directive_counts
|
|
545
|
-
* @returns {PatramDiagnostic[]}
|
|
546
|
-
*/
|
|
547
|
-
function collectMissingDirectiveDiagnostics(
|
|
548
|
-
document_path,
|
|
549
|
-
document_kind,
|
|
550
|
-
schema_definition,
|
|
551
|
-
directive_counts,
|
|
552
|
-
) {
|
|
553
|
-
if (!schema_definition) {
|
|
554
|
-
return [];
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
/** @type {PatramDiagnostic[]} */
|
|
558
|
-
const diagnostics = [];
|
|
559
|
-
|
|
560
|
-
for (const [directive_name, directive_rule] of Object.entries(
|
|
561
|
-
schema_definition.fields,
|
|
562
|
-
)) {
|
|
563
|
-
if (
|
|
564
|
-
directive_rule.presence === 'required' &&
|
|
565
|
-
(directive_counts.get(directive_name) ?? 0) === 0
|
|
566
|
-
) {
|
|
567
|
-
diagnostics.push(
|
|
568
|
-
createDocumentDiagnostic(
|
|
569
|
-
document_path,
|
|
570
|
-
'directive.missing_required',
|
|
571
|
-
`Missing required directive "${directive_name}" for class "${document_kind}".`,
|
|
572
|
-
),
|
|
573
|
-
);
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
return diagnostics;
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
/**
|
|
581
|
-
* @param {PatramRepoConfig} repo_config
|
|
582
|
-
* @param {string} document_path
|
|
583
|
-
* @param {string} document_kind
|
|
584
|
-
* @param {MetadataSchemaConfig | undefined} schema_definition
|
|
585
|
-
* @returns {PatramDiagnostic[]}
|
|
586
|
-
*/
|
|
587
|
-
function collectPlacementDiagnostics(
|
|
588
|
-
repo_config,
|
|
589
|
-
document_path,
|
|
590
|
-
document_kind,
|
|
591
|
-
schema_definition,
|
|
592
|
-
) {
|
|
593
|
-
const document_path_class = schema_definition?.document_path_class;
|
|
594
|
-
|
|
595
|
-
if (!document_path_class) {
|
|
596
|
-
return [];
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
const path_class_definition = repo_config.path_classes?.[document_path_class];
|
|
600
|
-
|
|
601
|
-
if (
|
|
602
|
-
!path_class_definition ||
|
|
603
|
-
path_class_definition.prefixes.some((prefix) =>
|
|
604
|
-
document_path.startsWith(prefix),
|
|
605
|
-
)
|
|
606
|
-
) {
|
|
607
|
-
return [];
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
return [
|
|
611
|
-
createDocumentDiagnostic(
|
|
612
|
-
document_path,
|
|
613
|
-
'document.invalid_placement',
|
|
614
|
-
`Document class "${document_kind}" must be placed in path class "${document_path_class}".`,
|
|
615
|
-
),
|
|
616
|
-
];
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
/**
|
|
620
|
-
* @param {PatramClaim} claim
|
|
621
|
-
* @param {string} document_kind
|
|
622
|
-
* @param {MetadataSchemaConfig | undefined} schema_definition
|
|
623
|
-
* @param {Set<string>} seen_markdown_styles
|
|
624
|
-
* @returns {PatramDiagnostic[]}
|
|
625
|
-
*/
|
|
626
|
-
function collectMarkdownStyleDiagnostics(
|
|
627
|
-
claim,
|
|
628
|
-
document_kind,
|
|
629
|
-
schema_definition,
|
|
630
|
-
seen_markdown_styles,
|
|
631
|
-
) {
|
|
632
|
-
const markdown_style = resolveClaimMarkdownStyle(claim);
|
|
633
|
-
|
|
634
|
-
if (!markdown_style || !claim.name) {
|
|
635
|
-
return [];
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
/** @type {PatramDiagnostic[]} */
|
|
639
|
-
const diagnostics = [];
|
|
640
|
-
const allowed_styles =
|
|
641
|
-
schema_definition?.fields[claim.name]?.markdown_styles ??
|
|
642
|
-
schema_definition?.markdown_styles;
|
|
643
|
-
|
|
644
|
-
if (allowed_styles && !allowed_styles.includes(markdown_style)) {
|
|
645
|
-
diagnostics.push(
|
|
646
|
-
createOriginDiagnostic(
|
|
647
|
-
claim,
|
|
648
|
-
'directive.invalid_style',
|
|
649
|
-
`Directive "${claim.name}" uses markdown style "${markdown_style}" but only ${formatQuotedList(allowed_styles)} are allowed.`,
|
|
650
|
-
),
|
|
651
|
-
);
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
if (
|
|
655
|
-
shouldReportMixedStyles(
|
|
656
|
-
schema_definition,
|
|
657
|
-
seen_markdown_styles,
|
|
658
|
-
markdown_style,
|
|
659
|
-
)
|
|
660
|
-
) {
|
|
661
|
-
diagnostics.push(
|
|
194
|
+
if (field_definition.on && !field_definition.on.includes(document_type)) {
|
|
195
|
+
return [
|
|
662
196
|
createOriginDiagnostic(
|
|
663
197
|
claim,
|
|
664
|
-
'
|
|
665
|
-
`
|
|
198
|
+
'directive.invalid_type_scope',
|
|
199
|
+
`Directive "${claim.name}" is not allowed on type "${document_type}".`,
|
|
666
200
|
),
|
|
667
|
-
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
seen_markdown_styles.add(markdown_style);
|
|
671
|
-
|
|
672
|
-
return diagnostics;
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
/**
|
|
676
|
-
* @param {PatramClaim} claim
|
|
677
|
-
* @returns {string | null}
|
|
678
|
-
*/
|
|
679
|
-
function resolveClaimMarkdownStyle(claim) {
|
|
680
|
-
if (claim.parser !== 'markdown' || claim.markdown_style === undefined) {
|
|
681
|
-
return null;
|
|
201
|
+
];
|
|
682
202
|
}
|
|
683
203
|
|
|
684
|
-
return
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
* @returns {boolean}
|
|
692
|
-
*/
|
|
693
|
-
function shouldReportMixedStyles(
|
|
694
|
-
schema_definition,
|
|
695
|
-
seen_markdown_styles,
|
|
696
|
-
markdown_style,
|
|
697
|
-
) {
|
|
698
|
-
return (
|
|
699
|
-
schema_definition?.mixed_styles === 'error' &&
|
|
700
|
-
seen_markdown_styles.size === 1 &&
|
|
701
|
-
!seen_markdown_styles.has(markdown_style)
|
|
204
|
+
return checkDirectiveValue(
|
|
205
|
+
claim,
|
|
206
|
+
claim.name,
|
|
207
|
+
repo_config,
|
|
208
|
+
document_entity_keys,
|
|
209
|
+
document_node_references,
|
|
210
|
+
document_paths,
|
|
702
211
|
);
|
|
703
212
|
}
|