patram 0.2.0 → 0.4.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 (38) hide show
  1. package/lib/build-graph-identity.js +86 -99
  2. package/lib/build-graph.js +536 -31
  3. package/lib/build-graph.types.ts +6 -2
  4. package/lib/check-directive-metadata.js +534 -0
  5. package/lib/check-directive-value.js +291 -0
  6. package/lib/check-graph.js +23 -5
  7. package/lib/cli-help-metadata.js +56 -16
  8. package/lib/command-output.js +16 -1
  9. package/lib/derived-summary.js +10 -8
  10. package/lib/directive-diagnostics.js +38 -0
  11. package/lib/directive-type-rules.js +133 -0
  12. package/lib/discover-fields.js +435 -0
  13. package/lib/discover-fields.types.ts +52 -0
  14. package/lib/document-node-identity.js +317 -0
  15. package/lib/format-node-header.js +9 -7
  16. package/lib/format-output-metadata.js +15 -23
  17. package/lib/layout-stored-queries.js +124 -85
  18. package/lib/load-patram-config.js +433 -96
  19. package/lib/load-patram-config.types.ts +98 -3
  20. package/lib/load-project-graph.js +4 -1
  21. package/lib/output-view.types.ts +14 -6
  22. package/lib/parse-cli-arguments.types.ts +1 -1
  23. package/lib/parse-where-clause.js +344 -107
  24. package/lib/parse-where-clause.types.ts +25 -8
  25. package/lib/patram-cli.js +68 -4
  26. package/lib/patram-config.js +31 -31
  27. package/lib/patram-config.types.ts +10 -4
  28. package/lib/query-graph.js +269 -40
  29. package/lib/query-inspection.js +440 -60
  30. package/lib/render-field-discovery.js +184 -0
  31. package/lib/render-json-output.js +21 -22
  32. package/lib/render-output-view.js +301 -34
  33. package/lib/render-plain-output.js +1 -1
  34. package/lib/render-rich-output.js +1 -1
  35. package/lib/render-rich-source.js +245 -14
  36. package/lib/resolve-patram-graph-config.js +15 -9
  37. package/lib/show-document.js +66 -9
  38. package/package.json +5 -5
@@ -1,53 +1,24 @@
1
+ /** @import * as $k$$l$document$j$node$j$identity$k$js from './document-node-identity.js'; */
1
2
  /**
2
3
  * @import { GraphNode } from './build-graph.types.ts';
3
4
  * @import { PatramClaim } from './parse-claims.types.ts';
4
- * @import { MappingDefinition } from './patram-config.types.ts';
5
5
  */
6
6
 
7
7
  import { posix } from 'node:path';
8
8
 
9
- /**
10
- * Collect semantic entity keys defined by canonical documents.
11
- *
12
- * @param {Record<string, MappingDefinition>} mappings
13
- * @param {PatramClaim[]} claims
14
- * @returns {Map<string, string>}
15
- */
16
- export function collectDocumentEntityKeys(mappings, claims) {
17
- /** @type {Map<string, string>} */
18
- const document_entity_keys = new Map();
19
-
20
- for (const claim of claims) {
21
- const mapping_definition = resolveMappingDefinition(mappings, claim);
9
+ import { normalizeRepoRelativePath } from './document-node-identity.js';
22
10
 
23
- if (mapping_definition?.node?.key !== 'value') {
24
- continue;
25
- }
26
-
27
- const source_path = normalizeRepoRelativePath(claim.origin.path);
28
- const entity_map_key = getDocumentEntityMapKey(
29
- source_path,
30
- mapping_definition.node.kind,
31
- );
32
- const entity_key = getStringClaimValue(claim);
33
- const existing_entity_key = document_entity_keys.get(entity_map_key);
34
-
35
- if (existing_entity_key && existing_entity_key !== entity_key) {
36
- throw new Error(
37
- `Document "${source_path}" defines multiple ${mapping_definition.node.kind} ids.`,
38
- );
39
- }
40
-
41
- document_entity_keys.set(entity_map_key, entity_key);
42
- }
43
-
44
- return document_entity_keys;
45
- }
11
+ export {
12
+ collectDocumentEntityKeys,
13
+ collectDocumentNodeReferences,
14
+ normalizeRepoRelativePath,
15
+ resolveDocumentNodeId,
16
+ } from './document-node-identity.js';
46
17
 
