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.
Files changed (110) hide show
  1. package/bin/patram.js +4 -4
  2. package/lib/cli/commands/fields.js +0 -4
  3. package/lib/cli/commands/queries.js +10 -20
  4. package/lib/cli/commands/query.js +1 -8
  5. package/lib/cli/commands/refs.js +3 -10
  6. package/lib/cli/commands/show.js +1 -8
  7. package/lib/cli/help-metadata.js +71 -106
  8. package/lib/cli/main.js +10 -10
  9. package/lib/cli/parse-arguments-helpers.js +165 -59
  10. package/lib/cli/parse-arguments.js +4 -4
  11. package/lib/cli/render-help.js +2 -2
  12. package/lib/config/defaults.js +33 -25
  13. package/lib/config/load-patram-config.d.ts +8 -33
  14. package/lib/config/load-patram-config.js +9 -33
  15. package/lib/config/load-patram-config.types.d.ts +3 -40
  16. package/lib/config/manage-stored-queries-helpers.d.ts +4 -4
  17. package/lib/config/manage-stored-queries-helpers.js +91 -33
  18. package/lib/config/manage-stored-queries.d.ts +4 -4
  19. package/lib/config/manage-stored-queries.js +11 -5
  20. package/lib/config/patram-config.d.ts +34 -34
  21. package/lib/config/patram-config.js +3 -3
  22. package/lib/config/patram-config.types.d.ts +5 -11
  23. package/lib/config/resolve-patram-graph-config.d.ts +5 -1
  24. package/lib/config/resolve-patram-graph-config.js +3 -119
  25. package/lib/config/schema.d.ts +158 -269
  26. package/lib/config/schema.js +72 -210
  27. package/lib/config/validate-patram-config-value.js +6 -31
  28. package/lib/config/validation.d.ts +2 -12
  29. package/lib/config/validation.js +125 -483
  30. package/lib/find-close-match.d.ts +4 -1
  31. package/lib/graph/build-graph-identity.d.ts +1 -32
  32. package/lib/graph/build-graph-identity.js +5 -269
  33. package/lib/graph/build-graph.d.ts +13 -4
  34. package/lib/graph/build-graph.js +347 -488
  35. package/lib/graph/build-graph.types.d.ts +8 -9
  36. package/lib/graph/check-directive-metadata-helpers.d.ts +30 -0
  37. package/lib/graph/check-directive-metadata-helpers.js +126 -0
  38. package/lib/graph/check-directive-metadata.d.ts +8 -9
  39. package/lib/graph/check-directive-metadata.js +70 -561
  40. package/lib/graph/check-directive-path-target.d.ts +6 -13
  41. package/lib/graph/check-directive-path-target.js +26 -57
  42. package/lib/graph/check-directive-value.d.ts +1 -5
  43. package/lib/graph/check-directive-value.js +40 -180
  44. package/lib/graph/check-graph.d.ts +5 -5
  45. package/lib/graph/check-graph.js +8 -6
  46. package/lib/graph/document-node-identity.d.ts +23 -7
  47. package/lib/graph/document-node-identity.js +417 -160
  48. package/lib/graph/graph-node.d.ts +42 -0
  49. package/lib/graph/graph-node.js +83 -0
  50. package/lib/graph/inspect-reverse-references.js +16 -11
  51. package/lib/graph/load-project-graph.d.ts +7 -7
  52. package/lib/graph/load-project-graph.js +7 -7
  53. package/lib/graph/parse-where-clause.types.d.ts +3 -2
  54. package/lib/graph/query/cypher-reader.d.ts +59 -0
  55. package/lib/graph/query/cypher-reader.js +151 -0
  56. package/lib/graph/query/cypher-support.d.ts +79 -0
  57. package/lib/graph/query/cypher-support.js +213 -0
  58. package/lib/graph/query/cypher-tokenize.d.ts +13 -0
  59. package/lib/graph/query/cypher-tokenize.js +225 -0
  60. package/lib/graph/query/cypher.types.d.ts +43 -0
  61. package/lib/graph/query/execute.d.ts +7 -7
  62. package/lib/graph/query/execute.js +71 -33
  63. package/lib/graph/query/inspect.js +58 -24
  64. package/lib/graph/query/parse-cypher-patterns.d.ts +27 -0
  65. package/lib/graph/query/parse-cypher-patterns.js +382 -0
  66. package/lib/graph/query/parse-cypher.d.ts +7 -0
  67. package/lib/graph/query/parse-cypher.js +580 -0
  68. package/lib/graph/query/parse-query.d.ts +13 -0
  69. package/lib/graph/query/parse-query.js +97 -0
  70. package/lib/graph/query/resolve.js +77 -23
  71. package/lib/output/command-output.js +12 -5
  72. package/lib/output/compact-layout.js +221 -0
  73. package/lib/output/format-output-item-block.js +31 -1
  74. package/lib/output/format-output-metadata.js +16 -29
  75. package/lib/output/format-stored-query-block.js +95 -0
  76. package/lib/output/layout-incoming-references.js +101 -19
  77. package/lib/output/layout-stored-queries.js +23 -330
  78. package/lib/output/list-queries.js +1 -1
  79. package/lib/output/render-field-discovery.js +11 -2
  80. package/lib/output/render-output-view.js +9 -5
  81. package/lib/output/renderers/json.js +5 -26
  82. package/lib/output/renderers/plain.js +155 -35
  83. package/lib/output/renderers/rich.js +250 -36
  84. package/lib/output/resolved-link-layout.js +43 -0
  85. package/lib/output/rich-source/render.js +193 -35
  86. package/lib/output/show-document.js +25 -18
  87. package/lib/output/view-model/index.js +124 -103
  88. package/lib/parse/jsdoc/parse-jsdoc-blocks.js +1 -1
  89. package/lib/parse/jsdoc/parse-jsdoc-claims.js +12 -6
  90. package/lib/parse/markdown/parse-markdown-claims.js +99 -62
  91. package/lib/parse/markdown/parse-markdown-directives.d.ts +10 -6
  92. package/lib/parse/markdown/parse-markdown-directives.js +104 -18
  93. package/lib/parse/markdown/parse-markdown-prose.d.ts +27 -0
  94. package/lib/parse/markdown/parse-markdown-prose.js +243 -0
  95. package/lib/parse/parse-claims.d.ts +2 -6
  96. package/lib/parse/parse-claims.js +11 -53
  97. package/lib/parse/tagged-fenced/tagged-fenced-blocks.d.ts +4 -4
  98. package/lib/parse/tagged-fenced/tagged-fenced-blocks.js +4 -4
  99. package/lib/parse/yaml/parse-yaml-claims.js +4 -4
  100. package/lib/patram.d.ts +3 -5
  101. package/lib/patram.js +1 -1
  102. package/lib/scan/discover-fields.js +194 -55
  103. package/lib/scan/list-source-files.d.ts +4 -4
  104. package/lib/scan/list-source-files.js +4 -4
  105. package/package.json +1 -1
  106. package/lib/directive-validation-test-helpers.js +0 -87
  107. package/lib/graph/query/parse.d.ts +0 -75
  108. package/lib/graph/query/parse.js +0 -1064
  109. package/lib/output/derived-summary.js +0 -280
  110. package/lib/output/format-derived-summary-row.js +0 -9
