patram 0.1.1 → 0.3.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 (49) hide show
  1. package/lib/build-graph-identity.js +57 -24
  2. package/lib/build-graph.js +383 -17
  3. package/lib/build-graph.types.ts +5 -2
  4. package/lib/check-directive-metadata.js +516 -0
  5. package/lib/check-directive-value.js +282 -0
  6. package/lib/check-graph.js +24 -5
  7. package/lib/cli-help-metadata.js +580 -0
  8. package/lib/derived-summary.js +280 -0
  9. package/lib/directive-diagnostics.js +38 -0
  10. package/lib/directive-type-rules.js +133 -0
  11. package/lib/discover-fields.js +427 -0
  12. package/lib/discover-fields.types.ts +52 -0
  13. package/lib/format-derived-summary-row.js +9 -0
  14. package/lib/format-node-header.js +21 -0
  15. package/lib/format-output-item-block.js +22 -0
  16. package/lib/format-output-metadata.js +54 -0
  17. package/lib/layout-stored-queries.js +96 -2
  18. package/lib/load-patram-config.js +754 -18
  19. package/lib/load-patram-config.types.ts +128 -2
  20. package/lib/load-project-graph.js +4 -1
  21. package/lib/output-view.types.ts +29 -6
  22. package/lib/parse-cli-arguments-helpers.js +263 -90
  23. package/lib/parse-cli-arguments.js +160 -8
  24. package/lib/parse-cli-arguments.types.ts +49 -4
  25. package/lib/parse-where-clause.js +670 -209
  26. package/lib/parse-where-clause.types.ts +72 -0
  27. package/lib/patram-cli.js +180 -21
  28. package/lib/patram-config.js +31 -31
  29. package/lib/patram-config.types.ts +10 -4
  30. package/lib/patram.js +6 -0
  31. package/lib/query-graph.js +444 -113
  32. package/lib/query-inspection.js +798 -0
  33. package/lib/render-check-output.js +1 -1
  34. package/lib/render-cli-help.js +419 -0
  35. package/lib/render-field-discovery.js +148 -0
  36. package/lib/render-json-output.js +66 -14
  37. package/lib/render-output-view.js +272 -22
  38. package/lib/render-plain-output.js +31 -86
  39. package/lib/render-rich-output.js +34 -87
  40. package/lib/resolve-patram-graph-config.js +15 -9
  41. package/lib/resolve-where-clause.js +18 -3
  42. package/lib/show-document.js +51 -7
  43. package/lib/tagged-fenced-block-error.js +17 -0
  44. package/lib/tagged-fenced-block-markdown.js +111 -0
  45. package/lib/tagged-fenced-block-metadata.js +97 -0
  46. package/lib/tagged-fenced-block-parser.js +292 -0
  47. package/lib/tagged-fenced-blocks.js +100 -0
  48. package/lib/tagged-fenced-blocks.types.ts +38 -0
  49. package/package.json +12 -7
