patram 0.4.0 → 0.6.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 +48 -7
- package/lib/build-graph.js +2 -2
- package/lib/check-directive-metadata.js +175 -6
- package/lib/check-directive-path-target.js +173 -0
- package/lib/check-directive-value.js +122 -125
- package/lib/directive-validation-test-helpers.js +87 -0
- package/lib/load-patram-config.js +263 -116
- package/lib/load-patram-config.types.ts +50 -152
- package/lib/load-project-graph.js +16 -6
- package/lib/parse-claims.js +97 -11
- package/lib/parse-claims.types.ts +7 -0
- package/lib/parse-jsdoc-claims.js +3 -3
- package/lib/parse-markdown-claims.js +9 -3
- package/lib/parse-markdown-directives.js +48 -25
- package/lib/parse-yaml-claims.js +472 -0
- package/lib/patram-config.js +26 -9
- package/lib/patram-config.types.ts +18 -36
- package/lib/render-output-view.js +8 -9
- package/lib/resolve-patram-graph-config.js +40 -2
- package/lib/source-file-defaults.js +3 -0
- package/package.json +2 -1
|
@@ -1,12 +1,8 @@
|
|
|
1
|
+
/** @import * as $k$$l$patram$j$config$k$js from './patram-config.js'; */
|
|
1
2
|
/* eslint-disable max-lines */
|
|
3
|
+
|
|
2
4
|
/**
|
|
3
|
-
* @import {
|
|
4
|
-
* ClassSchemaConfig,
|
|
5
|
-
* LoadPatramConfigResult,
|
|
6
|
-
* MetadataFieldConfig,
|
|
7
|
-
* PatramDiagnostic,
|
|
8
|
-
* PatramRepoConfig,
|
|
9
|
-
* } from './load-patram-config.types.ts';
|
|
5
|
+
* @import { ClassDefinition } from './patram-config.js';
|
|
10
6
|
*/
|
|
11
7
|
|
|
12
8
|
import { readFile } from 'node:fs/promises';
|
|
@@ -15,7 +11,12 @@ import process from 'node:process';
|
|
|
15
11
|
|
|
16
12
|
import { z } from 'zod';
|
|
17
13
|
|
|
18
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
class_definition_schema,
|
|
16
|
+
mapping_definition_schema,
|
|
17
|
+
parsePatramConfig,
|
|
18
|
+
relation_definition_schema,
|
|
19
|
+
} from './patram-config.js';
|
|
19
20
|
import { parseWhereClause } from './parse-where-clause.js';
|
|
20
21
|
import { getQuerySemanticDiagnostics } from './query-inspection.js';
|
|
21
22
|
import { resolvePatramGraphConfig } from './resolve-patram-graph-config.js';
|
|
@@ -39,13 +40,37 @@ import { DEFAULT_INCLUDE_PATTERNS } from './source-file-defaults.js';
|
|
|
39
40
|
|
|
40
41
|
const CONFIG_FILE_NAME = '.patram.json';
|
|
41
42
|
const RESERVED_STRUCTURAL_FIELD_NAMES = new Set(['$class', '$id', '$path']);
|
|
43
|
+
const MARKDOWN_STYLE_NAMES = [
|
|
44
|
+
'front_matter',
|
|
45
|
+
'visible_line',
|
|
46
|
+
'list_item',
|
|
47
|
+
'hidden_tag',
|
|
48
|
+
];
|
|
49
|
+
const MARKDOWN_STYLE_NAME_SET = new Set(MARKDOWN_STYLE_NAMES);
|
|
50
|
+
const MIXED_STYLE_VALUES = new Set(['ignore', 'error']);
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @typedef {object} PatramDiagnostic
|
|
54
|
+
* @property {string} code
|
|
55
|
+
* @property {number} column
|
|
56
|
+
* @property {'error'} level
|
|
57
|
+
* @property {number} line
|
|
58
|
+
* @property {string} message
|
|
59
|
+
* @property {string} path
|
|
60
|
+
*/
|
|
42
61
|
|
|
62
|
+
/**
|
|
63
|
+
* @typedef {z.output<typeof stored_query_schema>} StoredQueryConfig
|
|
64
|
+
*/
|
|
43
65
|
const stored_query_schema = z
|
|
44
66
|
.object({
|
|
45
67
|
where: z.string().min(1, 'Stored query "where" must not be empty.'),
|
|
46
68
|
})
|
|
47
69
|
.strict();
|
|
48
70
|
|
|
71
|
+
/**
|
|
72
|
+
* @typedef {z.output<typeof derived_summary_scalar_schema>} DerivedSummaryScalar
|
|
73
|
+
*/
|
|
49
74
|
const derived_summary_scalar_schema = z.union([
|
|
50
75
|
z.boolean(),
|
|
51
76
|
z.number(),
|
|
@@ -53,6 +78,9 @@ const derived_summary_scalar_schema = z.union([
|
|
|
53
78
|
z.null(),
|
|
54
79
|
]);
|
|
55
80
|
|
|
81
|
+
/**
|
|
82
|
+
* @typedef {z.output<typeof derived_summary_count_schema>} DerivedSummaryCountConfig
|
|
83
|
+
*/
|
|
56
84
|
const derived_summary_count_schema = z
|
|
57
85
|
.object({
|
|
58
86
|
traversal: z
|
|
@@ -64,6 +92,9 @@ const derived_summary_count_schema = z
|
|
|
64
92
|
})
|
|
65
93
|
.strict();
|
|
66
94
|
|
|
95
|
+
/**
|
|
96
|
+
* @typedef {z.output<typeof derived_summary_select_case_schema>} DerivedSummarySelectCaseConfig
|
|
97
|
+
*/
|
|
67
98
|
const derived_summary_select_case_schema = z
|
|
68
99
|
.object({
|
|
69
100
|
value: derived_summary_scalar_schema,
|
|
@@ -71,21 +102,41 @@ const derived_summary_select_case_schema = z
|
|
|
71
102
|
})
|
|
72
103
|
.strict();
|
|
73
104
|
|
|
74
|
-
const
|
|
105
|
+
const derived_summary_field_name_schema = z
|
|
106
|
+
.string()
|
|
107
|
+
.regex(
|
|
108
|
+
/^[a-z][a-z0-9_]*$/du,
|
|
109
|
+
'Derived summary field names must use lower_snake_case.',
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @typedef {z.output<typeof derived_summary_field_schema>} DerivedSummaryFieldConfig
|
|
114
|
+
*/
|
|
115
|
+
const derived_summary_count_field_schema = z
|
|
75
116
|
.object({
|
|
76
|
-
count: derived_summary_count_schema
|
|
77
|
-
|
|
78
|
-
name: z
|
|
79
|
-
.string()
|
|
80
|
-
.regex(
|
|
81
|
-
/^[a-z][a-z0-9_]*$/du,
|
|
82
|
-
'Derived summary field names must use lower_snake_case.',
|
|
83
|
-
),
|
|
84
|
-
select: z.array(derived_summary_select_case_schema).optional(),
|
|
117
|
+
count: derived_summary_count_schema,
|
|
118
|
+
name: derived_summary_field_name_schema,
|
|
85
119
|
})
|
|
86
|
-
.strict()
|
|
87
|
-
.superRefine(validateDerivedSummaryFieldDefinition);
|
|
120
|
+
.strict();
|
|
88
121
|
|
|
122
|
+
const derived_summary_select_field_schema = z
|
|
123
|
+
.object({
|
|
124
|
+
default: derived_summary_scalar_schema,
|
|
125
|
+
name: derived_summary_field_name_schema,
|
|
126
|
+
select: z
|
|
127
|
+
.array(derived_summary_select_case_schema)
|
|
128
|
+
.min(1, 'Derived summary "select" must contain at least one case.'),
|
|
129
|
+
})
|
|
130
|
+
.strict();
|
|
131
|
+
|
|
132
|
+
const derived_summary_field_schema = z.union([
|
|
133
|
+
derived_summary_count_field_schema,
|
|
134
|
+
derived_summary_select_field_schema,
|
|
135
|
+
]);
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @typedef {z.output<typeof derived_summary_schema>} DerivedSummaryConfig
|
|
139
|
+
*/
|
|
89
140
|
const derived_summary_schema = z
|
|
90
141
|
.object({
|
|
91
142
|
classes: z
|
|
@@ -98,6 +149,9 @@ const derived_summary_schema = z
|
|
|
98
149
|
.strict()
|
|
99
150
|
.superRefine(validateDerivedSummaryDefinition);
|
|
100
151
|
|
|
152
|
+
/**
|
|
153
|
+
* @typedef {z.output<typeof field_display_schema>} FieldDisplayConfig
|
|
154
|
+
*/
|
|
101
155
|
const field_display_schema = z
|
|
102
156
|
.object({
|
|
103
157
|
hidden: z.boolean().optional(),
|
|
@@ -105,6 +159,9 @@ const field_display_schema = z
|
|
|
105
159
|
})
|
|
106
160
|
.strict();
|
|
107
161
|
|
|
162
|
+
/**
|
|
163
|
+
* @typedef {z.output<typeof field_query_schema>} FieldQueryConfig
|
|
164
|
+
*/
|
|
108
165
|
const field_query_schema = z
|
|
109
166
|
.object({
|
|
110
167
|
contains: z.boolean().optional(),
|
|
@@ -118,6 +175,9 @@ const field_base_shape = {
|
|
|
118
175
|
path_class: z.string().min(1).optional(),
|
|
119
176
|
};
|
|
120
177
|
|
|
178
|
+
/**
|
|
179
|
+
* @typedef {z.output<typeof metadata_field_schema>} MetadataFieldConfig
|
|
180
|
+
*/
|
|
121
181
|
const metadata_field_schema = z.discriminatedUnion('type', [
|
|
122
182
|
z
|
|
123
183
|
.object({
|
|
@@ -167,20 +227,39 @@ const metadata_field_schema = z.discriminatedUnion('type', [
|
|
|
167
227
|
.strict(),
|
|
168
228
|
]);
|
|
169
229
|
|
|
230
|
+
/**
|
|
231
|
+
* @typedef {z.output<typeof class_field_rule_schema>} ClassFieldRuleConfig
|
|
232
|
+
*/
|
|
170
233
|
const class_field_rule_schema = z
|
|
171
234
|
.object({
|
|
235
|
+
markdown_styles: z.array(z.string().min(1)).optional(),
|
|
172
236
|
presence: z.enum(['required', 'optional', 'forbidden']),
|
|
173
237
|
})
|
|
174
238
|
.strict();
|
|
175
239
|
|
|
240
|
+
/**
|
|
241
|
+
* @typedef {z.output<typeof class_schema_schema>} ClassSchemaConfig
|
|
242
|
+
*/
|
|
176
243
|
const class_schema_schema = z
|
|
177
244
|
.object({
|
|
178
245
|
document_path_class: z.string().min(1).optional(),
|
|
179
246
|
fields: z.record(z.string().min(1), class_field_rule_schema).default({}),
|
|
247
|
+
markdown_styles: z.array(z.string().min(1)).optional(),
|
|
248
|
+
mixed_styles: z.string().min(1).optional(),
|
|
180
249
|
unknown_fields: z.enum(['ignore', 'error']).optional(),
|
|
181
250
|
})
|
|
182
251
|
.strict();
|
|
183
252
|
|
|
253
|
+
/**
|
|
254
|
+
* @typedef {z.output<typeof repo_class_definition_schema>} RepoClassConfig
|
|
255
|
+
*/
|
|
256
|
+
const repo_class_definition_schema = class_definition_schema.extend({
|
|
257
|
+
schema: class_schema_schema.optional(),
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* @typedef {z.output<typeof path_class_schema>} PathClassConfig
|
|
262
|
+
*/
|
|
184
263
|
const path_class_schema = z
|
|
185
264
|
.object({
|
|
186
265
|
prefixes: z
|
|
@@ -189,10 +268,14 @@ const path_class_schema = z
|
|
|
189
268
|
})
|
|
190
269
|
.strict();
|
|
191
270
|
|
|
271
|
+
/**
|
|
272
|
+
* @typedef {z.output<typeof patram_repo_config_schema>} PatramRepoConfig
|
|
273
|
+
*/
|
|
192
274
|
const patram_repo_config_schema = z
|
|
193
275
|
.object({
|
|
194
|
-
|
|
195
|
-
|
|
276
|
+
classes: z
|
|
277
|
+
.record(z.string().min(1), repo_class_definition_schema)
|
|
278
|
+
.optional(),
|
|
196
279
|
derived_summaries: z
|
|
197
280
|
.record(z.string().min(1), derived_summary_schema)
|
|
198
281
|
.optional(),
|
|
@@ -201,14 +284,23 @@ const patram_repo_config_schema = z
|
|
|
201
284
|
.array(z.string().min(1, 'Include globs must not be empty.'))
|
|
202
285
|
.min(1, 'Include must contain at least one glob.')
|
|
203
286
|
.default(DEFAULT_INCLUDE_PATTERNS),
|
|
204
|
-
mappings: z.
|
|
287
|
+
mappings: z.record(z.string().min(1), mapping_definition_schema).optional(),
|
|
205
288
|
path_classes: z.record(z.string().min(1), path_class_schema).optional(),
|
|
206
289
|
queries: z.record(z.string().min(1), stored_query_schema).default({}),
|
|
207
|
-
relations: z
|
|
290
|
+
relations: z
|
|
291
|
+
.record(z.string().min(1), relation_definition_schema)
|
|
292
|
+
.optional(),
|
|
208
293
|
})
|
|
209
294
|
.strict()
|
|
210
295
|
.superRefine(validateFieldDefinitionKeys);
|
|
211
296
|
|
|
297
|
+
/**
|
|
298
|
+
* @typedef {object} LoadPatramConfigResult
|
|
299
|
+
* @property {PatramRepoConfig | null} config
|
|
300
|
+
* @property {string} config_path
|
|
301
|
+
* @property {PatramDiagnostic[]} diagnostics
|
|
302
|
+
*/
|
|
303
|
+
|
|
212
304
|
/**
|
|
213
305
|
* Load and validate the repo Patram config.
|
|
214
306
|
*
|
|
@@ -229,6 +321,14 @@ export async function loadPatramConfig(project_directory = process.cwd()) {
|
|
|
229
321
|
return createLoadResult(null, [parse_result.diagnostic]);
|
|
230
322
|
}
|
|
231
323
|
|
|
324
|
+
const legacy_config_diagnostics = validateLegacyConfigShape(
|
|
325
|
+
parse_result.value,
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
if (legacy_config_diagnostics.length > 0) {
|
|
329
|
+
return createLoadResult(null, legacy_config_diagnostics);
|
|
330
|
+
}
|
|
331
|
+
|
|
232
332
|
const config_result = patram_repo_config_schema.safeParse(parse_result.value);
|
|
233
333
|
|
|
234
334
|
if (!config_result.success) {
|
|
@@ -382,61 +482,6 @@ function validateFieldDefinitionKeys(repo_config, refinement_context) {
|
|
|
382
482
|
}
|
|
383
483
|
}
|
|
384
484
|
|
|
385
|
-
/**
|
|
386
|
-
* @param {{ count?: unknown, default?: unknown, select?: unknown }} field_definition
|
|
387
|
-
* @param {import('zod').RefinementCtx} refinement_context
|
|
388
|
-
*/
|
|
389
|
-
function validateDerivedSummaryFieldDefinition(
|
|
390
|
-
field_definition,
|
|
391
|
-
refinement_context,
|
|
392
|
-
) {
|
|
393
|
-
const evaluator_count =
|
|
394
|
-
Number(field_definition.count !== undefined) +
|
|
395
|
-
Number(field_definition.select !== undefined);
|
|
396
|
-
|
|
397
|
-
if (evaluator_count !== 1) {
|
|
398
|
-
refinement_context.addIssue({
|
|
399
|
-
code: 'custom',
|
|
400
|
-
message:
|
|
401
|
-
'Derived summary fields must define exactly one of "count" or "select".',
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
if (
|
|
406
|
-
field_definition.count !== undefined &&
|
|
407
|
-
field_definition.default !== undefined
|
|
408
|
-
) {
|
|
409
|
-
refinement_context.addIssue({
|
|
410
|
-
code: 'custom',
|
|
411
|
-
message: 'Derived summary count fields must not define "default".',
|
|
412
|
-
path: ['default'],
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
if (field_definition.select === undefined) {
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
if (
|
|
421
|
-
Array.isArray(field_definition.select) &&
|
|
422
|
-
field_definition.select.length === 0
|
|
423
|
-
) {
|
|
424
|
-
refinement_context.addIssue({
|
|
425
|
-
code: 'custom',
|
|
426
|
-
message: 'Derived summary "select" must contain at least one case.',
|
|
427
|
-
path: ['select'],
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
if (field_definition.default === undefined) {
|
|
432
|
-
refinement_context.addIssue({
|
|
433
|
-
code: 'custom',
|
|
434
|
-
message: 'Derived summary select fields must define "default".',
|
|
435
|
-
path: ['default'],
|
|
436
|
-
});
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
485
|
/**
|
|
441
486
|
* @param {{ fields: Array<{ name: string }> }} summary_definition
|
|
442
487
|
* @param {import('zod').RefinementCtx} refinement_context
|
|
@@ -465,7 +510,7 @@ function validateDerivedSummaryDefinition(
|
|
|
465
510
|
}
|
|
466
511
|
|
|
467
512
|
/**
|
|
468
|
-
* @param {
|
|
513
|
+
* @param {PatramRepoConfig} repo_config
|
|
469
514
|
* @returns {PatramDiagnostic[]}
|
|
470
515
|
*/
|
|
471
516
|
function validateGraphSchema(repo_config) {
|
|
@@ -479,7 +524,7 @@ function validateGraphSchema(repo_config) {
|
|
|
479
524
|
|
|
480
525
|
try {
|
|
481
526
|
parsePatramConfig({
|
|
482
|
-
classes: repo_config.classes
|
|
527
|
+
classes: collectGraphClassDefinitions(repo_config.classes),
|
|
483
528
|
mappings: repo_config.mappings ?? {},
|
|
484
529
|
relations: repo_config.relations ?? {},
|
|
485
530
|
});
|
|
@@ -509,9 +554,8 @@ function validateFieldSchemaConfig(repo_config) {
|
|
|
509
554
|
collectClassSchemaConfigDiagnostics(
|
|
510
555
|
diagnostics,
|
|
511
556
|
path_classes,
|
|
512
|
-
classes,
|
|
513
557
|
fields,
|
|
514
|
-
|
|
558
|
+
classes,
|
|
515
559
|
);
|
|
516
560
|
|
|
517
561
|
return diagnostics;
|
|
@@ -586,7 +630,7 @@ function createDefaultRepoConfig() {
|
|
|
586
630
|
}
|
|
587
631
|
|
|
588
632
|
/**
|
|
589
|
-
* @param {
|
|
633
|
+
* @param {PatramRepoConfig} repo_config
|
|
590
634
|
* @returns {PatramRepoConfig}
|
|
591
635
|
*/
|
|
592
636
|
function normalizeRepoConfig(repo_config) {
|
|
@@ -596,11 +640,6 @@ function normalizeRepoConfig(repo_config) {
|
|
|
596
640
|
queries: { ...repo_config.queries },
|
|
597
641
|
};
|
|
598
642
|
|
|
599
|
-
assignOptionalRepoConfigField(
|
|
600
|
-
normalized_config,
|
|
601
|
-
'class_schemas',
|
|
602
|
-
repo_config.class_schemas,
|
|
603
|
-
);
|
|
604
643
|
assignOptionalRepoConfigField(
|
|
605
644
|
normalized_config,
|
|
606
645
|
'classes',
|
|
@@ -635,6 +674,27 @@ function normalizeRepoConfig(repo_config) {
|
|
|
635
674
|
return normalized_config;
|
|
636
675
|
}
|
|
637
676
|
|
|
677
|
+
/**
|
|
678
|
+
* @param {unknown} config_value
|
|
679
|
+
* @returns {PatramDiagnostic[]}
|
|
680
|
+
*/
|
|
681
|
+
function validateLegacyConfigShape(config_value) {
|
|
682
|
+
if (
|
|
683
|
+
config_value === null ||
|
|
684
|
+
typeof config_value !== 'object' ||
|
|
685
|
+
!Object.hasOwn(config_value, 'class_schemas')
|
|
686
|
+
) {
|
|
687
|
+
return [];
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
return [
|
|
691
|
+
createConfigDiagnostic(
|
|
692
|
+
'class_schemas',
|
|
693
|
+
'Top-level "class_schemas" is not supported. Move entries into classes.<name>.schema.',
|
|
694
|
+
),
|
|
695
|
+
];
|
|
696
|
+
}
|
|
697
|
+
|
|
638
698
|
/**
|
|
639
699
|
* @param {PatramDiagnostic[]} diagnostics
|
|
640
700
|
* @param {Map<string, string>} class_coverage
|
|
@@ -669,7 +729,7 @@ function collectDuplicateClassDiagnostics(
|
|
|
669
729
|
* @param {Set<string>} known_relation_names
|
|
670
730
|
* @param {PatramRepoConfig} repo_config
|
|
671
731
|
* @param {string} summary_name
|
|
672
|
-
* @param {
|
|
732
|
+
* @param {DerivedSummaryFieldConfig[]} field_definitions
|
|
673
733
|
*/
|
|
674
734
|
function collectDerivedSummaryFieldDiagnostics(
|
|
675
735
|
diagnostics,
|
|
@@ -861,50 +921,58 @@ function collectFieldPathClassDiagnostic(
|
|
|
861
921
|
/**
|
|
862
922
|
* @param {PatramDiagnostic[]} diagnostics
|
|
863
923
|
* @param {Record<string, { prefixes: string[] }>} path_classes
|
|
864
|
-
* @param {Record<string, unknown>} classes
|
|
865
924
|
* @param {Record<string, MetadataFieldConfig>} fields
|
|
866
|
-
* @param {PatramRepoConfig['
|
|
925
|
+
* @param {NonNullable<PatramRepoConfig['classes']>} classes
|
|
867
926
|
*/
|
|
868
927
|
function collectClassSchemaConfigDiagnostics(
|
|
869
928
|
diagnostics,
|
|
870
929
|
path_classes,
|
|
871
|
-
classes,
|
|
872
930
|
fields,
|
|
873
|
-
|
|
931
|
+
classes,
|
|
874
932
|
) {
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
}
|
|
933
|
+
for (const [class_name, class_definition] of Object.entries(classes)) {
|
|
934
|
+
const schema_definition = class_definition.schema;
|
|
878
935
|
|
|
879
|
-
|
|
880
|
-
if (classes[class_name]) {
|
|
936
|
+
if (!schema_definition) {
|
|
881
937
|
continue;
|
|
882
938
|
}
|
|
883
939
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
940
|
+
collectMarkdownStylesDiagnostic(
|
|
941
|
+
diagnostics,
|
|
942
|
+
`classes.${class_name}.schema.markdown_styles`,
|
|
943
|
+
schema_definition.markdown_styles,
|
|
944
|
+
);
|
|
945
|
+
collectMixedStylesDiagnostic(
|
|
946
|
+
diagnostics,
|
|
947
|
+
`classes.${class_name}.schema.mixed_styles`,
|
|
948
|
+
schema_definition.mixed_styles,
|
|
889
949
|
);
|
|
890
|
-
}
|
|
891
950
|
|
|
892
|
-
for (const [class_name, schema_definition] of Object.entries(class_schemas)) {
|
|
893
951
|
for (const field_name of Object.keys(schema_definition.fields)) {
|
|
894
952
|
if (fields[field_name]) {
|
|
895
|
-
|
|
953
|
+
collectMarkdownStylesDiagnostic(
|
|
954
|
+
diagnostics,
|
|
955
|
+
`classes.${class_name}.schema.fields.${field_name}.markdown_styles`,
|
|
956
|
+
schema_definition.fields[field_name].markdown_styles,
|
|
957
|
+
);
|
|
958
|
+
} else {
|
|
959
|
+
diagnostics.push(
|
|
960
|
+
createConfigDiagnostic(
|
|
961
|
+
`classes.${class_name}.schema.fields.${field_name}`,
|
|
962
|
+
`Unknown field "${field_name}".`,
|
|
963
|
+
),
|
|
964
|
+
);
|
|
896
965
|
}
|
|
897
|
-
|
|
898
|
-
diagnostics.push(
|
|
899
|
-
createConfigDiagnostic(
|
|
900
|
-
`class_schemas.${class_name}.fields.${field_name}`,
|
|
901
|
-
`Unknown field "${field_name}".`,
|
|
902
|
-
),
|
|
903
|
-
);
|
|
904
966
|
}
|
|
905
967
|
}
|
|
906
968
|
|
|
907
|
-
for (const [class_name,
|
|
969
|
+
for (const [class_name, class_definition] of Object.entries(classes)) {
|
|
970
|
+
const schema_definition = class_definition.schema;
|
|
971
|
+
|
|
972
|
+
if (!schema_definition) {
|
|
973
|
+
continue;
|
|
974
|
+
}
|
|
975
|
+
|
|
908
976
|
if (
|
|
909
977
|
schema_definition.document_path_class === undefined ||
|
|
910
978
|
path_classes[schema_definition.document_path_class]
|
|
@@ -914,13 +982,92 @@ function collectClassSchemaConfigDiagnostics(
|
|
|
914
982
|
|
|
915
983
|
diagnostics.push(
|
|
916
984
|
createConfigDiagnostic(
|
|
917
|
-
`
|
|
985
|
+
`classes.${class_name}.schema.document_path_class`,
|
|
918
986
|
`Unknown path class "${schema_definition.document_path_class}".`,
|
|
919
987
|
),
|
|
920
988
|
);
|
|
921
989
|
}
|
|
922
990
|
}
|
|
923
991
|
|
|
992
|
+
/**
|
|
993
|
+
* @param {PatramDiagnostic[]} diagnostics
|
|
994
|
+
* @param {string} diagnostic_path
|
|
995
|
+
* @param {string[] | undefined} markdown_styles
|
|
996
|
+
*/
|
|
997
|
+
function collectMarkdownStylesDiagnostic(
|
|
998
|
+
diagnostics,
|
|
999
|
+
diagnostic_path,
|
|
1000
|
+
markdown_styles,
|
|
1001
|
+
) {
|
|
1002
|
+
if (markdown_styles === undefined) {
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
if (markdown_styles.length === 0) {
|
|
1007
|
+
diagnostics.push(
|
|
1008
|
+
createConfigDiagnostic(
|
|
1009
|
+
diagnostic_path,
|
|
1010
|
+
'Markdown styles must contain at least one style.',
|
|
1011
|
+
),
|
|
1012
|
+
);
|
|
1013
|
+
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
for (const markdown_style of markdown_styles) {
|
|
1018
|
+
if (MARKDOWN_STYLE_NAME_SET.has(markdown_style)) {
|
|
1019
|
+
continue;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
diagnostics.push(
|
|
1023
|
+
createConfigDiagnostic(
|
|
1024
|
+
diagnostic_path,
|
|
1025
|
+
`Unknown markdown style "${markdown_style}".`,
|
|
1026
|
+
),
|
|
1027
|
+
);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
/**
|
|
1032
|
+
* @param {PatramDiagnostic[]} diagnostics
|
|
1033
|
+
* @param {string} diagnostic_path
|
|
1034
|
+
* @param {string | undefined} mixed_styles
|
|
1035
|
+
*/
|
|
1036
|
+
function collectMixedStylesDiagnostic(
|
|
1037
|
+
diagnostics,
|
|
1038
|
+
diagnostic_path,
|
|
1039
|
+
mixed_styles,
|
|
1040
|
+
) {
|
|
1041
|
+
if (mixed_styles === undefined || MIXED_STYLE_VALUES.has(mixed_styles)) {
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
diagnostics.push(
|
|
1046
|
+
createConfigDiagnostic(
|
|
1047
|
+
diagnostic_path,
|
|
1048
|
+
'Mixed styles must be "ignore" or "error".',
|
|
1049
|
+
),
|
|
1050
|
+
);
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
/**
|
|
1054
|
+
* @param {PatramRepoConfig['classes']} classes
|
|
1055
|
+
* @returns {Record<string, ClassDefinition>}
|
|
1056
|
+
*/
|
|
1057
|
+
function collectGraphClassDefinitions(classes) {
|
|
1058
|
+
/** @type {Record<string, ClassDefinition>} */
|
|
1059
|
+
const graph_class_definitions = {};
|
|
1060
|
+
|
|
1061
|
+
for (const [class_name, class_definition] of Object.entries(classes ?? {})) {
|
|
1062
|
+
graph_class_definitions[class_name] = {
|
|
1063
|
+
builtin: class_definition.builtin,
|
|
1064
|
+
label: class_definition.label,
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
return graph_class_definitions;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
924
1071
|
/**
|
|
925
1072
|
* @template {Exclude<keyof PatramRepoConfig, 'include' | 'queries'>} TKey
|
|
926
1073
|
* @param {PatramRepoConfig} normalized_config
|