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.
@@ -0,0 +1,472 @@
1
+ /** @import * as yaml from 'yaml'; */
2
+ /* eslint-disable max-lines */
3
+ /**
4
+ * @import { PatramDiagnostic } from './load-patram-config.types.ts';
5
+ * @import { ParseClaimsInput, ParseSourceFileResult, PatramClaimFields } from './parse-claims.types.ts';
6
+ */
7
+
8
+ import { isMap, isScalar, isSeq, LineCounter, parseAllDocuments } from 'yaml';
9
+
10
+ import { createClaim, getFileExtension } from './claim-helpers.js';
11
+ import { YAML_SOURCE_FILE_EXTENSIONS } from './source-file-defaults.js';
12
+
13
+ /**
14
+ * YAML claim parsing.
15
+ *
16
+ * Parses standalone YAML metadata files and front matter with one projection
17
+ * model for top-level scalar directives.
18
+ *
19
+ * Kind: parse
20
+ * Status: active
21
+ * Tracked in: ../docs/plans/v0/yaml-source-and-front-matter.md
22
+ * Decided by: ../docs/decisions/yaml-source-and-front-matter.md
23
+ * @patram
24
+ * @see {@link ./parse-claims.js}
25
+ * @see {@link ./parse-markdown-directives.js}
26
+ */
27
+
28
+ const YAML_EXTENSIONS = new Set(YAML_SOURCE_FILE_EXTENSIONS);
29
+
30
+ /**
31
+ * Parse standalone YAML source into neutral directive claims.
32
+ *
33
+ * @param {ParseClaimsInput} parse_input
34
+ * @param {{ multi_value_directive_names?: ReadonlySet<string> }} [parse_options]
35
+ * @returns {ParseSourceFileResult}
36
+ */
37
+ export function parseYamlClaims(parse_input, parse_options) {
38
+ if (!YAML_EXTENSIONS.has(getFileExtension(parse_input.path))) {
39
+ return {
40
+ claims: [],
41
+ diagnostics: [],
42
+ };
43
+ }
44
+
45
+ const parse_result = parseYamlDirectiveFields({
46
+ file_path: parse_input.path,
47
+ parser: 'yaml',
48
+ source_text: parse_input.source,
49
+ start_line: 1,
50
+ multi_value_directive_names: parse_options?.multi_value_directive_names,
51
+ });
52
+
53
+ return {
54
+ claims: parse_result.directive_fields.map((directive_fields, claim_index) =>
55
+ createClaim(
56
+ parse_input.path,
57
+ claim_index + 1,
58
+ 'directive',
59
+ directive_fields,
60
+ ),
61
+ ),
62
+ diagnostics: parse_result.diagnostics,
63
+ };
64
+ }
65
+
66
+ /**
67
+ * Parse YAML metadata into neutral directive fields.
68
+ *
69
+ * @param {{
70
+ * file_path: string,
71
+ * parser: 'markdown' | 'yaml',
72
+ * source_text: string,
73
+ * start_line: number,
74
+ * markdown_style?: 'front_matter',
75
+ * multi_value_directive_names?: ReadonlySet<string>,
76
+ * }} parse_input
77
+ * @returns {{ diagnostics: PatramDiagnostic[], directive_fields: PatramClaimFields[] }}
78
+ */
79
+ export function parseYamlDirectiveFields(parse_input) {
80
+ const line_counter = new LineCounter();
81
+ const yaml_documents = parseAllDocuments(parse_input.source_text, {
82
+ lineCounter: line_counter,
83
+ prettyErrors: false,
84
+ });
85
+ const parse_result = resolveYamlParseResult(
86
+ parse_input,
87
+ yaml_documents,
88
+ line_counter,
89
+ );
90
+
91
+ if (!parse_result.success) {
92
+ return parse_result.value;
93
+ }
94
+
95
+ return {
96
+ diagnostics: [],
97
+ directive_fields: collectDirectiveFields(
98
+ parse_input,
99
+ parse_result.value,
100
+ line_counter,
101
+ ),
102
+ };
103
+ }
104
+
105
+ /**
106
+ * @param {{
107
+ * file_path: string,
108
+ * start_line: number,
109
+ * }} parse_input
110
+ * @param {any[]} yaml_documents
111
+ * @param {LineCounter} line_counter
112
+ * @returns {{
113
+ success: true,
114
+ value: yaml.YAMLMap<unknown, unknown>
115
+ } | {
116
+ success: false,
117
+ value: {diagnostics: PatramDiagnostic[], directive_fields: PatramClaimFields[]}
118
+ }}
119
+ * success: true,
120
+ * value: import('yaml').YAMLMap<unknown, unknown>,
121
+ * } | {
122
+ * success: false,
123
+ * value: { diagnostics: PatramDiagnostic[], directive_fields: PatramClaimFields[] },
124
+ * }}
125
+ */
126
+ function resolveYamlParseResult(parse_input, yaml_documents, line_counter) {
127
+ if (yaml_documents.length !== 1) {
128
+ return {
129
+ success: false,
130
+ value: createDiagnosticResult([
131
+ createYamlDiagnostic(
132
+ parse_input.file_path,
133
+ line_counter,
134
+ yaml_documents[1]?.range?.[0] ?? 0,
135
+ parse_input.start_line,
136
+ 'yaml.multiple_documents',
137
+ 'Patram YAML sources must contain exactly one document.',
138
+ ),
139
+ ]),
140
+ };
141
+ }
142
+
143
+ const yaml_document = yaml_documents[0];
144
+
145
+ if (yaml_document.errors.length > 0) {
146
+ return {
147
+ success: false,
148
+ value: createDiagnosticResult(
149
+ yaml_document.errors.map(
150
+ /** @param {{ message: string, pos: [number, number] }} yaml_error */
151
+ (yaml_error) =>
152
+ createYamlDiagnostic(
153
+ parse_input.file_path,
154
+ line_counter,
155
+ yaml_error.pos[0] ?? 0,
156
+ parse_input.start_line,
157
+ 'yaml.invalid_syntax',
158
+ yaml_error.message,
159
+ ),
160
+ ),
161
+ ),
162
+ };
163
+ }
164
+
165
+ if (!isMap(yaml_document.contents)) {
166
+ return {
167
+ success: false,
168
+ value: createDiagnosticResult([
169
+ createYamlDiagnostic(
170
+ parse_input.file_path,
171
+ line_counter,
172
+ resolveNodeRangeStart(yaml_document.contents),
173
+ parse_input.start_line,
174
+ 'yaml.invalid_root',
175
+ 'Patram YAML metadata must use one top-level mapping.',
176
+ ),
177
+ ]),
178
+ };
179
+ }
180
+
181
+ return {
182
+ success: true,
183
+ value: yaml_document.contents,
184
+ };
185
+ }
186
+
187
+ /**
188
+ * @param {{
189
+ * file_path: string,
190
+ * parser: 'markdown' | 'yaml',
191
+ * start_line: number,
192
+ * markdown_style?: 'front_matter',
193
+ * multi_value_directive_names?: ReadonlySet<string>,
194
+ * }} parse_input
195
+ * @param {import('yaml').YAMLMap<unknown, unknown>} yaml_map
196
+ * @param {LineCounter} line_counter
197
+ * @returns {PatramClaimFields[]}
198
+ */
199
+ function collectDirectiveFields(parse_input, yaml_map, line_counter) {
200
+ /** @type {PatramClaimFields[]} */
201
+ const directive_fields = [];
202
+
203
+ for (const pair of yaml_map.items) {
204
+ const pair_fields = createPairDirectiveFields(
205
+ parse_input,
206
+ pair,
207
+ line_counter,
208
+ );
209
+
210
+ directive_fields.push(...pair_fields);
211
+ }
212
+
213
+ return directive_fields;
214
+ }
215
+
216
+ /**
217
+ * @param {{
218
+ * file_path: string,
219
+ * parser: 'markdown' | 'yaml',
220
+ * start_line: number,
221
+ * markdown_style?: 'front_matter',
222
+ * multi_value_directive_names?: ReadonlySet<string>,
223
+ * }} parse_input
224
+ * @param {any} yaml_pair
225
+ * @param {LineCounter} line_counter
226
+ * @returns {PatramClaimFields[]}
227
+ */
228
+ function createPairDirectiveFields(parse_input, yaml_pair, line_counter) {
229
+ const directive_name = resolveDirectiveName(yaml_pair.key);
230
+
231
+ if (!directive_name || yaml_pair.value === null) {
232
+ return [];
233
+ }
234
+
235
+ if (isScalar(yaml_pair.value)) {
236
+ return createScalarDirectiveFields(
237
+ parse_input,
238
+ directive_name,
239
+ yaml_pair.key,
240
+ yaml_pair.value.value,
241
+ line_counter,
242
+ );
243
+ }
244
+
245
+ if (!shouldCollectSequence(parse_input, directive_name, yaml_pair.value)) {
246
+ return [];
247
+ }
248
+
249
+ const sequence_items =
250
+ /** @type {Array<{ range?: [number, number, number], value: unknown }>} */ (
251
+ yaml_pair.value.items
252
+ );
253
+
254
+ return sequence_items.flatMap((sequence_item) =>
255
+ createScalarDirectiveFields(
256
+ parse_input,
257
+ directive_name,
258
+ sequence_item,
259
+ sequence_item.value,
260
+ line_counter,
261
+ ),
262
+ );
263
+ }
264
+
265
+ /**
266
+ * @param {{
267
+ * file_path: string,
268
+ * parser: 'markdown' | 'yaml',
269
+ * start_line: number,
270
+ * markdown_style?: 'front_matter',
271
+ * }} parse_input
272
+ * @param {string} directive_name
273
+ * @param {{ range?: [number, number, number] }} yaml_node
274
+ * @param {unknown} scalar_value
275
+ * @param {LineCounter} line_counter
276
+ * @returns {PatramClaimFields[]}
277
+ */
278
+ function createScalarDirectiveFields(
279
+ parse_input,
280
+ directive_name,
281
+ yaml_node,
282
+ scalar_value,
283
+ line_counter,
284
+ ) {
285
+ const normalized_value = normalizeScalarValue(scalar_value);
286
+
287
+ if (normalized_value === null) {
288
+ return [];
289
+ }
290
+
291
+ return [
292
+ {
293
+ ...createDirectiveBaseFields(parse_input, yaml_node, line_counter),
294
+ name: directive_name,
295
+ value: normalized_value,
296
+ },
297
+ ];
298
+ }
299
+
300
+ /**
301
+ * @param {{
302
+ * multi_value_directive_names?: ReadonlySet<string>,
303
+ * }} parse_input
304
+ * @param {string} directive_name
305
+ * @param {unknown} yaml_value
306
+ * @returns {boolean}
307
+ */
308
+ function shouldCollectSequence(parse_input, directive_name, yaml_value) {
309
+ return (
310
+ isSeq(yaml_value) &&
311
+ parse_input.multi_value_directive_names?.has(directive_name) === true &&
312
+ yaml_value.items.every(isNonNullScalarNode)
313
+ );
314
+ }
315
+
316
+ /**
317
+ * @param {{
318
+ * file_path: string,
319
+ * parser: 'markdown' | 'yaml',
320
+ * start_line: number,
321
+ * markdown_style?: 'front_matter',
322
+ * }} parse_input
323
+ * @param {{ range?: [number, number, number] }} yaml_node
324
+ * @param {LineCounter} line_counter
325
+ * @returns {PatramClaimFields}
326
+ */
327
+ function createDirectiveBaseFields(parse_input, yaml_node, line_counter) {
328
+ /** @type {PatramClaimFields} */
329
+ const directive_fields = {
330
+ name: '',
331
+ origin: createOrigin(
332
+ parse_input.file_path,
333
+ yaml_node.range?.[0] ?? 0,
334
+ parse_input.start_line,
335
+ line_counter,
336
+ ),
337
+ parser: parse_input.parser,
338
+ value: '',
339
+ };
340
+
341
+ if (parse_input.markdown_style !== undefined) {
342
+ directive_fields.markdown_style = parse_input.markdown_style;
343
+ }
344
+
345
+ return directive_fields;
346
+ }
347
+
348
+ /**
349
+ * @param {unknown} yaml_key
350
+ * @returns {string | null}
351
+ */
352
+ function resolveDirectiveName(yaml_key) {
353
+ if (!isScalar(yaml_key) || typeof yaml_key.value !== 'string') {
354
+ return null;
355
+ }
356
+
357
+ return normalizeDirectiveName(yaml_key.value);
358
+ }
359
+
360
+ /**
361
+ * @param {unknown} scalar_value
362
+ * @returns {string | null}
363
+ */
364
+ function normalizeScalarValue(scalar_value) {
365
+ if (scalar_value === null) {
366
+ return null;
367
+ }
368
+
369
+ if (typeof scalar_value === 'string') {
370
+ return scalar_value;
371
+ }
372
+
373
+ if (typeof scalar_value === 'boolean' || typeof scalar_value === 'number') {
374
+ return String(scalar_value);
375
+ }
376
+
377
+ return null;
378
+ }
379
+
380
+ /**
381
+ * @param {unknown} yaml_node
382
+ * @returns {boolean}
383
+ */
384
+ function isNonNullScalarNode(yaml_node) {
385
+ return isScalar(yaml_node) && normalizeScalarValue(yaml_node.value) !== null;
386
+ }
387
+
388
+ /**
389
+ * @param {string} file_path
390
+ * @param {number} offset
391
+ * @param {number} start_line
392
+ * @param {LineCounter} line_counter
393
+ * @returns {{ column: number, line: number, path: string }}
394
+ */
395
+ function createOrigin(file_path, offset, start_line, line_counter) {
396
+ const location = line_counter.linePos(offset);
397
+
398
+ return {
399
+ column: location?.col ?? 1,
400
+ line: (location?.line ?? 1) + start_line - 1,
401
+ path: file_path,
402
+ };
403
+ }
404
+
405
+ /**
406
+ * @param {string} file_path
407
+ * @param {LineCounter} line_counter
408
+ * @param {number} offset
409
+ * @param {number} start_line
410
+ * @param {string} code
411
+ * @param {string} message
412
+ * @returns {PatramDiagnostic}
413
+ */
414
+ function createYamlDiagnostic(
415
+ file_path,
416
+ line_counter,
417
+ offset,
418
+ start_line,
419
+ code,
420
+ message,
421
+ ) {
422
+ const origin = createOrigin(file_path, offset, start_line, line_counter);
423
+
424
+ return {
425
+ code,
426
+ column: origin.column,
427
+ level: 'error',
428
+ line: origin.line,
429
+ message,
430
+ path: file_path,
431
+ };
432
+ }
433
+
434
+ /**
435
+ * @param {PatramDiagnostic[]} diagnostics
436
+ * @returns {{ diagnostics: PatramDiagnostic[], directive_fields: PatramClaimFields[] }}
437
+ */
438
+ function createDiagnosticResult(diagnostics) {
439
+ return {
440
+ diagnostics,
441
+ directive_fields: [],
442
+ };
443
+ }
444
+
445
+ /**
446
+ * @param {unknown} yaml_node
447
+ * @returns {number}
448
+ */
449
+ function resolveNodeRangeStart(yaml_node) {
450
+ if (
451
+ yaml_node &&
452
+ typeof yaml_node === 'object' &&
453
+ 'range' in yaml_node &&
454
+ Array.isArray(yaml_node.range) &&
455
+ typeof yaml_node.range[0] === 'number'
456
+ ) {
457
+ return yaml_node.range[0];
458
+ }
459
+
460
+ return 0;
461
+ }
462
+
463
+ /**
464
+ * @param {string} directive_label
465
+ * @returns {string}
466
+ */
467
+ function normalizeDirectiveName(directive_label) {
468
+ return directive_label
469
+ .trim()
470
+ .toLowerCase()
471
+ .replaceAll(/[\s-]+/dgu, '_');
472
+ }
@@ -1,5 +1,4 @@
1
1
  /**
2
- * @import { PatramConfig } from './patram-config.types.ts';
3
2
  * @import { RefinementCtx } from 'zod';
4
3
  */