@@ -0,0 +1,72 @@
1
+ import type { PatramDiagnostic } from './load-patram-config.types.ts';
2
+
3
+ export type ParsedFieldName = string;
4
+
5
+ export interface ParsedFieldTerm {
6
+ column: number;
7
+ field_name: ParsedFieldName;
8
+ kind: 'field';
9
+ operator: '!=' | '<' | '<=' | '=' | '>' | '>=' | '^=' | '~';
10
+ value: string;
11
+ }
12
+
13
+ export interface ParsedFieldSetTerm {
14
+ column: number;
15
+ field_name: ParsedFieldName;
16
+ kind: 'field_set';
17
+ operator: 'in' | 'not in';
18
+ values: string[];
19
+ }
20
+
21
+ export interface ParsedTraversalTerm {
22
+ column: number;
23
+ direction: 'in' | 'out';
24
+ relation_name: string;
25
+ }
26
+
27
+ export interface ParsedRelationTerm {
28
+ column: number;
29
+ kind: 'relation';
30
+ relation_name: string;
31
+ }
32
+
33
+ export interface ParsedRelationTargetTerm {
34
+ column: number;
35
+ kind: 'relation_target';
36
+ relation_name: string;
37
+ target_id: string;
38
+ }
39
+
40
+ export type ParsedAggregateComparison = '!=' | '<' | '<=' | '=' | '>' | '>=';
41
+ export type ParsedAggregateName = 'any' | 'count' | 'none';
42
+
43
+ export interface ParsedAggregateTerm {
44
+ aggregate_name: ParsedAggregateName;
45
+ clauses: ParsedClause[];
46
+ comparison?: ParsedAggregateComparison;
47
+ kind: 'aggregate';
48
+ traversal: ParsedTraversalTerm;
49
+ value?: number;
50
+ }
51
+
52
+ export type ParsedTerm =
53
+ | ParsedAggregateTerm
54
+ | ParsedFieldSetTerm
55
+ | ParsedFieldTerm
56
+ | ParsedRelationTargetTerm
57
+ | ParsedRelationTerm;
58
+
59
+ export interface ParsedClause {
60
+ is_negated: boolean;
61
+ term: ParsedTerm;
62
+ }
63
+
64
+ export type ParseWhereClauseResult =
65
+ | {
66
+ clauses: ParsedClause[];
67
+ success: true;
68
+ }
69
+ | {
70
+ diagnostic: PatramDiagnostic;
71
+ success: false;
72
+ };
package/lib/patram-cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable max-lines */
2
2
  /**
3
- * @import { ParsedCliArguments } from './parse-cli-arguments.types.ts';
3
+ * @import { ParsedCliCommandRequest } from './parse-cli-arguments.types.ts';
4
4
  */
5
5
 
6
6
  import process from 'node:process';
@@ -10,16 +10,24 @@ import {
10
10
  shouldPageCommandOutput,
11
11
  writeCommandOutput,
12
12
  } from './command-output.js';
13
+ import { discoverFields } from './discover-fields.js';
13
14
  import { listRepoFiles } from './list-source-files.js';
14
15
  import { listQueries } from './list-queries.js';
15
16
  import { loadPatramConfig } from './load-patram-config.js';
16
17
  import { loadProjectGraph } from './load-project-graph.js';
17
18
  import { parseCliArguments } from './parse-cli-arguments.js';
18
19
  import { DEFAULT_QUERY_LIMIT, queryGraph } from './query-graph.js';
20
+ import { inspectQuery, renderQueryInspection } from './query-inspection.js';
21
+ import { createDerivedSummaryEvaluator } from './derived-summary.js';
19
22
  import {
20
23
  renderCheckDiagnostics,
21
24
  renderCheckSuccess,
22
25
  } from './render-check-output.js';
