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
@@ -1,167 +1,65 @@
1
- /** @import * as $k$$l$patram$j$config$k$js from './patram-config.js'; */
2
- /* eslint-disable max-lines */
3
-
4
1
  import { z } from 'zod';
5
2
 
6
- import {
7
- class_definition_schema,
8
- mapping_definition_schema,
9
- relation_definition_schema,
10
- } from './patram-config.js';
11
3
  import { DEFAULT_INCLUDE_PATTERNS } from './source-file-defaults.js';
12
4
 
13
5
  export const CONFIG_FILE_NAME = '.patram.json';
14
6
 
15
7
  const RESERVED_STRUCTURAL_FIELD_NAMES = new Set(['$class', '$id', '$path']);
16
- const MARKDOWN_STYLE_NAMES = [
17
- 'front_matter',
18
- 'visible_line',
19
- 'list_item',
20
- 'hidden_tag',
21
- ];
22
- const MARKDOWN_STYLE_NAME_SET = new Set(MARKDOWN_STYLE_NAMES);
23
- const MIXED_STYLE_VALUES = new Set(['ignore', 'error']);
24
8
 
25
9
  /**
26
10
  * @typedef {z.output<typeof stored_query_schema>} StoredQueryConfig
27
11
  */
28
12
  const stored_query_schema = z
29
13
  .object({
14
+ cypher: z
15
+ .string()
16
+ .min(1, 'Stored query "cypher" must not be empty.')
17
+ .optional(),
30
18
  description: z
31
19
  .string()
32
20
  .min(1, 'Stored query "description" must not be empty.')
33
21
  .optional(),
34
- where: z.string().min(1, 'Stored query "where" must not be empty.'),
35
- })
36
- .strict();
37
-
38
- /**
39
- * @typedef {z.output<typeof derived_summary_scalar_schema>} DerivedSummaryScalar
40
- */
41
- const derived_summary_scalar_schema = z.union([
42
- z.boolean(),
43
- z.number(),
44
- z.string(),
45
- z.null(),
46
- ]);
47
-
48
- /**
49
- * @typedef {z.output<typeof derived_summary_count_schema>} DerivedSummaryCountConfig
50
- */
51
- const derived_summary_count_schema = z
52
- .object({
53
- traversal: z
54
- .string()
55
- .min(1, 'Derived summary count "traversal" must not be empty.'),
56
- where: z
57
- .string()
58
- .min(1, 'Derived summary count "where" must not be empty.'),
59
- })
60
- .strict();
61
-
62
- /**
63
- * @typedef {z.output<typeof derived_summary_select_case_schema>} DerivedSummarySelectCaseConfig
64
- */
65
- const derived_summary_select_case_schema = z
66
- .object({
67
- value: derived_summary_scalar_schema,
68
- when: z.string().min(1, 'Derived summary select "when" must not be empty.'),
69
- })
70
- .strict();
71
-
72
- const derived_summary_field_name_schema = z
73
- .string()
74
- .regex(
75
- /^[a-z][a-z0-9_]*$/du,
76
- 'Derived summary field names must use lower_snake_case.',
77
- );
78
-
79
- /**
80
- * @typedef {z.output<typeof derived_summary_field_schema>} DerivedSummaryFieldConfig
81
- */
82
- const derived_summary_count_field_schema = z
83
- .object({
84
- count: derived_summary_count_schema,
85
- name: derived_summary_field_name_schema,
86
- })
87
- .strict();
88
-
89
- const derived_summary_select_field_schema = z
90
- .object({
91
- default: derived_summary_scalar_schema,
92
- name: derived_summary_field_name_schema,
93
- select: z
94
- .array(derived_summary_select_case_schema)
95
- .min(1, 'Derived summary "select" must contain at least one case.'),
96
- })
97
- .strict();
98
-
99
- const derived_summary_field_schema = z.union([
100
- derived_summary_count_field_schema,
101
- derived_summary_select_field_schema,
102
- ]);
103
-
104
- /**
105
- * @typedef {z.output<typeof derived_summary_schema>} DerivedSummaryConfig
106
- */
107
- const derived_summary_schema = z
108
- .object({
109
- classes: z
110
- .array(z.string().min(1))
111
- .min(1, 'Derived summary "classes" must contain at least one class.'),
112
- fields: z
113
- .array(derived_summary_field_schema)
114
- .min(1, 'Derived summary "fields" must contain at least one field.'),
115
22
  })
116
23
  .strict()