5
4
 
@@ -11,14 +10,20 @@ const CLAIM_TYPE_SCHEMA = z.string().min(1);
11
10
  const KEY_SOURCE_SCHEMA = z.enum(['path', 'value']);
12
11
  const TARGET_SCHEMA = z.enum(['path', 'value']);
13
12
 
14
- const class_definition_schema = z
13
+ /**
14
+ * @typedef {z.output<typeof class_definition_schema>} ClassDefinition
15
+ */
16
+ export const class_definition_schema = z
15
17
  .object({
16
18
  builtin: z.boolean().optional(),
17
19
  label: z.string().min(1).optional(),
18
20
  })
19
21
  .strict();
20
22
 
21
- const relation_definition_schema = z
23
+ /**
24
+ * @typedef {z.output<typeof relation_definition_schema>} RelationDefinition
25
+ */
26
+ export const relation_definition_schema = z
22
27
  .object({
23
28
  builtin: z.boolean().optional(),
24
29
  from: z.array(CLASS_NAME_SCHEMA).min(1),
@@ -26,6 +31,9 @@ const relation_definition_schema = z
26
31
  })
27
32
  .strict();
28
33
 
34
+ /**
35
+ * @typedef {z.output<typeof mapping_node_schema>} MappingNodeDefinition
36
+ */
29
37
  const mapping_node_schema = z