26
+ import {
27
+ renderCliParseError,
28
+ renderHelpRequest,
29
+ renderInvalidWhereDiagnostic,
30
+ } from './render-cli-help.js';
23
31
  import {
24
32
  resolveCheckTarget,
25
33
  selectCheckTargetDiagnostics,
@@ -29,6 +37,7 @@ import {
29
37
  createOutputView,
30
38
  createShowOutputView,
31
39
  } from './render-output-view.js';
40
+ import { renderFieldDiscovery } from './render-field-discovery.js';
32
41
  import { resolveWhereClause } from './resolve-where-clause.js';
33
42
  import { resolveOutputMode } from './resolve-output-mode.js';
34
43
  import { loadShowOutput } from './show-document.js';
@@ -36,8 +45,8 @@ import { loadShowOutput } from './show-document.js';
36
45
  /**
37
46
  * Patram command execution flow.
38
47
  *
39
- * Loads repo state and routes `check`, `query`, `queries`, and `show` through
40
- * the shared output pipeline.
48
+ * Loads repo state and routes `check`, `fields`, `query`, `queries`, and
49
+ * `show` through the shared output pipeline.
41
50
  *
42
51
  * Kind: cli
43
52
  * Status: active
@@ -64,12 +73,20 @@ export async function main(cli_arguments, io_context) {
64
73
  const parsed_arguments = parseCliArguments(cli_arguments);
65
74
 
66
75
  if (!parsed_arguments.success) {
67
- io_context.stderr.write(`${parsed_arguments.message}\n`);
76
+ io_context.stderr.write(renderCliParseError(parsed_arguments.error));
68
77
 
69
78
  return 1;
70
79
  }
71
80
 
72
- const parsed_command = parsed_arguments.value;
81
+ if (parsed_arguments.value.kind === 'help') {
82
+ io_context.stdout.write(renderHelpRequest(parsed_arguments.value));
83
+
84
+ return 0;
85
+ }
86
+
87
+ const parsed_command = /** @type {ParsedCliCommandRequest} */ (
88
+ parsed_arguments.value
89
+ );
73
90
 
74
91
  if (parsed_command.command_name === 'check') {
75
92
  return runCheckCommand(parsed_command, io_context);
@@ -79,6 +96,10 @@ export async function main(cli_arguments, io_context) {
79
96
  return runQueryCommand(parsed_command, io_context);
80
97
  }
81
98
 
99
+ if (parsed_command.command_name === 'fields') {
100
+ return runFieldsCommand(parsed_command, io_context);
101
+ }
102
+
82
103
  if (parsed_command.command_name === 'queries') {
83
104
  return runQueriesCommand(parsed_command, io_context);
84
105
  }
@@ -93,7 +114,7 @@ export async function main(cli_arguments, io_context) {
93
114
  }
94
115
 
95
116
  /**
96
- * @param {ParsedCliArguments} parsed_command
117
+ * @param {ParsedCliCommandRequest} parsed_command
97
118
  * @param {{ stderr: { write(chunk: string): boolean }, stdout: { isTTY?: boolean, write(chunk: string): boolean }, write_paged_output?: (output_text: string) => Promise<void> }} io_context
98
119
  * @returns {Promise<number>}
99
120
  */
@@ -125,7 +146,12 @@ async function runCheckCommand(parsed_command, io_context) {
125
146
  return 1;
126
147
  }
127
148
 
128
- const diagnostics = checkGraph(project_graph_result.graph, repo_file_paths);
149
+ const diagnostics = checkGraph(
150
+ project_graph_result.graph,
151
+ repo_file_paths,
152
+ project_graph_result.config,
153
+ project_graph_result.claims,
154
+ );
129
155
  const selected_diagnostics = selectCheckTargetDiagnostics(
130
156
  diagnostics,
131
157
  resolved_target,
@@ -147,12 +173,27 @@ async function runCheckCommand(parsed_command, io_context) {
147
173
  }
148
174
 
149
175
  /**
150
- * @param {ParsedCliArguments} parsed_command
176
+ * @param {ParsedCliCommandRequest} parsed_command
151
177
  * @param {{ stderr: { write(chunk: string): boolean }, stdout: { isTTY?: boolean, write(chunk: string): boolean }, write_paged_output?: (output_text: string) => Promise<void> }} io_context
152
178
  * @returns {Promise<number>}
153
179
  */
154
180
  async function runQueryCommand(parsed_command, io_context) {
155
181
  const use_pager = shouldPageCommandOutput(parsed_command, io_context.stdout);
182
+ const output_mode = resolveOutputMode(parsed_command, {
183
+ is_tty: io_context.stdout.isTTY === true,
184
+ no_color: process.env.NO_COLOR !== undefined,
185
+ term: process.env.TERM,
186
+ });
187
+
188
+ if (parsed_command.query_inspection_mode) {
189
+ return runQueryInspectionCommand(
190
+ parsed_command,
191
+ io_context,
192
+ output_mode,
193
+ use_pager,
194
+ );
195
+ }
196
+
156
197
  const project_graph_result = await loadProjectGraph(process.cwd());
157
198
 
158
199
  if (project_graph_result.diagnostics.length > 0) {
@@ -174,31 +215,123 @@ async function runQueryCommand(parsed_command, io_context) {
174
215
 
175
216
  const query_result = queryGraph(
176
217
  project_graph_result.graph,
177
- where_clause.value,
218
+ where_clause.value.where_clause,
219
+ project_graph_result.config,
178
220
  createQueryPaginationOptions(parsed_command, use_pager),
179
221
  );
180
222
 
181
223
  if (query_result.diagnostics.length > 0) {
182
- writeDiagnostics(io_context.stderr, query_result.diagnostics);
224
+ io_context.stderr.write(
225
+ renderInvalidWhereDiagnostic(query_result.diagnostics[0]),
226
+ );
183
227
 
184
228
  return 1;
185
229
  }
186
230
 
231
+ const derived_summary_evaluator = createDerivedSummaryEvaluator(
232
+ project_graph_result.config,
233
+ project_graph_result.graph,
234
+ );
235
+
187
236
  await writeCommandOutput(
188
237
  io_context,
189
238
  parsed_command,
190
- createOutputView(
191
- 'query',
192
- query_result.nodes,
193
- createQueryOutputOptions(parsed_command, query_result, use_pager),
194
- ),
239
+ createOutputView('query', query_result.nodes, {
240
+ derived_summary_evaluator,
241
+ ...createQueryOutputOptions(parsed_command, query_result, use_pager),
242
+ repo_config: project_graph_result.config,
243
+ }),
244
+ );
245
+
246
+ return 0;
247
+ }
248
+
249
+ /**
250
+ * @param {ParsedCliCommandRequest} parsed_command
251
+ * @param {{ stderr: { write(chunk: string): boolean }, stdout: { isTTY?: boolean, write(chunk: string): boolean } }} io_context
252
+ * @returns {Promise<number>}
253
+ */
254
+ async function runFieldsCommand(parsed_command, io_context) {
255
+ const output_mode = resolveOutputMode(parsed_command, {
256
+ is_tty: io_context.stdout.isTTY === true,
257
+ no_color: process.env.NO_COLOR !== undefined,
258
+ term: process.env.TERM,
259
+ });
260
+ const discovery_result = await discoverFields(process.cwd());
261
+
262
+ io_context.stdout.write(renderFieldDiscovery(discovery_result, output_mode));
263
+
264
+ return 0;
265
+ }
266
+
267
+ /**
268
+ * @param {ParsedCliCommandRequest} parsed_command
269
+ * @param {{ stderr: { write(chunk: string): boolean }, stdout: { isTTY?: boolean, write(chunk: string): boolean } }} io_context
270
+ * @param {import('./output-view.types.ts').ResolvedOutputMode} output_mode
271
+ * @param {boolean} use_pager
272
+ * @returns {Promise<number>}
273
+ */
274
+ async function runQueryInspectionCommand(
275
+ parsed_command,
276
+ io_context,
277
+ output_mode,
278
+ use_pager,
279
+ ) {
280
+ const query_inspection_mode = parsed_command.query_inspection_mode;
281
+
282
+ if (!query_inspection_mode) {
283
+ throw new Error('Expected a query inspection mode.');
284
+ }
285
+
286
+ const load_result = await loadPatramConfig(process.cwd());
287
+
288
+ if (load_result.diagnostics.length > 0) {
289
+ io_context.stderr.write(
290
+ renderCheckDiagnostics(load_result.diagnostics, output_mode),
291
+ );
292
+
293
+ return 1;
294
+ }
295
+
296
+ const repo_config = load_result.config;
297
+
298
+ if (!repo_config) {
299
+ throw new Error('Expected a valid Patram repo config.');
300
+ }
301
+
302
+ const where_clause = resolveWhereClause(
303
+ repo_config,
304
+ parsed_command.command_arguments,
305
+ );
306
+
307
+ if (!where_clause.success) {
308
+ io_context.stderr.write(`${where_clause.message}\n`);
309
+
310
+ return 1;
311
+ }
312
+
313
+ const query_inspection = inspectQuery(repo_config, where_clause.value, {
314
+ inspection_mode: query_inspection_mode,
315
+ ...createQueryExecutionOptions(parsed_command, use_pager),
316
+ });
317
+
318
+ if (!query_inspection.success) {
319
+ io_context.stderr.write(
320
+ renderCheckDiagnostics(query_inspection.diagnostics, output_mode),
321
+ );
322
+
323
+ return 1;
324
+ }
325
+
326
+ io_context.stdout.write(
327
+ renderQueryInspection(query_inspection.value, output_mode),
195
328
  );
196
329
 
197
330
  return 0;
198
331
  }
199
332
 
200
333
  /**
201
- * @param {ParsedCliArguments} parsed_command
334
+ * @param {ParsedCliCommandRequest} parsed_command
202
335
  * @param {{ stderr: { write(chunk: string): boolean }, stdout: { isTTY?: boolean, write(chunk: string): boolean }, write_paged_output?: (output_text: string) => Promise<void> }} io_context
203
336
  * @returns {Promise<number>}
204
337
  */
@@ -227,7 +360,7 @@ async function runQueriesCommand(parsed_command, io_context) {
227
360
  }
228
361
 
229
362
  /**
230
- * @param {ParsedCliArguments} parsed_command
363
+ * @param {ParsedCliCommandRequest} parsed_command
231
364
  * @param {{ stderr: { write(chunk: string): boolean }, stdout: { isTTY?: boolean, write(chunk: string): boolean }, write_paged_output?: (output_text: string) => Promise<void> }} io_context
232
365
  * @returns {Promise<number>}
233
366
  */
@@ -252,10 +385,19 @@ async function runShowCommand(parsed_command, io_context) {
252
385
  return 1;
253
386
  }
254
387
 
388
+ const derived_summary_evaluator = createDerivedSummaryEvaluator(
389
+ project_graph_result.config,
390
+ project_graph_result.graph,
391
+ );
392
+
255
393
  await writeCommandOutput(
256
394
  io_context,
257
395
  parsed_command,
258
- createShowOutputView(show_output.value),
396
+ createShowOutputView(show_output.value, {
397
+ derived_summary_evaluator,
398
+ graph_nodes: project_graph_result.graph.nodes,
399
+ repo_config: project_graph_result.config,
400
+ }),
259
401
  );
260
402
 
261
403
  return 0;
@@ -272,7 +414,7 @@ function writeDiagnostics(output_stream, diagnostics) {
272
414
  }
273
415
 
274
416
  /**
275
- * @param {ParsedCliArguments} parsed_command
417
+ * @param {ParsedCliCommandRequest} parsed_command
276
418
  * @param {{ total_count: number, nodes: import('./build-graph.types.ts').GraphNode[] }} query_result
277
419
  * @param {boolean} use_pager
278
420
  * @returns {{ hints: string[], limit: number, offset: number, total_count: number }}
@@ -286,7 +428,7 @@ function createQueryOutputOptions(parsed_command, query_result, use_pager) {
286
428
  const offset = parsed_command.query_offset ?? 0;
287
429
 
288
430
  if (query_result.total_count === 0) {
289
- hints.push('Try: patram query --where "kind=task"');
431
+ hints.push('Try: patram query --where "$class=task"');
290
432
  }
291
433
 
292
434
  if (
@@ -309,7 +451,7 @@ function createQueryOutputOptions(parsed_command, query_result, use_pager) {
309
451
  }
310
452
 
311
453
  /**
312
- * @param {ParsedCliArguments} parsed_command
454
+ * @param {ParsedCliCommandRequest} parsed_command
313
455
  * @param {boolean} use_pager
314
456
  * @returns {{ limit?: number, offset: number }}
315
457
  */
@@ -328,6 +470,23 @@ function createQueryPaginationOptions(parsed_command, use_pager) {
328
470
  return pagination_options;
329
471
  }
330
472
 
473
+ /**
474
+ * @param {ParsedCliCommandRequest} parsed_command
475
+ * @param {boolean} use_pager
476
+ * @returns {{ limit: number | null, offset: number }}
477
+ */
478
+ function createQueryExecutionOptions(parsed_command, use_pager) {
479
+ const pagination_options = createQueryPaginationOptions(
480
+ parsed_command,
481
+ use_pager,
482
+ );
483
+
484
+ return {
485
+ limit: pagination_options.limit ?? null,
486
+ offset: pagination_options.offset,
487
+ };
488
+ }
489
+
331
490
  /**
332
491
  * @param {import('./load-patram-config.types.ts').PatramDiagnostic} diagnostic
333
492
  * @returns {string}
@@ -5,13 +5,13 @@
5
5
 
6
6
  import { z } from 'zod';
7
7
 
8
- const KIND_NAME_SCHEMA = z.string().min(1);
8
+ const CLASS_NAME_SCHEMA = z.string().min(1);
9
9
  const RELATION_NAME_SCHEMA = z.string().min(1);
10
10
  const CLAIM_TYPE_SCHEMA = z.string().min(1);
11
11
  const KEY_SOURCE_SCHEMA = z.enum(['path', 'value']);
12
12
  const TARGET_SCHEMA = z.enum(['path', 'value']);
13
13
 
14
- const kind_definition_schema = z
14
+ const class_definition_schema = z
15
15
  .object({
16
16
  builtin: z.boolean().optional(),
17
17
  label: z.string().min(1).optional(),
@@ -21,16 +21,16 @@ const kind_definition_schema = z
21
21
  const relation_definition_schema = z
22
22
  .object({
23
23
  builtin: z.boolean().optional(),
24
- from: z.array(KIND_NAME_SCHEMA).min(1),
25
- to: z.array(KIND_NAME_SCHEMA).min(1),
24
+ from: z.array(CLASS_NAME_SCHEMA).min(1),
25
+ to: z.array(CLASS_NAME_SCHEMA).min(1),
26
26
  })
27
27
  .strict();
28
28
 
29
29
  const mapping_node_schema = z
30
30
  .object({
31
+ class: CLASS_NAME_SCHEMA,
31
32
  field: z.string().min(1),
32
33
  key: KEY_SOURCE_SCHEMA.optional(),
33
- kind: KIND_NAME_SCHEMA,
34
34
  })
35
35
  .strict();
36
36
 
@@ -38,7 +38,7 @@ const mapping_emit_schema = z
38
38
  .object({
39
39
  relation: RELATION_NAME_SCHEMA,
40
40
  target: TARGET_SCHEMA,
41
- target_kind: KIND_NAME_SCHEMA,
41
+ target_class: CLASS_NAME_SCHEMA,
42
42
  })
43
43
  .strict();
44
44
 
@@ -53,7 +53,7 @@ const mapping_definition_schema = z
53
53
  export const patramConfigSchema = z
54
54
  .object({
55
55
  $schema: z.url().optional(),
56
- kinds: z.record(KIND_NAME_SCHEMA, kind_definition_schema),
56
+ classes: z.record(CLASS_NAME_SCHEMA, class_definition_schema),
57
57
  mappings: z.record(CLAIM_TYPE_SCHEMA, mapping_definition_schema),
58
58
  relations: z.record(RELATION_NAME_SCHEMA, relation_definition_schema),
59
59
  })
@@ -90,8 +90,8 @@ function validateMappingDefinition(mapping_definition, refinement_context) {
90
90
  * @param {RefinementCtx} refinement_context
91
91
  */
92
92
  function validatePatramConfigReferences(config_json, refinement_context) {
93
- validateRelationKinds(config_json, refinement_context);
94
- validateMappingKinds(config_json, refinement_context);
93
+ validateRelationClasses(config_json, refinement_context);
94
+ validateMappingClasses(config_json, refinement_context);
95
95
  validateMappingRelations(config_json, refinement_context);
96
96
  }
97
97
 
@@ -99,19 +99,19 @@ function validatePatramConfigReferences(config_json, refinement_context) {
99
99
  * @param {PatramConfig} config_json
100
100
  * @param {RefinementCtx} refinement_context
101
101
  */
102
- function validateRelationKinds(config_json, refinement_context) {
102
+ function validateRelationClasses(config_json, refinement_context) {
103
103
  for (const [relation_name, relation_definition] of Object.entries(
104
104
  config_json.relations,
105
105
  )) {
106
- validateReferencedKinds(
106
+ validateReferencedClasses(
107
107
  relation_definition.from,
108
- config_json.kinds,
108
+ config_json.classes,
109
109
  ['relations', relation_name, 'from'],
110
110
  refinement_context,
111
111
  );
112
- validateReferencedKinds(
112
+ validateReferencedClasses(
113
113
  relation_definition.to,
114
- config_json.kinds,
114
+ config_json.classes,
115
115
  ['relations', relation_name, 'to'],
116
116
  refinement_context,
117
117
  );
@@ -122,24 +122,24 @@ function validateRelationKinds(config_json, refinement_context) {
122
122
  * @param {PatramConfig} config_json
123
123
  * @param {RefinementCtx} refinement_context
124
124
  */
125
- function validateMappingKinds(config_json, refinement_context) {
125
+ function validateMappingClasses(config_json, refinement_context) {
126
126
  for (const [mapping_name, mapping_definition] of Object.entries(
127
127
  config_json.mappings,
128
128
  )) {
129
129
  if (mapping_definition.emit) {
130
- validateReferencedKinds(
131
- [mapping_definition.emit.target_kind],
132
- config_json.kinds,
133
- ['mappings', mapping_name, 'emit', 'target_kind'],
130
+ validateReferencedClasses(
131
+ [mapping_definition.emit.target_class],
132
+ config_json.classes,
133
+ ['mappings', mapping_name, 'emit', 'target_class'],
134
134
  refinement_context,
135
135
  );
136
136
  }
137
137
 
138
138
  if (mapping_definition.node) {
139
- validateReferencedKinds(
140
- [mapping_definition.node.kind],
141
- config_json.kinds,
142
- ['mappings', mapping_name, 'node', 'kind'],
139
+ validateReferencedClasses(
140
+ [mapping_definition.node.class],
141
+ config_json.classes,
142
+ ['mappings', mapping_name, 'node', 'class'],
143
143
  refinement_context,
144
144
  );
145
145
  }
@@ -171,25 +171,25 @@ function validateMappingRelations(config_json, refinement_context) {
171
171
  }
172
172
 
173
173
  /**
174
- * @param {string[]} referenced_kinds
175
- * @param {Record<string, unknown>} known_kinds
174
+ * @param {string[]} referenced_classes
175
+ * @param {Record<string, unknown>} known_classes
176
176
  * @param {(string | number)[]} issue_path
177
177
  * @param {RefinementCtx} refinement_context
178
178
  */
179
- function validateReferencedKinds(
180
- referenced_kinds,
181
- known_kinds,
179
+ function validateReferencedClasses(
180
+ referenced_classes,
181
+ known_classes,
182
182
  issue_path,
183
183
  refinement_context,
184
184
  ) {
185
- for (const referenced_kind of referenced_kinds) {
186
- if (known_kinds[referenced_kind]) {
185
+ for (const referenced_class of referenced_classes) {
186
+ if (known_classes[referenced_class]) {
187
187
  continue;
188
188
  }
189
189
 
190
190
  refinement_context.addIssue({
191
191
  code: 'custom',
192
- message: `Unknown kind "${referenced_kind}".`,
192
+ message: `Unknown class "${referenced_class}".`,
193
193
  path: issue_path,
194
194
  });
195
195
  }
@@ -1,4 +1,4 @@
1
- export interface KindDefinition {
1
+ export interface ClassDefinition {
2
2
  builtin?: boolean;
3
3
  label?: string;
4
4
  }
@@ -10,15 +10,15 @@ export interface RelationDefinition {
10
10
  }
11
11
 
12
12
  export interface MappingNodeDefinition {
13
+ class: string;
13
14
  field: string;
14
15
  key?: 'path' | 'value';
15
- kind: string;
16
16
  }
17
17
 
18
18
  export interface MappingEmitDefinition {
19
19
  relation: string;
20
20
  target: 'path' | 'value';
21
- target_kind: string;
21
+ target_class: string;
22
22
  }
23
23
 
24
24
  export interface MappingDefinition {
@@ -28,7 +28,13 @@ export interface MappingDefinition {
28
28
 
29
29
  export interface PatramConfig {
30
30
  $schema?: string;
31
- kinds: Record<string, KindDefinition>;
31
+ classes: Record<string, ClassDefinition>;
32
+ class_schemas?: Record<string, ClassSchemaConfig>;
33
+ fields?: Record<string, MetadataFieldConfig>;
32
34
  mappings: Record<string, MappingDefinition>;
33
35
  relations: Record<string, RelationDefinition>;
34
36
  }
37
+ import type {
38
+ ClassSchemaConfig,
39
+ MetadataFieldConfig,
40
+ } from './load-patram-config.types.ts';
package/lib/patram.js ADDED
@@ -0,0 +1,6 @@
1
+ export {
2
+ extractTaggedFencedBlocks,
3
+ loadTaggedFencedBlocks,
4
+ selectTaggedBlock,
5
+ selectTaggedBlocks,
6
+ } from './tagged-fenced-blocks.js';