47
18
  /**
48
19
  * Resolve the node key for one mapped claim.
49
20
  *
50
- * @param {{ field: string, key?: 'path' | 'value', kind: string }} node_mapping
21
+ * @param {{ field: string, key?: 'path' | 'value', class: string }} node_mapping
51
22
  * @param {PatramClaim} claim
52
23
  * @param {Map<string, string>} document_entity_keys
53
24
  * @returns {string}
@@ -55,7 +26,7 @@ export function collectDocumentEntityKeys(mappings, claims) {
55
26
  export function resolveNodeKey(node_mapping, claim, document_entity_keys) {
56
27
  const source_key = normalizeRepoRelativePath(claim.origin.path);
57
28
 
58
- if (node_mapping.kind === 'document') {
29
+ if (node_mapping.class === 'document') {
59
30
  return source_key;
60
31
  }
61
32
 
@@ -65,7 +36,7 @@ export function resolveNodeKey(node_mapping, claim, document_entity_keys) {
65
36
 
66
37
  return (
67
38
  document_entity_keys.get(
68
- getDocumentEntityMapKey(source_key, node_mapping.kind),
39
+ getDocumentEntityMapKey(source_key, node_mapping.class),
69
40
  ) ?? source_key
70
41
  );
71
42
  }
@@ -73,123 +44,95 @@ export function resolveNodeKey(node_mapping, claim, document_entity_keys) {
73
44
  /**
74
45
  * Resolve one edge target key and canonical path.
75
46
  *
76
- * @param {string} target_kind
47
+ * @param {string} target_class
77
48
  * @param {'path' | 'value'} target_type
78
49
  * @param {PatramClaim} claim
79
50
  * @param {Map<string, string>} document_entity_keys
51
+ * @param {Map<string, import('./document-node-identity.js').DocumentNodeReference>} document_node_references
80
52
  * @param {Set<string>} document_paths
81
- * @returns {{ key: string, path?: string }}
53
+ * @returns {{ class_name: string, key: string, path?: string }}
82
54
  */
83
55
  export function resolveTargetReference(
84
- target_kind,
56
+ target_class,
85
57
  target_type,
86
58
  claim,
87
59
  document_entity_keys,
60
+ document_node_references,
88
61
  document_paths,
89
62
  ) {
90
63
  if (target_type === 'value') {
91
- return resolveValueTargetReference(target_kind, claim);
64
+ return resolveValueTargetReference(target_class, claim);
92
65
  }
93
66
 
94
67
  return resolvePathTargetReference(
95
- target_kind,
68
+ target_class,
96
69
  claim,
97
70
  document_entity_keys,
71
+ document_node_references,
98
72
  document_paths,
99
73
  );
100
74
  }
101
75
 
102
76
  /**
103
- * Attach one canonical path to a non-document graph node.
77
+ * Attach one canonical path to a graph node.
104
78
  *
105
79
  * @param {GraphNode} graph_node
106
80
  * @param {string | undefined} source_path
107
81
  */