30
38
  .object({
31
39
  class: CLASS_NAME_SCHEMA,
@@ -34,6 +42,9 @@ const mapping_node_schema = z
34
42
  })
35
43
  .strict();
36
44
 
45
+ /**
46
+ * @typedef {z.output<typeof mapping_emit_schema>} MappingEmitDefinition
47
+ */
37
48
  const mapping_emit_schema = z
38
49
  .object({
39
50
  relation: RELATION_NAME_SCHEMA,
@@ -42,7 +53,10 @@ const mapping_emit_schema = z
42
53
  })
43
54
  .strict();
44
55
 
45
- const mapping_definition_schema = z
56
+ /**
57
+ * @typedef {z.output<typeof mapping_definition_schema>} MappingDefinition
58
+ */
59
+ export const mapping_definition_schema = z
46
60
  .object({
47
61
  emit: mapping_emit_schema.optional(),
48
62
  node: mapping_node_schema.optional(),
@@ -50,6 +64,9 @@ const mapping_definition_schema = z
50
64
  .strict()
51
65
  .superRefine(validateMappingDefinition);
52
66
 
67
+ /**
68
+ * @typedef {z.output<typeof patramConfigSchema>} PatramGraphConfig
69
+ */
53
70
  export const patramConfigSchema = z
54
71
  .object({
55
72
  $schema: z.url().optional(),
@@ -64,7 +81,7 @@ export const patramConfigSchema = z
64
81
  * Parse and validate Patram JSON configuration.
65
82
  *
66
83
  * @param {unknown} config_json
67
- * @returns {PatramConfig}
84
+ * @returns {PatramGraphConfig}
68
85
  */
69
86
  export function parsePatramConfig(config_json) {
70
87
  return patramConfigSchema.parse(config_json);
@@ -86,7 +103,7 @@ function validateMappingDefinition(mapping_definition, refinement_context) {
86
103
  }
87
104
 
88
105
  /**
89
- * @param {PatramConfig} config_json
106
+ * @param {PatramGraphConfig} config_json
90
107
  * @param {RefinementCtx} refinement_context
91
108
  */
92
109
  function validatePatramConfigReferences(config_json, refinement_context) {
@@ -96,7 +113,7 @@ function validatePatramConfigReferences(config_json, refinement_context) {
96
113
  }
97
114
 
98
115
  /**
99
- * @param {PatramConfig} config_json
116
+ * @param {PatramGraphConfig} config_json
100
117
  * @param {RefinementCtx} refinement_context
101
118
  */
102
119
  function validateRelationClasses(config_json, refinement_context) {
@@ -119,7 +136,7 @@ function validateRelationClasses(config_json, refinement_context) {
119
136
  }
120
137
 
121
138
  /**
122
- * @param {PatramConfig} config_json
139
+ * @param {PatramGraphConfig} config_json
123
140
  * @param {RefinementCtx} refinement_context
124
141
  */
125
142
  function validateMappingClasses(config_json, refinement_context) {
@@ -147,7 +164,7 @@ function validateMappingClasses(config_json, refinement_context) {
147
164
  }
148
165
 
149
166
  /**
150
- * @param {PatramConfig} config_json
167
+ * @param {PatramGraphConfig} config_json
151
168
  * @param {RefinementCtx} refinement_context
152
169
  */
153
170
  function validateMappingRelations(config_json, refinement_context) {
@@ -1,40 +1,22 @@
1
- export interface ClassDefinition {
2
- builtin?: boolean;
3
- label?: string;
4
- }
5
-
6
- export interface RelationDefinition {
7
- builtin?: boolean;
8
- from: string[];
9
- to: string[];
10
- }
11
-
12
- export interface MappingNodeDefinition {
13
- class: string;
14
- field: string;
15
- key?: 'path' | 'value';
16
- }
17
-
18
- export interface MappingEmitDefinition {
19
- relation: string;
20
- target: 'path' | 'value';
21
- target_class: string;
22
- }
23
-
24
- export interface MappingDefinition {
25
- emit?: MappingEmitDefinition;
26
- node?: MappingNodeDefinition;
27
- }
28
-
29
- export interface PatramConfig {
30
- $schema?: string;
31
- classes: Record<string, ClassDefinition>;
32
- class_schemas?: Record<string, ClassSchemaConfig>;
33
- fields?: Record<string, MetadataFieldConfig>;
34
- mappings: Record<string, MappingDefinition>;
35
- relations: Record<string, RelationDefinition>;
36
- }
37
1
  import type {
38
2
  ClassSchemaConfig,
39
3
  MetadataFieldConfig,
40
4
  } from './load-patram-config.types.ts';
5
+
6
+ export type ClassDefinition = import('./patram-config.js').ClassDefinition;
7
+ export type RelationDefinition =
8
+ import('./patram-config.js').RelationDefinition;
9
+ export type MappingNodeDefinition =
10
+ import('./patram-config.js').MappingNodeDefinition;
11
+ export type MappingEmitDefinition =
12
+ import('./patram-config.js').MappingEmitDefinition;
13
+ export type MappingDefinition = import('./patram-config.js').MappingDefinition;
14
+ export type PatramGraphConfig = import('./patram-config.js').PatramGraphConfig;
15
+ export type PatramClassConfig = ClassDefinition & {
16
+ schema?: ClassSchemaConfig;
17
+ };
18
+
19
+ export type PatramConfig = Omit<PatramGraphConfig, 'classes'> & {
20
+ classes: Record<string, PatramClassConfig>;
21
+ fields?: Record<string, MetadataFieldConfig>;
22
+ };
@@ -1,12 +1,11 @@
1
- /** @import * as $k$$l$output$j$view$k$types$k$ts from './output-view.types.ts'; */
2
- /* eslint-disable max-lines */
3
1
  /**
4
2
  * @import { BuildGraphResult, GraphNode } from './build-graph.types.ts';
5
3
  * @import { DerivedSummaryEvaluator } from './derived-summary.js';
6
4
  * @import { PatramRepoConfig } from './load-patram-config.types.ts';
7
5
  * @import { ParsedCliArguments } from './parse-cli-arguments.types.ts';
8
- * @import { OutputMetadataField, OutputStoredQueryItem, OutputView, ResolvedOutputMode, ShowOutputView } from './output-view.types.ts';
6
+ * @import { OutputDerivedSummary, OutputMetadataField, OutputNodeItem, OutputResolvedLinkItem, OutputResolvedLinkTarget, OutputStoredQueryItem, OutputView, ResolvedOutputMode, ShowOutputView } from './output-view.types.ts';
9
7
  */
8
+ /* eslint-disable max-lines */
10
9
 
11
10
  import { renderJsonOutput } from './render-json-output.js';
12
11
  import { renderPlainOutput } from './render-plain-output.js';
@@ -171,9 +170,9 @@ function createStoredQueriesOutputView(stored_queries) {
171
170
 
172
171
  /**
173
172
  * @param {GraphNode} graph_node
174
- * @param {import('./output-view.types.ts').OutputDerivedSummary | null} derived_summary
173
+ * @param {OutputDerivedSummary | null} derived_summary
175
174
  * @param {NonNullable<PatramRepoConfig['fields']>} field_definitions
176
- * @returns {$k$$l$output$j$view$k$types$k$ts.OutputNodeItem}
175
+ * @returns {OutputNodeItem}
177
176
  */
178
177
  function createOutputNodeItem(graph_node, derived_summary, field_definitions) {
179
178
  const title = getOutputNodeTitle(graph_node);
@@ -203,9 +202,9 @@ function createOutputNodeItem(graph_node, derived_summary, field_definitions) {
203
202
  /**
204
203
  * @param {{ kind?: string, path: string, status?: string, title: string }} target
205
204
  * @param {NonNullable<PatramRepoConfig['fields']>} field_definitions
206
- * @param {import('./output-view.types.ts').OutputDerivedSummary | null} derived_summary
205
+ * @param {OutputDerivedSummary | null} derived_summary
207
206
  * @param {GraphNode | undefined} graph_node
208
- * @returns {$k$$l$output$j$view$k$types$k$ts.OutputResolvedLinkTarget}
207
+ * @returns {OutputResolvedLinkTarget}
209
208
  */
210
209
  function createResolvedLinkTarget(
211
210
  target,
@@ -220,7 +219,7 @@ function createResolvedLinkTarget(
220
219
  fields.status = target.status;
221
220
  }
222
221
 
223
- /** @type {$k$$l$output$j$view$k$types$k$ts.OutputResolvedLinkTarget} */
222
+ /** @type {OutputResolvedLinkTarget} */
224
223
  const resolved_target = {
225
224
  derived_summary: derived_summary ?? undefined,
226
225
  fields,
@@ -288,7 +287,7 @@ function getOutputNodeId(graph_node) {
288
287
  /**
289
288
  * @param {{ label: string, reference: number, target: { kind?: string, path: string, status?: string, title: string } }} resolved_link
290
289
  * @param {{ derived_summary_evaluator?: DerivedSummaryEvaluator, document_node_ids?: BuildGraphResult['document_node_ids'], graph_nodes?: BuildGraphResult['nodes'], repo_config?: PatramRepoConfig }} command_options
291
- * @returns {$k$$l$output$j$view$k$types$k$ts.OutputResolvedLinkItem}
290
+ * @returns {OutputResolvedLinkItem}
292
291
  */
293
292
  function createResolvedLinkOutputItem(resolved_link, command_options) {
294
293
  const target_graph_node = resolveDocumentGraphNode(