@@ -162,7 +162,7 @@ async function renderBlockNode(node, render_state, indent_level) {
162
162
  }
163
163
 
164
164
  if (node_tag === 'table') {
165
- return renderTable(node_children);
165
+ return renderTable(node_children, render_state);
166
166
  }
167
167
 
168
168
  return renderInlineNodes(node_children, render_state);
@@ -252,6 +252,7 @@ async function renderListBlock(
252
252
  /** @type {ComarkElement | null} */
253
253
  let previous_item = null;
254
254
  let rendered_item_count = 0;
255
+ const ordered_marker_width = getOrderedListMarkerWidth(nodes_type, nodes);
255
256
 
256
257
  for (let item_index = 0; item_index < nodes.length; item_index += 1) {
257
258
  const node = nodes[item_index];
@@ -276,6 +277,7 @@ async function renderListBlock(
276
277
  node,
277
278
  item_index + 1,
278
279
  nodes_type === 'ol',
280
+ ordered_marker_width,
279
281
  render_state,
280
282
  indent_level,
281
283
  ),
@@ -291,6 +293,7 @@ async function renderListBlock(
291
293
  * @param {ComarkElement} node
292
294
  * @param {number} item_number
293
295
  * @param {boolean} is_ordered
296
+ * @param {number} ordered_marker_width
294
297
  * @param {RichSourceRenderState} render_state
295
298
  * @param {number} indent_level
296
299
  * @returns {Promise<string>}
@@ -299,10 +302,11 @@ async function renderListItem(
299
302
  node,
300
303
  item_number,
301
304
  is_ordered,
305
+ ordered_marker_width,
302
306
  render_state,
303
307
  indent_level,
304
308
  ) {
305
- const item_prefix = `${' '.repeat(indent_level)}${is_ordered ? `${item_number}.` : '•'} `;
309
+ const item_prefix = `${' '.repeat(indent_level)}${renderListMarker(item_number, is_ordered, ordered_marker_width)} `;
306
310
  const followup_prefix = ' '.repeat(indent_level);
307
311
  const { block_nodes, lead_text } = collectListItemParts(node, render_state);
308
312
 
@@ -368,36 +372,50 @@ async function renderBlockquote(nodes, render_state, indent_level) {
368
372
 
369
373
  /**
370
374
  * @param {ComarkNode[]} nodes
375
+ * @param {RichSourceRenderState} render_state
371
376
  * @returns {string}
372
377
  */
373
- function renderTable(nodes) {
374
- const table_rows = extractTableRows(nodes);
378
+ function renderTable(nodes, render_state) {
379
+ const table_rows = extractTableRows(nodes, render_state);
375
380
 
376
381
  if (table_rows.length === 0) {
377
382
  return '';
378
383
  }
379
384
 
380
- /** @type {number[]} */
381
- const column_widths = [];
382
-
383
- for (const row of table_rows) {
384
- for (let column_index = 0; column_index < row.length; column_index += 1) {
385
- const cell_text = row[column_index];
386
- const current_width = column_widths[column_index] ?? 0;
387
-
388
- column_widths[column_index] = Math.max(current_width, cell_text.length);
389
- }
390
- }
385
+ const { column_alignments, column_widths } = measureTableColumns(table_rows);
391
386
 
392
387
  /** @type {string[]} */
393
- const rendered_lines = [formatTableRow(table_rows[0], column_widths)];
394
-
395
- rendered_lines.push(formatTableDivider(column_widths));
388
+ const rendered_lines = [
389
+ formatTableBorderLine('┌', '┬', '┐', column_widths, render_state.ansi),
390
+ formatTableRow(
391
+ table_rows[0],
392
+ column_widths,
393
+ column_alignments,
394
+ render_state.ansi,
395
+ ),
396
+ ];
397
+
398
+ if (table_rows.length > 1) {
399
+ rendered_lines.push(
400
+ formatTableBorderLine('├', '┼', '┤', column_widths, render_state.ansi),
401
+ );
402
+ }
396
403
 
397
404
  for (let row_index = 1; row_index < table_rows.length; row_index += 1) {
398
- rendered_lines.push(formatTableRow(table_rows[row_index], column_widths));
405
+ rendered_lines.push(
406
+ formatTableRow(
407
+ table_rows[row_index],
408
+ column_widths,
409
+ column_alignments,
410
+ render_state.ansi,
411
+ ),
412
+ );
399
413
  }
400
414
 
415
+ rendered_lines.push(
416
+ formatTableBorderLine('└', '┴', '┘', column_widths, render_state.ansi),
417
+ );
418
+
401
419
  return rendered_lines.join('\n');
402
420
  }
403
421
 
@@ -702,10 +720,11 @@ function renderCodeBlock(
702
720
 
703
721
  /**
704
722
  * @param {ComarkNode[]} nodes
705
- * @returns {string[][]}
723
+ * @param {RichSourceRenderState} render_state
724
+ * @returns {Array<{ cells: Array<{ align: 'center' | 'left' | 'right', text: string }>, is_header: boolean }>}
706
725
  */
707
- function extractTableRows(nodes) {
708
- /** @type {string[][]} */
726
+ function extractTableRows(nodes, render_state) {
727
+ /** @type {Array<{ cells: Array<{ align: 'center' | 'left' | 'right', text: string }>, is_header: boolean }>} */
709
728
  const table_rows = [];
710
729
 
711
730
  for (const node of nodes) {
@@ -724,7 +743,10 @@ function extractTableRows(nodes) {
724
743
  continue;
725
744
  }
726
745
 
727
- table_rows.push(extractTableRowCells(row_node));
746
+ table_rows.push({
747
+ cells: extractTableRowCells(row_node, render_state),
748
+ is_header: node_tag === 'thead',
749
+ });
728
750
  }
729
751
  }
730
752
 
@@ -732,11 +754,50 @@ function extractTableRows(nodes) {
732
754
  }
733
755
 
734
756
  /**
735
- * @param {string[]} row_cells
757
+ * @param {Array<{ cells: Array<{ align: 'center' | 'left' | 'right', text: string }>, is_header: boolean }>} table_rows
758
+ * @returns {{ column_alignments: ('center' | 'left' | 'right')[], column_widths: number[] }}
759
+ */
760
+ function measureTableColumns(table_rows) {
761
+ /** @type {number[]} */
762
+ const column_widths = [];
763
+ /** @type {('center' | 'left' | 'right')[]} */
764
+ const column_alignments = [];
765
+
766
+ for (const row of table_rows) {
767
+ for (
768
+ let column_index = 0;
769
+ column_index < row.cells.length;
770
+ column_index += 1
771
+ ) {
772
+ const table_cell = row.cells[column_index];
773
+ const cell_text = table_cell?.text ?? '';
774
+ const current_width = column_widths[column_index] ?? 0;
775
+
776
+ column_widths[column_index] = Math.max(
777
+ current_width,
778
+ stringWidth(cell_text),
779
+ );
780
+
781
+ if (!column_alignments[column_index]) {
782
+ column_alignments[column_index] = table_cell?.align ?? 'left';
783
+ }
784
+ }
785
+ }
786
+
787
+ return {
788
+ column_alignments,
789
+ column_widths,
790
+ };
791
+ }
792
+
793
+ /**
794
+ * @param {{ cells: Array<{ align: 'center' | 'left' | 'right', text: string }>, is_header: boolean }} row
736
795
  * @param {number[]} column_widths
796
+ * @param {('center' | 'left' | 'right')[]} column_alignments
797
+ * @param {Ansis} ansi
737
798
  * @returns {string}
738
799
  */
739
- function formatTableRow(row_cells, column_widths) {
800
+ function formatTableRow(row, column_widths, column_alignments, ansi) {
740
801
  /** @type {string[]} */
741
802
  const padded_cells = [];
742
803
 
@@ -745,27 +806,47 @@ function formatTableRow(row_cells, column_widths) {
745
806
  column_index < column_widths.length;
746
807
  column_index += 1
747
808
  ) {
748
- const cell_text = row_cells[column_index] ?? '';
809
+ const table_cell = row.cells[column_index] ?? {
810
+ align: column_alignments[column_index] ?? 'left',
811
+ text: '',
812
+ };
813
+ const aligned_text = alignTableCell(
814
+ table_cell.text,
815
+ column_widths[column_index],
816
+ table_cell.align ?? column_alignments[column_index] ?? 'left',
817
+ );
749
818
 
750
- padded_cells.push(cell_text.padEnd(column_widths[column_index], ' '));
819
+ padded_cells.push(row.is_header ? ansi.red(aligned_text) : aligned_text);
751
820
  }
752
821
 
753
- return `| ${padded_cells.join(' | ')} |`;
822
+ return `${ansi.gray('│')} ${padded_cells.join(ansi.gray(' '))} ${ansi.gray('│')}`;
754
823
  }
755
824
 
756
825
  /**
826
+ * @param {'┌' | '├' | '└'} left_border
827
+ * @param {'┬' | '┼' | '┴'} join_border
828
+ * @param {'┐' | '┤' | '┘'} right_border
757
829
  * @param {number[]} column_widths
830
+ * @param {Ansis} ansi
758
831
  * @returns {string}
759
832
  */
760
- function formatTableDivider(column_widths) {
833
+ function formatTableBorderLine(
834
+ left_border,
835
+ join_border,
836
+ right_border,
837
+ column_widths,
838
+ ansi,
839
+ ) {
761
840
  /** @type {string[]} */
762
841
  const divider_cells = [];
763
842
 
764
843
  for (const column_width of column_widths) {
765
- divider_cells.push('-'.repeat(column_width));
844
+ divider_cells.push(''.repeat(column_width + 2));
766
845
  }
767
846
 
768
- return `|-${divider_cells.join('-|-')}-|`;
847
+ return ansi.gray(
848
+ `${left_border}${divider_cells.join(join_border)}${right_border}`,
849
+ );
769
850
  }
770
851
 
771
852
  /**
@@ -803,10 +884,11 @@ function renderInlineCode(nodes, ansi) {
803
884
 
804
885
  /**
805
886
  * @param {ComarkElement} row_node
806
- * @returns {string[]}
887
+ * @param {RichSourceRenderState} render_state
888
+ * @returns {Array<{ align: 'center' | 'left' | 'right', text: string }>}
807
889
  */
808
- function extractTableRowCells(row_node) {
809
- /** @type {string[]} */
890
+ function extractTableRowCells(row_node, render_state) {
891
+ /** @type {Array<{ align: 'center' | 'left' | 'right', text: string }>} */
810
892
  const row_cells = [];
811
893
 
812
894
  for (const cell_node of getElementChildren(row_node)) {
@@ -814,12 +896,53 @@ function extractTableRowCells(row_node) {
814
896
  continue;
815
897
  }
816
898
 
817
- row_cells.push(extractInlineText(getElementChildren(cell_node)));
899
+ row_cells.push({
900
+ align: getTableCellAlignment(cell_node),
901
+ text: renderInlineNodes(getElementChildren(cell_node), render_state),
902
+ });
818
903
  }
819
904
 
820
905
  return row_cells;
821
906
  }
822
907
 
908
+ /**
909
+ * @param {string} text
910
+ * @param {number} content_width
911
+ * @param {'center' | 'left' | 'right'} alignment
912
+ * @returns {string}
913
+ */
914
+ function alignTableCell(text, content_width, alignment) {
915
+ const current_width = stringWidth(text);
916
+ const missing_width = Math.max(content_width - current_width, 0);
917
+
918
+ if (alignment === 'right') {
919
+ return `${' '.repeat(missing_width)}${text}`;
920
+ }
921
+
922
+ if (alignment === 'center') {
923
+ const left_padding = Math.floor(missing_width / 2);
924
+ const right_padding = missing_width - left_padding;
925
+
926
+ return `${' '.repeat(left_padding)}${text}${' '.repeat(right_padding)}`;
927
+ }
928
+
929
+ return `${text}${' '.repeat(missing_width)}`;
930
+ }
931
+
932
+ /**
933
+ * @param {ComarkElement} node
934
+ * @returns {'center' | 'left' | 'right'}
935
+ */
936
+ function getTableCellAlignment(node) {
937
+ const node_props = getElementProps(node);
938
+
939
+ if (node_props.align === 'center' || node_props.align === 'right') {
940
+ return node_props.align;
941
+ }
942
+
943
+ return 'left';
944
+ }
945
+
823
946
  /**
824
947
  * @param {ComarkElement} node
825
948
  * @param {RichSourceRenderState} render_state
@@ -1084,6 +1207,41 @@ function renderParagraphLines(text, prefix) {
1084
1207
  return renderWrappedPrefixedLines(text, prefix, prefix, prefix);
1085
1208
  }
1086
1209
 
1210
+ /**
1211
+ * @param {'ol' | 'ul'} nodes_type
1212
+ * @param {ComarkNode[]} nodes
1213
+ * @returns {number}
1214
+ */
1215
+ function getOrderedListMarkerWidth(nodes_type, nodes) {
1216
+ if (nodes_type !== 'ol') {
1217
+ return 0;
1218
+ }
1219
+
1220
+ let item_count = 0;
1221
+
1222
+ for (const node of nodes) {
1223
+ if (typeof node !== 'string' && getElementTag(node) === 'li') {
1224
+ item_count += 1;
1225
+ }
1226
+ }
1227
+
1228
+ return item_count === 0 ? 0 : `${item_count}.`.length;
1229
+ }
1230
+
1231
+ /**
1232
+ * @param {number} item_number
1233
+ * @param {boolean} is_ordered
1234
+ * @param {number} ordered_marker_width
1235
+ * @returns {string}
1236
+ */
1237
+ function renderListMarker(item_number, is_ordered, ordered_marker_width) {
1238
+ if (!is_ordered) {
1239
+ return '•';
1240
+ }
1241
+
1242
+ return `${item_number}.`.padStart(ordered_marker_width, ' ');
1243
+ }
1244
+
1087
1245
  /**
1088
1246
  * @param {string} value
1089
1247
  * @param {number} indent_level
@@ -9,6 +9,11 @@ import { readFile } from 'node:fs/promises';
9
9
  import { posix, relative, resolve } from 'node:path';
10
10
 
11
11
  import { resolveDocumentNodeId } from '../graph/build-graph-identity.js';
12
+ import {
13
+ getGraphNodeClassName,
14
+ getGraphNodeMetadataValue,
15
+ getGraphNodePath,
16
+ } from '../graph/graph-node.js';
12
17
  import { inspectReverseReferences } from '../graph/inspect-reverse-references.js';
13
18
  import { parseSourceFile } from '../parse/parse-claims.js';
14
19
 
@@ -18,11 +23,11 @@ import { parseSourceFile } from '../parse/parse-claims.js';
18
23
  * Loads one source file, resolves indexed links, and builds the shared show
19
24
  * output model.
20
25
  *
21
- * Kind: output
22
- * Status: active
23
- * Tracked in: ../../docs/plans/v0/source-anchor-dogfooding.md
24
- * Decided by: ../../docs/decisions/show-output.md
25
- * Decided by: ../../docs/decisions/source-rendering.md
26
+ * kind: output
27
+ * status: active
28
+ * tracked_in: ../../docs/plans/v0/source-anchor-dogfooding.md
29
+ * decided_by: ../../docs/decisions/show-output.md
30
+ * decided_by: ../../docs/decisions/source-rendering.md
26
31
  * @patram
27
32
  * @see {@link ./render-output-view.js}
28
33
  * @see {@link ../../docs/decisions/show-output.md}
@@ -96,7 +101,7 @@ export async function loadShowOutput(
96
101
  source_text,
97
102
  parse_result.claims,
98
103
  graph,
99
- graph.document_node_ids,
104
+ graph.document_path_ids,
100
105
  graph.nodes,
101
106
  ),
102
107
  };
@@ -107,7 +112,7 @@ export async function loadShowOutput(
107
112
  * @param {string} source_text
108
113
  * @param {PatramClaim[]} claims
109
114
  * @param {BuildGraphResult} graph
110
- * @param {import('../graph/build-graph.types.ts').BuildGraphResult['document_node_ids']} document_node_ids
115
+ * @param {import('../graph/build-graph.types.ts').BuildGraphResult['document_path_ids']} document_path_ids
111
116
  * @param {Record<string, GraphNode>} graph_nodes
112
117
  * @returns {{ incoming_summary: Record<string, number>, path: string, rendered_source: string, resolved_links: Array<{ label: string, reference: number, target: { kind?: string, path: string, status?: string, title: string } }>, source: string }}
113
118
  */
@@ -116,7 +121,7 @@ function createShowOutput(
116
121
  source_text,
117
122
  claims,
118
123
  graph,
119
- document_node_ids,
124
+ document_path_ids,
120
125
  graph_nodes,
121
126
  ) {
122
127
  const link_claims = claims.filter(isResolvedLinkClaim);
@@ -126,7 +131,7 @@ function createShowOutput(
126
131
  source_file_path,
127
132
  claim,
128
133
  claim_index + 1,
129
- document_node_ids,
134
+ document_path_ids,
130
135
  graph_nodes,
131
136
  ),
132
137
  );
@@ -219,7 +224,7 @@ function renderResolvedSourceLine(
219
224
  * @param {string} source_file_path
220
225
  * @param {PatramClaim} claim
221
226
  * @param {number} reference
222
- * @param {import('../graph/build-graph.types.ts').BuildGraphResult['document_node_ids']} document_node_ids
227
+ * @param {import('../graph/build-graph.types.ts').BuildGraphResult['document_path_ids']} document_path_ids
223
228
  * @param {Record<string, GraphNode>} graph_nodes
224
229
  * @returns {{ label: string, reference: number, target: { kind?: string, path: string, status?: string, title: string } }}
225
230
  */
@@ -227,7 +232,7 @@ function createResolvedLinkSummary(
227
232
  source_file_path,
228
233
  claim,
229
234
  reference,
230
- document_node_ids,
235
+ document_path_ids,
231
236
  graph_nodes,
232
237
  ) {
233
238
  const claim_value = getLinkClaimValue(claim);
@@ -236,7 +241,7 @@ function createResolvedLinkSummary(
236
241
  claim_value.target,
237
242
  );
238
243
  const target_node =
239
- graph_nodes[resolveDocumentNodeId(document_node_ids, target_path)];
244
+ graph_nodes[resolveDocumentNodeId(document_path_ids, target_path)];
240
245
 
241
246
  return {
242
247
  label: claim_value.text,
@@ -284,10 +289,14 @@ function createResolvedLinkTarget(target_node, target_path, fallback_title) {
284
289
  /** @type {{ kind?: string, path: string, status?: string, title: string }} */
285
290
  const resolved_target = {
286
291
  path: getResolvedLinkTargetPath(target_node, target_path),
287
- title: getScalarGraphField(target_node?.title) ?? fallback_title,
292
+ title:
293
+ getScalarGraphField(getGraphNodeMetadataValue(target_node, 'title')) ??
294
+ fallback_title,
288
295
  };
289
296
  const target_kind = getResolvedLinkTargetKind(target_node);
290
- const target_status = getScalarGraphField(target_node?.status);
297
+ const target_status = getScalarGraphField(
298
+ getGraphNodeMetadataValue(target_node, 'status'),
299
+ );
291
300
 
292
301
  if (target_kind) {
293
302
  resolved_target.kind = target_kind;
@@ -305,7 +314,7 @@ function createResolvedLinkTarget(target_node, target_path, fallback_title) {
305
314
  * @returns {string | undefined}
306
315
  */
307
316
  function getResolvedLinkTargetKind(target_node) {
308
- return getScalarGraphField(target_node?.$class ?? target_node?.kind);
317
+ return getScalarGraphField(getGraphNodeClassName(target_node));
309
318
  }
310
319
 
311
320
  /**
@@ -314,9 +323,7 @@ function getResolvedLinkTargetKind(target_node) {
314
323
  * @returns {string}
315
324
  */
316
325
  function getResolvedLinkTargetPath(target_node, target_path) {
317
- return (
318
- getScalarGraphField(target_node?.$path ?? target_node?.path) ?? target_path
319
- );
326
+ return getScalarGraphField(getGraphNodePath(target_node)) ?? target_path;
320
327
  }
321
328
 
322
329
  /**