108
- export function setNonDocumentPath(graph_node, source_path) {
109
- if (!source_path || graph_node.kind === 'document') {
82
+ export function setCanonicalPath(graph_node, source_path) {
83
+ if (!source_path) {
110
84
  return;
111
85
  }
112
86
 
113
- if (!graph_node.path) {
87
+ if (!graph_node.$path) {
88
+ graph_node.$path = source_path;
114
89
  graph_node.path = source_path;
115
90
  return;
116
91
  }
117
92
 
118
- if (graph_node.path !== source_path) {
93
+ if (graph_node.$path !== source_path) {
119
94
  throw new Error(
120
95
  `Node "${graph_node.id}" maps to multiple canonical paths.`,
121
96
  );
122
97
  }
123
98
  }
124
99
 
125
- /**
126
- * Normalize one repo-relative source path.
127
- *
128
- * @param {string} source_path
129
- * @returns {string}
130
- */
131
- export function normalizeRepoRelativePath(source_path) {
132
- return posix.normalize(source_path.replaceAll('\\', '/'));
133
- }
134
-
135
- /**
136
- * @param {Record<string, MappingDefinition>} mappings
137
- * @param {PatramClaim} claim
138
- * @returns {MappingDefinition | null}
139
- */
140
- function resolveMappingDefinition(mappings, claim) {
141
- if (claim.type === 'directive') {
142
- return resolveDirectiveMapping(mappings, claim);
143
- }
144
-
145
- return mappings[claim.type] ?? null;
146
- }
147
-
148
- /**
149
- * @param {Record<string, MappingDefinition>} mappings
150
- * @param {PatramClaim} claim
151
- * @returns {MappingDefinition | null}
152
- */
153
- function resolveDirectiveMapping(mappings, claim) {
154
- if (!claim.parser || !claim.name) {
155
- return null;
156
- }
157
-
158
- return mappings[`${claim.parser}.directive.${claim.name}`] ?? null;
159
- }
160
-
161
100
  /**
162
101
  * @param {string} target_kind
163
102
  * @param {PatramClaim} claim
164
- * @returns {{ key: string, path?: string }}
103
+ * @returns {{ class_name: string, key: string, path?: string }}
165
104
  */
166
105
  function resolveValueTargetReference(target_kind, claim) {
167
106
  const target_key = getStringClaimValue(claim);
168
107
 
169
108
  if (target_kind === 'document') {
170
109
  return {
110
+ class_name: 'document',
171
111
  key: target_key,
172
112
  path: target_key,
173
113
  };
174
114
  }
175
115
 
176
116
  return {
117
+ class_name: target_kind,
177
118
  key: target_key,
178
119
  path: normalizeRepoRelativePath(claim.origin.path),
179
120
  };
180
121
  }
181
122
 
182
123
  /**
183
- * @param {string} target_kind
124
+ * @param {string} target_class
184
125
  * @param {PatramClaim} claim
185
126
  * @param {Map<string, string>} document_entity_keys
127
+ * @param {Map<string, import('./document-node-identity.js').DocumentNodeReference>} document_node_references
186
128
  * @param {Set<string>} document_paths
187
- * @returns {{ key: string, path?: string }}
129
+ * @returns {{ class_name: string, key: string, path?: string }}
188
130
  */
189
131
  function resolvePathTargetReference(
190
- target_kind,
132
+ target_class,
191
133
  claim,
192
134
  document_entity_keys,
135
+ document_node_references,
193
136
  document_paths,
194
137
  ) {
195
138
  const raw_target = getPathTargetValue(claim);
@@ -199,19 +142,52 @@ function resolvePathTargetReference(
199
142
  document_paths,
200
143
  );
201
144
 
202
- if (target_kind === 'document') {
145
+ if (target_class === 'document') {
146
+ return resolveDocumentTargetReference(
147
+ target_path,
148
+ document_node_references,
149
+ );
150
+ }
151
+
152
+ const document_node_reference = document_node_references.get(target_path);
153
+
154
+ if (documentNodeReferenceIsPromoted(document_node_reference)) {
203
155
  return {
204
- key: target_path,
156
+ class_name: document_node_reference.class_name,
157
+ key: document_node_reference.key,
205
158
  path: target_path,
206
159
  };
207
160
  }
208
161
 
209
- const semantic_target_key = document_entity_keys.get(
210
- getDocumentEntityMapKey(target_path, target_kind),
211
- );
162
+ return {
163
+ class_name: target_class,
164
+ key:
165
+ document_entity_keys.get(
166
+ getDocumentEntityMapKey(target_path, target_class),
167
+ ) ?? target_path,
168
+ path: target_path,
169
+ };
170
+ }
171
+
172
+ /**
173
+ * @param {string} target_path
174
+ * @param {Map<string, import('./document-node-identity.js').DocumentNodeReference>} document_node_references
175
+ * @returns {{ class_name: string, key: string, path?: string }}
176
+ */
177
+ function resolveDocumentTargetReference(target_path, document_node_references) {
178
+ const document_node_reference = document_node_references.get(target_path);
179
+
180
+ if (!document_node_reference) {
181
+ return {
182
+ class_name: 'document',
183
+ key: target_path,
184
+ path: target_path,
185
+ };
186
+ }
212
187
 
213
188
  return {
214
- key: semantic_target_key ?? target_path,
189
+ class_name: document_node_reference.class_name,
190
+ key: document_node_reference.key,
215
191
  path: target_path,
216
192
  };
217
193
  }
@@ -262,9 +238,20 @@ function getStringClaimValue(claim) {
262
238
 
263
239
  /**
264
240
  * @param {string} document_path
265
- * @param {string} kind_name
241
+ * @param {string} class_name
266
242
  * @returns {string}
267
243
  */
268
- function getDocumentEntityMapKey(document_path, kind_name) {
269
- return `${kind_name}:${document_path}`;
244
+ function getDocumentEntityMapKey(document_path, class_name) {
245
+ return `${class_name}:${document_path}`;
246
+ }
247
+
248
+ /**
249
+ * @param {import('./document-node-identity.js').DocumentNodeReference | undefined} document_node_reference
250
+ * @returns {document_node_reference is $k$$l$document$j$node$j$identity$k$js.DocumentNodeReference}
251
+ */
252
+ function documentNodeReferenceIsPromoted(document_node_reference) {
253
+ return (
254
+ document_node_reference !== undefined &&
255
+ document_node_reference.class_name !== 'document'
256
+ );
270
257
  }