117
- .superRefine(validateDerivedSummaryDefinition);
118
-
119
- /**
120
- * @typedef {z.output<typeof field_display_schema>} FieldDisplayConfig
121
- */
122
- const field_display_schema = z
123
- .object({
124
- hidden: z.boolean().optional(),
125
- order: z.number().optional(),
126
- })
127
- .strict();
128
-
129
- /**
130
- * @typedef {z.output<typeof field_query_schema>} FieldQueryConfig
131
- */
132
- const field_query_schema = z
133
- .object({
134
- contains: z.boolean().optional(),
135
- prefix: z.boolean().optional(),
136
- })
137
- .strict();
24
+ .superRefine((stored_query, refinement_context) => {
25
+ if (stored_query.cypher !== undefined) {
26
+ return;
27
+ }
138
28
 
139
- const field_base_shape = {
140
- display: field_display_schema.optional(),
141
- multiple: z.boolean().optional(),
142
- path_class: z.string().min(1).optional(),
29
+ refinement_context.addIssue({
30
+ code: 'custom',
31
+ message: 'Stored queries require "cypher".',
32
+ path: ['cypher'],
33
+ });
34
+ });
35
+
36
+ const field_common_shape = {
37
+ hidden: z.boolean().optional(),
38
+ many: z.boolean().optional(),
39
+ on: z.array(z.string().min(1)).min(1).optional(),
40
+ order: z.number().int().nonnegative().optional(),
41
+ required_on: z.array(z.string().min(1)).min(1).optional(),
143
42
  };
144
43
 
145
44
  /**
146
- * @typedef {z.output<typeof metadata_field_schema>} MetadataFieldConfig
45
+ * @typedef {z.output<typeof scalar_field_schema>} ScalarFieldConfig
147
46
  */
148
- const metadata_field_schema = z.discriminatedUnion('type', [
47
+ const scalar_field_schema = z.discriminatedUnion('type', [
149
48
  z
150
49
  .object({
151
- ...field_base_shape,
152
- query: field_query_schema.optional(),
50
+ ...field_common_shape,
153
51
  type: z.literal('string'),
154
52
  })
155
53
  .strict(),
156
54
  z
157
55
  .object({
158
- ...field_base_shape,
56
+ ...field_common_shape,
159
57
  type: z.literal('integer'),
160
58
  })
161
59
  .strict(),
162
60
  z
163
61
  .object({
164
- ...field_base_shape,
62
+ ...field_common_shape,
165
63
  type: z.literal('enum'),
166
64
  values: z
167
65
  .array(z.string().min(1, 'Field enum values must not be empty.'))
@@ -170,90 +68,97 @@ const metadata_field_schema = z.discriminatedUnion('type', [
170
68
  .strict(),
171
69
  z
172
70
  .object({
173
- ...field_base_shape,
71
+ ...field_common_shape,
174
72
  type: z.literal('path'),
175
73
  })
176
74
  .strict(),
177
75
  z
178
76
  .object({
179
- ...field_base_shape,
77
+ ...field_common_shape,
180
78
  type: z.literal('glob'),
181
79
  })
182
80
  .strict(),
183
81
  z
184
82
  .object({
185
- ...field_base_shape,
83
+ ...field_common_shape,
186
84
  type: z.literal('date'),
187
85
  })
188
86
  .strict(),
189
87
  z
190
88
  .object({
191
- ...field_base_shape,
89
+ ...field_common_shape,
192
90
  type: z.literal('date_time'),
193
91
  })
194
92
  .strict(),
195
93
  ]);
196
94
 
197
95
  /**
198
- * @typedef {z.output<typeof class_field_rule_schema>} ClassFieldRuleConfig
96
+ * @typedef {z.output<typeof ref_field_schema>} RefFieldConfig
199
97
  */
200
- const class_field_rule_schema = z
98
+ const ref_field_schema = z
201
99
  .object({
202
- markdown_styles: z.array(z.string().min(1)).optional(),
203
- presence: z.enum(['required', 'optional', 'forbidden']),
100
+ ...field_common_shape,
101
+ to: z.string().min(1),
102
+ type: z.literal('ref'),
204
103
  })
205
104
  .strict();
206
105
 
207
106
  /**
208
- * @typedef {z.output<typeof class_schema_schema>} ClassSchemaConfig
107
+ * @typedef {z.output<typeof metadata_field_schema>} MetadataFieldConfig
209
108
  */
210
- const class_schema_schema = z
211
- .object({
212
- document_path_class: z.string().min(1).optional(),
213
- fields: z.record(z.string().min(1), class_field_rule_schema).default({}),
214
- markdown_styles: z.array(z.string().min(1)).optional(),
215
- mixed_styles: z.string().min(1).optional(),
216
- unknown_fields: z.enum(['ignore', 'error']).optional(),
217
- })
218
- .strict();
219
-
220
- const repo_class_definition_schema = class_definition_schema.extend({
221
- schema: class_schema_schema.optional(),
222
- });
109
+ const metadata_field_schema = z.discriminatedUnion('type', [
110
+ ...scalar_field_schema.options,
111
+ ref_field_schema,
112
+ ]);
223
113
 
224
114
  /**
225
- * @typedef {z.output<typeof path_class_schema>} PathClassConfig
115
+ * @typedef {z.output<typeof type_definition_schema>} TypeDefinitionConfig
226
116
  */
227
- const path_class_schema = z
117
+ const type_definition_schema = z
228
118
  .object({
229
- prefixes: z
230
- .array(z.string().min(1, 'Path class prefixes must not be empty.'))
231
- .min(1, 'Path classes must contain at least one prefix.'),
119
+ defined_by: z.string().min(1).optional(),
120
+ in: z
121
+ .union([z.string().min(1), z.array(z.string().min(1)).min(1)])
122
+ .optional(),
123
+ label: z.string().min(1).optional(),
232
124
  })
233
- .strict();
125
+ .strict()
126
+ .superRefine((type_definition, refinement_context) => {
127
+ const has_in = type_definition.in !== undefined;
128
+ const has_defined_by = type_definition.defined_by !== undefined;
129
+
130
+ if (has_in && has_defined_by) {
131
+ refinement_context.addIssue({
132
+ code: 'custom',
133
+ message:
134
+ 'Type definitions must not declare both "in" and "defined_by".',
135
+ });
136
+ return;
137
+ }
138
+
139
+ if (has_in || has_defined_by) {
140
+ return;
141
+ }
142
+
143
+ refinement_context.addIssue({
144
+ code: 'custom',
145
+ message:
146
+ 'Type definitions must declare exactly one of "in" or "defined_by".',
147
+ });
148
+ });
234
149
 
235
150
  /**
236
151
  * @typedef {z.output<typeof patram_repo_config_schema>} PatramRepoConfig
237
152
  */
238
153
  export const patram_repo_config_schema = z
239
154
  .object({
240
- classes: z
241
- .record(z.string().min(1), repo_class_definition_schema)
242
- .optional(),
243
- derived_summaries: z
244
- .record(z.string().min(1), derived_summary_schema)
245
- .optional(),
246
155
  fields: z.record(z.string().min(1), metadata_field_schema).optional(),
247
156
  include: z
248
157
  .array(z.string().min(1, 'Include globs must not be empty.'))
249
158
  .min(1, 'Include must contain at least one glob.')
250
159
  .default(DEFAULT_INCLUDE_PATTERNS),
251
- mappings: z.record(z.string().min(1), mapping_definition_schema).optional(),
252
- path_classes: z.record(z.string().min(1), path_class_schema).optional(),
253
160
  queries: z.record(z.string().min(1), stored_query_schema).default({}),
254
- relations: z
255
- .record(z.string().min(1), relation_definition_schema)
256
- .optional(),
161
+ types: z.record(z.string().min(1), type_definition_schema).optional(),
257
162
  })
258
163
  .strict()
259
164
  .superRefine(validateFieldDefinitionKeys);
@@ -276,33 +181,6 @@ function validateFieldDefinitionKeys(repo_config, refinement_context) {
276
181
  }
277
182
  }
278
183
 
279
- /**
280
- * @param {{ fields: Array<{ name: string }> }} summary_definition
281
- * @param {import('zod').RefinementCtx} refinement_context
282
- */
283
- function validateDerivedSummaryDefinition(
284
- summary_definition,
285
- refinement_context,
286
- ) {
287
- const seen_field_names = new Set();
288
-
289
- for (const [
290
- field_index,
291
- field_definition,
292
- ] of summary_definition.fields.entries()) {
293
- if (!seen_field_names.has(field_definition.name)) {
294
- seen_field_names.add(field_definition.name);
295
- continue;
296
- }
297
-
298
- refinement_context.addIssue({
299
- code: 'custom',
300
- message: `Duplicate derived summary field "${field_definition.name}".`,
301
- path: ['fields', field_index, 'name'],
302
- });
303
- }
304
- }
305
-
306
184
  /**
307
185
  * @param {string} field_name
308
186
  * @returns {boolean}
@@ -310,19 +188,3 @@ function validateDerivedSummaryDefinition(
310
188
  export function isReservedStructuralFieldName(field_name) {
311
189
  return RESERVED_STRUCTURAL_FIELD_NAMES.has(field_name);
312
190
  }
313
-
314
- /**
315
- * @param {string} markdown_style
316
- * @returns {boolean}
317
- */
318
- export function isKnownMarkdownStyle(markdown_style) {
319
- return MARKDOWN_STYLE_NAME_SET.has(markdown_style);
320
- }
321
-
322
- /**
323
- * @param {string} mixed_styles
324
- * @returns {boolean}
325
- */
326
- export function isMixedStyleValue(mixed_styles) {
327
- return MIXED_STYLE_VALUES.has(mixed_styles);
328
- }
@@ -8,9 +8,7 @@
8
8
  import { patram_repo_config_schema } from './schema.js';
9
9
  import { normalizeRepoConfig } from './defaults.js';
10
10
  import {
11
- validateDerivedSummaries,
12
11
  validateFieldSchemaConfig,
13
- validateGraphSchema,
14
12
  validateLegacyConfigShape,
15
13
  validateStoredQueries,
16
14
  } from './validation.js';
@@ -38,40 +36,17 @@ export function validatePatramConfigValue(config_value) {
38
36
  };
39
37
  }
40
38
 
41
- const graph_schema_diagnostics = validateGraphSchema(config_result.data);
42
-
43
- if (graph_schema_diagnostics.length > 0) {
44
- return {
45
- diagnostics: graph_schema_diagnostics,
46
- success: false,
47
- };
48
- }
49
-
50
39
  const normalized_config = normalizeRepoConfig(config_result.data);
51
40
  const field_schema_diagnostics = validateFieldSchemaConfig(normalized_config);
52
-
53
- if (field_schema_diagnostics.length > 0) {
54
- return {
55
- diagnostics: field_schema_diagnostics,
56
- success: false,
57
- };
58
- }
59
-
60
41
  const stored_query_diagnostics = validateStoredQueries(normalized_config);
42
+ const diagnostics = [
43
+ ...field_schema_diagnostics,
44
+ ...stored_query_diagnostics,
45
+ ];
61
46
 
62
- if (stored_query_diagnostics.length > 0) {
63
- return {
64
- diagnostics: stored_query_diagnostics,
65
- success: false,
66
- };
67
- }
68
-
69
- const derived_summary_diagnostics =
70
- validateDerivedSummaries(normalized_config);
71
-
72
- if (derived_summary_diagnostics.length > 0) {
47
+ if (diagnostics.length > 0) {
73
48
  return {
74
- diagnostics: derived_summary_diagnostics,
49
+ diagnostics,
75
50
  success: false,
76
51
  };
77
52
  }
@@ -3,11 +3,6 @@
3
3
  * @returns {PatramDiagnostic[]}
4
4
  */
5
5
  export function validateLegacyConfigShape(config_value: unknown): PatramDiagnostic[];
6
- /**
7
- * @param {PatramRepoConfig} repo_config
8
- * @returns {PatramDiagnostic[]}
9
- */
10
- export function validateGraphSchema(repo_config: PatramRepoConfig): PatramDiagnostic[];
11
6
  /**
12
7
  * @param {PatramRepoConfig} repo_config
13
8
  * @returns {PatramDiagnostic[]}
@@ -18,10 +13,5 @@ export function validateFieldSchemaConfig(repo_config: PatramRepoConfig): Patram
18
13
  * @returns {PatramDiagnostic[]}
19
14
  */
20
15
  export function validateStoredQueries(repo_config: PatramRepoConfig): PatramDiagnostic[];
21
- /**
22
- * @param {PatramRepoConfig} repo_config
23
- * @returns {PatramDiagnostic[]}
24
- */
25
- export function validateDerivedSummaries(repo_config: PatramRepoConfig): PatramDiagnostic[];
26
- import type { PatramDiagnostic } from './load-patram-config.js';
27
- import type { PatramRepoConfig } from './schema.js';
16
+ import type { PatramDiagnostic } from './load-patram-config.types.d.ts';
17
+ import type { PatramRepoConfig } from './load-patram-config.types.d.ts';