patram 0.6.2 → 0.8.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.
- package/lib/build-graph-identity.d.ts +40 -0
- package/lib/build-graph.d.ts +11 -0
- package/lib/build-graph.types.d.ts +24 -0
- package/lib/claim-helpers.d.ts +20 -0
- package/lib/cli-help-metadata.js +48 -9
- package/lib/command-output.js +1 -0
- package/lib/document-node-identity.d.ts +47 -0
- package/lib/inspect-reverse-references.js +184 -0
- package/lib/layout-incoming-references.js +105 -0
- package/lib/layout-incoming-summary-lines.js +21 -0
- package/lib/list-source-files.d.ts +29 -0
- package/lib/load-patram-config.d.ts +384 -0
- package/lib/load-patram-config.types.d.ts +45 -0
- package/lib/load-project-graph.d.ts +35 -0
- package/lib/output-view.types.d.ts +88 -0
- package/lib/output-view.types.ts +19 -2
- package/lib/overlay-graph.d.ts +43 -0
- package/lib/overlay-graph.js +191 -0
- package/lib/parse-claims.d.ts +40 -0
- package/lib/parse-claims.types.d.ts +31 -0
- package/lib/parse-cli-arguments-helpers.js +11 -4
- package/lib/parse-cli-arguments.types.ts +8 -2
- package/lib/parse-jsdoc-blocks.d.ts +15 -0
- package/lib/parse-jsdoc-claims.d.ts +9 -0
- package/lib/parse-jsdoc-prose.d.ts +28 -0
- package/lib/parse-markdown-claims.d.ts +14 -0
- package/lib/parse-markdown-directives.d.ts +34 -0
- package/lib/parse-where-clause.d.ts +75 -0
- package/lib/parse-where-clause.js +157 -37
- package/lib/parse-where-clause.types.d.ts +63 -0
- package/lib/parse-yaml-claims.d.ts +38 -0
- package/lib/patram-cli.js +66 -1
- package/lib/patram-config.d.ts +106 -0
- package/lib/patram-config.types.d.ts +14 -0
- package/lib/patram.d.ts +73 -0
- package/lib/patram.js +3 -0
- package/lib/query-graph.d.ts +68 -0
- package/lib/query-graph.js +27 -24
- package/lib/query-inspection.d.ts +86 -0
- package/lib/render-cli-help.js +1 -1
- package/lib/render-json-output.js +91 -62
- package/lib/render-output-view.js +58 -3
- package/lib/render-plain-output.js +46 -3
- package/lib/render-rich-output.js +50 -5
- package/lib/resolve-patram-graph-config.d.ts +9 -0
- package/lib/reverse-reference-test-helpers.js +76 -0
- package/lib/show-document.js +44 -6
- package/lib/source-file-defaults.d.ts +5 -0
- package/lib/tagged-fenced-block-error.d.ts +10 -0
- package/lib/tagged-fenced-block-markdown.d.ts +47 -0
- package/lib/tagged-fenced-block-metadata.d.ts +26 -0
- package/lib/tagged-fenced-block-parser.d.ts +61 -0
- package/lib/tagged-fenced-blocks.d.ts +39 -0
- package/lib/tagged-fenced-blocks.types.d.ts +32 -0
- package/package.json +13 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @import { OutputNodeItem, OutputResolvedLinkItem, OutputStoredQueryItem, OutputView, QueryOutputView, ShowOutputView } from './output-view.types.ts';
|
|
2
|
+
* @import { OutputNodeItem, OutputResolvedLinkItem, OutputStoredQueryItem, OutputView, QueryOutputView, RefsOutputView, ShowOutputView } from './output-view.types.ts';
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import {
|
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
} from './format-output-metadata.js';
|
|
9
9
|
import { formatNodeHeader } from './format-node-header.js';
|
|
10
10
|
import { formatOutputItemBlock } from './format-output-item-block.js';
|
|
11
|
+
import { layoutIncomingReferenceLines } from './layout-incoming-references.js';
|
|
12
|
+
import { layoutIncomingSummaryLines } from './layout-incoming-summary-lines.js';
|
|
11
13
|
import { layoutStoredQueries } from './layout-stored-queries.js';
|
|
12
14
|
|
|
13
15
|
/**
|
|
@@ -25,6 +27,10 @@ export function renderPlainOutput(output_view) {
|
|
|
25
27
|
return renderPlainStoredQueries(output_view.items);
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
if (output_view.command === 'refs') {
|
|
31
|
+
return renderPlainRefsOutput(output_view);
|
|
32
|
+
}
|
|
33
|
+
|
|
28
34
|
if (output_view.command === 'show') {
|
|
29
35
|
return renderPlainShowOutput(output_view);
|
|
30
36
|
}
|
|
@@ -85,8 +91,13 @@ function renderPlainShowOutput(output_view) {
|
|
|
85
91
|
const document_summary = output_view.document
|
|
86
92
|
? formatPlainNodeItem(output_view.document)
|
|
87
93
|
: '';
|
|
94
|
+
const incoming_summary = renderPlainIncomingSummary(output_view);
|
|
88
95
|
|
|
89
|
-
if (
|
|
96
|
+
if (
|
|
97
|
+
document_summary.length === 0 &&
|
|
98
|
+
output_view.items.length === 0 &&
|
|
99
|
+
incoming_summary.length === 0
|
|
100
|
+
) {
|
|
90
101
|
return `${rendered_source}\n`;
|
|
91
102
|
}
|
|
92
103
|
|
|
@@ -99,7 +110,28 @@ function renderPlainShowOutput(output_view) {
|
|
|
99
110
|
|
|
100
111
|
summary_items.push(...output_view.items.map(formatPlainResolvedLinkItem));
|
|
101
112
|
|
|
102
|
-
|
|
113
|
+
const summary_blocks = summary_items.filter((summary_item) => summary_item);
|
|
114
|
+
|
|
115
|
+
if (incoming_summary.length > 0) {
|
|
116
|
+
summary_blocks.push(incoming_summary);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return `${rendered_source}\n\n----------------\n${summary_blocks.join('\n\n')}\n`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @param {RefsOutputView} output_view
|
|
124
|
+
* @returns {string}
|
|
125
|
+
*/
|
|
126
|
+
function renderPlainRefsOutput(output_view) {
|
|
127
|
+
const node_summary = formatPlainNodeItem(output_view.node);
|
|
128
|
+
const output_lines = layoutIncomingReferenceLines(output_view.incoming);
|
|
129
|
+
|
|
130
|
+
if (output_lines.length === 0) {
|
|
131
|
+
return `${node_summary}\n\nNo incoming references.\n`;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return `${node_summary}\n\n${output_lines.join('\n')}\n`;
|
|
103
135
|
}
|
|
104
136
|
|
|
105
137
|
/**
|
|
@@ -135,6 +167,17 @@ function formatPlainResolvedLinkItem(output_item) {
|
|
|
135
167
|
});
|
|
136
168
|
}
|
|
137
169
|
|
|
170
|
+
/**
|
|
171
|
+
* @param {ShowOutputView} output_view
|
|
172
|
+
* @returns {string}
|
|
173
|
+
*/
|
|
174
|
+
function renderPlainIncomingSummary(output_view) {
|
|
175
|
+
const output_lines = layoutIncomingSummaryLines(output_view.incoming_summary);
|
|
176
|
+
output_lines.push('', `Hint: patram refs ${output_view.path}`);
|
|
177
|
+
|
|
178
|
+
return output_lines.join('\n');
|
|
179
|
+
}
|
|
180
|
+
|
|
138
181
|
/**
|
|
139
182
|
* @param {string} value
|
|
140
183
|
* @returns {string}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @import { CliColorMode } from './parse-cli-arguments.types.ts';
|
|
3
|
-
* @import { OutputNodeItem, OutputResolvedLinkItem, OutputStoredQueryItem, OutputView, QueryOutputView, ShowOutputView } from './output-view.types.ts';
|
|
3
|
+
* @import { OutputNodeItem, OutputResolvedLinkItem, OutputStoredQueryItem, OutputView, QueryOutputView, RefsOutputView, ShowOutputView } from './output-view.types.ts';
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { Ansis } from 'ansis';
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
} from './format-output-metadata.js';
|
|
12
12
|
import { formatNodeHeader } from './format-node-header.js';
|
|
13
13
|
import { formatOutputItemBlock } from './format-output-item-block.js';
|
|
14
|
+
import { layoutIncomingReferenceLines } from './layout-incoming-references.js';
|
|
15
|
+
import { layoutIncomingSummaryLines } from './layout-incoming-summary-lines.js';
|
|
14
16
|
import { layoutStoredQueries } from './layout-stored-queries.js';
|
|
15
17
|
import { renderRichSource } from './render-rich-source.js';
|
|
16
18
|
|
|
@@ -34,6 +36,9 @@ export async function renderRichOutput(output_view, render_options) {
|
|
|
34
36
|
return renderRichStoredQueries(output_view.items, ansi);
|
|
35
37
|
}
|
|
36
38
|
|
|
39
|
+
if (output_view.command === 'refs') {
|
|
40
|
+
return renderRichRefsOutput(output_view, ansi);
|
|
41
|
+
}
|
|
37
42
|
if (output_view.command === 'show') {
|
|
38
43
|
return renderRichShowOutput(output_view, render_options, ansi);
|
|
39
44
|
}
|
|
@@ -105,10 +110,7 @@ async function renderRichShowOutput(output_view, render_options, ansi) {
|
|
|
105
110
|
const document_summary = output_view.document
|
|
106
111
|
? formatRichNodeItem(output_view.document, ansi)
|
|
107
112
|
: '';
|
|
108
|
-
|
|
109
|
-
if (document_summary.length === 0 && output_view.items.length === 0) {
|
|
110
|
-
return `${rendered_source}\n`;
|
|
111
|
-
}
|
|
113
|
+
const incoming_summary = renderRichIncomingSummary(output_view, ansi);
|
|
112
114
|
|
|
113
115
|
/** @type {string[]} */
|
|
114
116
|
const summary_items = [];
|
|
@@ -121,9 +123,34 @@ async function renderRichShowOutput(output_view, render_options, ansi) {
|
|
|
121
123
|
...output_view.items.map((item) => formatRichResolvedLinkItem(item, ansi)),
|
|
122
124
|
);
|
|
123
125
|
|
|
126
|
+
if (incoming_summary.length > 0) {
|
|
127
|
+
summary_items.push(incoming_summary);
|
|
128
|
+
}
|
|
129
|
+
|
|
124
130
|
return `${rendered_source}\n\n${ansi.gray(FULL_WIDTH_DIVIDER)}\n\n${summary_items.join('\n\n')}\n`;
|
|
125
131
|
}
|
|
126
132
|
|
|
133
|
+
/**
|
|
134
|
+
* @param {RefsOutputView} output_view
|
|
135
|
+
* @param {Ansis} ansi
|
|
136
|
+
* @returns {string}
|
|
137
|
+
*/
|
|
138
|
+
function renderRichRefsOutput(output_view, ansi) {
|
|
139
|
+
const node_summary = formatRichNodeItem(output_view.node, ansi);
|
|
140
|
+
const output_lines = layoutIncomingReferenceLines(output_view.incoming, {
|
|
141
|
+
format_node_header(output_item) {
|
|
142
|
+
return ansi.green(formatNodeHeader(output_item));
|
|
143
|
+
},
|
|
144
|
+
format_relation_header(relation_name, relation_count) {
|
|
145
|
+
return `${ansi.bold(relation_name)} ${ansi.gray(`(${relation_count})`)}`;
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
return output_lines.length === 0
|
|
150
|
+
? `${node_summary}\n\n${ansi.yellow('No incoming references.')}\n`
|
|
151
|
+
: `${node_summary}\n\n${output_lines.join('\n')}\n`;
|
|
152
|
+
}
|
|
153
|
+
|
|
127
154
|
/**
|
|
128
155
|
* @param {OutputNodeItem} output_item
|
|
129
156
|
* @param {Ansis} ansi
|
|
@@ -162,6 +189,24 @@ function formatRichResolvedLinkItem(output_item, ansi) {
|
|
|
162
189
|
});
|
|
163
190
|
}
|
|
164
191
|
|
|
192
|
+
/**
|
|
193
|
+
* @param {ShowOutputView} output_view
|
|
194
|
+
* @param {Ansis} ansi
|
|
195
|
+
* @returns {string}
|
|
196
|
+
*/
|
|
197
|
+
function renderRichIncomingSummary(output_view, ansi) {
|
|
198
|
+
const output_lines = layoutIncomingSummaryLines(output_view.incoming_summary);
|
|
199
|
+
output_lines[0] = ansi.bold(output_lines[0]);
|
|
200
|
+
|
|
201
|
+
if (Object.keys(output_view.incoming_summary).length === 0) {
|
|
202
|
+
output_lines[1] = ` ${ansi.gray('none')}`;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
output_lines.push('', ansi.gray(`Hint: patram refs ${output_view.path}`));
|
|
206
|
+
|
|
207
|
+
return output_lines.join('\n');
|
|
208
|
+
}
|
|
209
|
+
|
|
165
210
|
/**
|
|
166
211
|
* @param {boolean} color_enabled
|
|
167
212
|
* @returns {Ansis}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge built-in Patram graph semantics with repo-defined schema.
|
|
3
|
+
*
|
|
4
|
+
* @param {PatramRepoConfig} repo_config
|
|
5
|
+
* @returns {PatramConfig}
|
|
6
|
+
*/
|
|
7
|
+
export function resolvePatramGraphConfig(repo_config: PatramRepoConfig): PatramConfig;
|
|
8
|
+
import type { PatramRepoConfig } from './load-patram-config.types.ts';
|
|
9
|
+
import type { PatramConfig } from './patram-config.types.ts';
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared reverse-reference graph fixtures for tests.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export function createDecisionNode() {
|
|
6
|
+
return {
|
|
7
|
+
$class: 'decision',
|
|
8
|
+
$id: 'decision:query-language',
|
|
9
|
+
$path: 'docs/decisions/query-language.md',
|
|
10
|
+
id: 'decision:query-language',
|
|
11
|
+
path: 'docs/decisions/query-language.md',
|
|
12
|
+
status: 'accepted',
|
|
13
|
+
title: 'Query Language',
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function createReconcileNode() {
|
|
18
|
+
return {
|
|
19
|
+
$class: 'document',
|
|
20
|
+
$id: 'doc:lib/reconcile.js',
|
|
21
|
+
$path: 'lib/reconcile.js',
|
|
22
|
+
id: 'doc:lib/reconcile.js',
|
|
23
|
+
path: 'lib/reconcile.js',
|
|
24
|
+
title: 'Reconciler entrypoint.',
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function createResumeNode() {
|
|
29
|
+
return {
|
|
30
|
+
$class: 'document',
|
|
31
|
+
$id: 'doc:lib/resume.js',
|
|
32
|
+
$path: 'lib/resume.js',
|
|
33
|
+
id: 'doc:lib/resume.js',
|
|
34
|
+
path: 'lib/resume.js',
|
|
35
|
+
title: 'Resume entrypoint.',
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function createTaskNode() {
|
|
40
|
+
return {
|
|
41
|
+
$class: 'task',
|
|
42
|
+
$id: 'task:reverse-reference-inspection',
|
|
43
|
+
$path: 'docs/tasks/v0/reverse-reference-inspection.md',
|
|
44
|
+
id: 'task:reverse-reference-inspection',
|
|
45
|
+
path: 'docs/tasks/v0/reverse-reference-inspection.md',
|
|
46
|
+
status: 'ready',
|
|
47
|
+
title: 'Implement reverse reference inspection',
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @param {string} edge_id
|
|
53
|
+
* @param {string} from_id
|
|
54
|
+
* @param {string} origin_path
|
|
55
|
+
* @param {string} relation_name
|
|
56
|
+
* @param {string} to_id
|
|
57
|
+
*/
|
|
58
|
+
export function createGraphEdge(
|
|
59
|
+
edge_id,
|
|
60
|
+
from_id,
|
|
61
|
+
origin_path,
|
|
62
|
+
relation_name,
|
|
63
|
+
to_id,
|
|
64
|
+
) {
|
|
65
|
+
return {
|
|
66
|
+
from: from_id,
|
|
67
|
+
id: edge_id,
|
|
68
|
+
origin: {
|
|
69
|
+
column: 1,
|
|
70
|
+
line: 1,
|
|
71
|
+
path: origin_path,
|
|
72
|
+
},
|
|
73
|
+
relation: relation_name,
|
|
74
|
+
to: to_id,
|
|
75
|
+
};
|
|
76
|
+
}
|
package/lib/show-document.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable max-lines */
|
|
2
2
|
/**
|
|
3
|
-
* @import { GraphNode } from './build-graph.types.ts';
|
|
3
|
+
* @import { BuildGraphResult, GraphNode } from './build-graph.types.ts';
|
|
4
4
|
* @import { PatramClaim } from './parse-claims.types.ts';
|
|
5
5
|
* @import { PatramDiagnostic } from './load-patram-config.types.ts';
|
|
6
6
|
*/
|
|
@@ -9,6 +9,7 @@ import { readFile } from 'node:fs/promises';
|
|
|
9
9
|
import { posix, relative, resolve } from 'node:path';
|
|
10
10
|
|
|
11
11
|
import { resolveDocumentNodeId } from './build-graph-identity.js';
|
|
12
|
+
import { inspectReverseReferences } from './inspect-reverse-references.js';
|
|
12
13
|
import { parseSourceFile } from './parse-claims.js';
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -30,11 +31,12 @@ import { parseSourceFile } from './parse-claims.js';
|
|
|
30
31
|
/**
|
|
31
32
|
* @param {string} requested_file_path
|
|
32
33
|
* @param {string} project_directory
|
|
33
|
-
* @param {
|
|
34
|
+
* @param {BuildGraphResult} graph
|
|
34
35
|
* @returns {Promise<
|
|
35
36
|
* | {
|
|
36
37
|
* success: true;
|
|
37
38
|
* value: {
|
|
39
|
+
* incoming_summary: Record<string, number>;
|
|
38
40
|
* path: string;
|
|
39
41
|
* rendered_source: string;
|
|
40
42
|
* resolved_links: Array<{
|
|
@@ -93,6 +95,7 @@ export async function loadShowOutput(
|
|
|
93
95
|
source_file_path,
|
|
94
96
|
source_text,
|
|
95
97
|
parse_result.claims,
|
|
98
|
+
graph,
|
|
96
99
|
graph.document_node_ids,
|
|
97
100
|
graph.nodes,
|
|
98
101
|
),
|
|
@@ -103,14 +106,16 @@ export async function loadShowOutput(
|
|
|
103
106
|
* @param {string} source_file_path
|
|
104
107
|
* @param {string} source_text
|
|
105
108
|
* @param {PatramClaim[]} claims
|
|
109
|
+
* @param {BuildGraphResult} graph
|
|
106
110
|
* @param {import('./build-graph.types.ts').BuildGraphResult['document_node_ids']} document_node_ids
|
|
107
111
|
* @param {Record<string, GraphNode>} graph_nodes
|
|
108
|
-
* @returns {{ path: string, rendered_source: string, resolved_links: Array<{ label: string, reference: number, target: { kind?: string, path: string, status?: string, title: string } }>, source: string }}
|
|
112
|
+
* @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 }}
|
|
109
113
|
*/
|
|
110
114
|
function createShowOutput(
|
|
111
115
|
source_file_path,
|
|
112
116
|
source_text,
|
|
113
117
|
claims,
|
|
118
|
+
graph,
|
|
114
119
|
document_node_ids,
|
|
115
120
|
graph_nodes,
|
|
116
121
|
) {
|
|
@@ -125,8 +130,15 @@ function createShowOutput(
|
|
|
125
130
|
graph_nodes,
|
|
126
131
|
),
|
|
127
132
|
);
|
|
133
|
+
const reverse_references = inspectReverseReferences(
|
|
134
|
+
graph,
|
|
135
|
+
source_file_path,
|
|
136
|
+
undefined,
|
|
137
|
+
undefined,
|
|
138
|
+
);
|
|
128
139
|
|
|
129
140
|
return {
|
|
141
|
+
incoming_summary: summarizeIncomingReferences(reverse_references.incoming),
|
|
130
142
|
path: source_file_path,
|
|
131
143
|
rendered_source: renderResolvedSource(
|
|
132
144
|
source_text,
|
|
@@ -269,12 +281,23 @@ function getScalarGraphField(field_value) {
|
|
|
269
281
|
* @returns {{ kind?: string, path: string, status?: string, title: string }}
|
|
270
282
|
*/
|
|
271
283
|
function createResolvedLinkTarget(target_node, target_path, fallback_title) {
|
|
272
|
-
|
|
273
|
-
|
|
284
|
+
/** @type {{ kind?: string, path: string, status?: string, title: string }} */
|
|
285
|
+
const resolved_target = {
|
|
274
286
|
path: getResolvedLinkTargetPath(target_node, target_path),
|
|
275
|
-
status: getScalarGraphField(target_node?.status),
|
|
276
287
|
title: getScalarGraphField(target_node?.title) ?? fallback_title,
|
|
277
288
|
};
|
|
289
|
+
const target_kind = getResolvedLinkTargetKind(target_node);
|
|
290
|
+
const target_status = getScalarGraphField(target_node?.status);
|
|
291
|
+
|
|
292
|
+
if (target_kind) {
|
|
293
|
+
resolved_target.kind = target_kind;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (target_status) {
|
|
297
|
+
resolved_target.status = target_status;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return resolved_target;
|
|
278
301
|
}
|
|
279
302
|
|
|
280
303
|
/**
|
|
@@ -355,6 +378,21 @@ function trimTrailingLineBreaks(value) {
|
|
|
355
378
|
return value.replace(/\n+$/du, '');
|
|
356
379
|
}
|
|
357
380
|
|
|
381
|
+
/**
|
|
382
|
+
* @param {Record<string, GraphNode[]>} incoming
|
|
383
|
+
* @returns {Record<string, number>}
|
|
384
|
+
*/
|
|
385
|
+
function summarizeIncomingReferences(incoming) {
|
|
386
|
+
/** @type {Record<string, number>} */
|
|
387
|
+
const incoming_summary = {};
|
|
388
|
+
|
|
389
|
+
for (const relation_name of Object.keys(incoming)) {
|
|
390
|
+
incoming_summary[relation_name] = incoming[relation_name].length;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return incoming_summary;
|
|
394
|
+
}
|
|
395
|
+
|
|
358
396
|
/**
|
|
359
397
|
* @param {unknown} error
|
|
360
398
|
* @returns {error is NodeJS.ErrnoException}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export const MARKDOWN_SOURCE_FILE_EXTENSIONS: string[];
|
|
2
|
+
export const YAML_SOURCE_FILE_EXTENSIONS: string[];
|
|
3
|
+
export const JSDOC_SOURCE_FILE_EXTENSIONS: string[];
|
|
4
|
+
export const SUPPORTED_SOURCE_FILE_EXTENSIONS: string[];
|
|
5
|
+
export const DEFAULT_INCLUDE_PATTERNS: string[];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import { TaggedFencedBlockError } from './tagged-fenced-blocks.types.ts';
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* @param {string} code
|
|
6
|
+
* @param {string} message
|
|
7
|
+
* @returns {TaggedFencedBlockError}
|
|
8
|
+
*/
|
|
9
|
+
export function createTaggedFencedBlockError(code: string, message: string): TaggedFencedBlockError;
|
|
10
|
+
import type { TaggedFencedBlockError } from './tagged-fenced-blocks.types.ts';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {string[]} lines
|
|
3
|
+
* @returns {number}
|
|
4
|
+
*/
|
|
5
|
+
export function findMarkdownBodyStartLineIndex(lines: string[]): number;
|
|
6
|
+
/**
|
|
7
|
+
* @param {string[]} lines
|
|
8
|
+
* @param {number} body_start
|
|
9
|
+
* @returns {string}
|
|
10
|
+
*/
|
|
11
|
+
export function getMarkdownTitle(lines: string[], body_start: number): string;
|
|
12
|
+
/**
|
|
13
|
+
* @param {string} line
|
|
14
|
+
* @returns {{ level: number, text: string } | null}
|
|
15
|
+
*/
|
|
16
|
+
export function parseHeading(line: string): {
|
|
17
|
+
level: number;
|
|
18
|
+
text: string;
|
|
19
|
+
} | null;
|
|
20
|
+
/**
|
|
21
|
+
* @param {string[]} heading_path
|
|
22
|
+
* @param {string} title
|
|
23
|
+
* @param {{ level: number, text: string }} heading
|
|
24
|
+
* @returns {string[]}
|
|
25
|
+
*/
|
|
26
|
+
export function updateHeadingPath(heading_path: string[], title: string, heading: {
|
|
27
|
+
level: number;
|
|
28
|
+
text: string;
|
|
29
|
+
}): string[];
|
|
30
|
+
/**
|
|
31
|
+
* @param {string} line
|
|
32
|
+
* @returns {{ character: string, lang: string, length: number } | null}
|
|
33
|
+
*/
|
|
34
|
+
export function parseOpeningMarkdownFence(line: string): {
|
|
35
|
+
character: string;
|
|
36
|
+
lang: string;
|
|
37
|
+
length: number;
|
|
38
|
+
} | null;
|
|
39
|
+
/**
|
|
40
|
+
* @param {string} line
|
|
41
|
+
* @param {{ character: string, length: number }} open_fence
|
|
42
|
+
* @returns {boolean}
|
|
43
|
+
*/
|
|
44
|
+
export function isClosingMarkdownFence(line: string, open_fence: {
|
|
45
|
+
character: string;
|
|
46
|
+
length: number;
|
|
47
|
+
}): boolean;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {string} file_path
|
|
3
|
+
* @param {{ metadata: Record<string, string>, tag_lines: number[] }} pending_tag_set
|
|
4
|
+
* @param {{ metadata: Record<string, string>, tag_lines: number[] }} next_tag_set
|
|
5
|
+
* @returns {{ metadata: Record<string, string>, tag_lines: number[] }}
|
|
6
|
+
*/
|
|
7
|
+
export function mergePendingTagSets(file_path: string, pending_tag_set: {
|
|
8
|
+
metadata: Record<string, string>;
|
|
9
|
+
tag_lines: number[];
|
|
10
|
+
}, next_tag_set: {
|
|
11
|
+
metadata: Record<string, string>;
|
|
12
|
+
tag_lines: number[];
|
|
13
|
+
}): {
|
|
14
|
+
metadata: Record<string, string>;
|
|
15
|
+
tag_lines: number[];
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* @param {string} file_path
|
|
19
|
+
* @param {string} line
|
|
20
|
+
* @param {number} line_number
|
|
21
|
+
* @returns {{ metadata: Record<string, string>, tag_lines: number[] } | null}
|
|
22
|
+
*/
|
|
23
|
+
export function parseTaggedMetadataLine(file_path: string, line: string, line_number: number): {
|
|
24
|
+
metadata: Record<string, string>;
|
|
25
|
+
tag_lines: number[];
|
|
26
|
+
} | null;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {{ metadata: Record<string, string>, tag_lines: number[] }} PendingTagSet
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {{
|
|
6
|
+
* heading_path: string[];
|
|
7
|
+
* lang: string;
|
|
8
|
+
* line_start: number;
|
|
9
|
+
* metadata: Record<string, string>;
|
|
10
|
+
* tag_lines: number[];
|
|
11
|
+
* value_lines: string[];
|
|
12
|
+
* }} OpenTaggedBlock
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {{ character: string, lang: string, length: number }} OpenFence
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {{
|
|
19
|
+
* blocks: TaggedFencedBlock[];
|
|
20
|
+
* body_start: number;
|
|
21
|
+
* heading_path: string[];
|
|
22
|
+
* open_fence: OpenFence | null;
|
|
23
|
+
* open_tagged_block: OpenTaggedBlock | null;
|
|
24
|
+
* pending_tag_set: PendingTagSet | null;
|
|
25
|
+
* title: string;
|
|
26
|
+
* }} TaggedBlockScannerState
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* @param {TaggedFencedBlocksInput} input
|
|
30
|
+
* @returns {TaggedFencedBlockFile}
|
|
31
|
+
*/
|
|
32
|
+
export function extractTaggedFencedBlocksFromSource(input: TaggedFencedBlocksInput): TaggedFencedBlockFile;
|
|
33
|
+
export type PendingTagSet = {
|
|
34
|
+
metadata: Record<string, string>;
|
|
35
|
+
tag_lines: number[];
|
|
36
|
+
};
|
|
37
|
+
export type OpenTaggedBlock = {
|
|
38
|
+
heading_path: string[];
|
|
39
|
+
lang: string;
|
|
40
|
+
line_start: number;
|
|
41
|
+
metadata: Record<string, string>;
|
|
42
|
+
tag_lines: number[];
|
|
43
|
+
value_lines: string[];
|
|
44
|
+
};
|
|
45
|
+
export type OpenFence = {
|
|
46
|
+
character: string;
|
|
47
|
+
lang: string;
|
|
48
|
+
length: number;
|
|
49
|
+
};
|
|
50
|
+
export type TaggedBlockScannerState = {
|
|
51
|
+
blocks: TaggedFencedBlock[];
|
|
52
|
+
body_start: number;
|
|
53
|
+
heading_path: string[];
|
|
54
|
+
open_fence: OpenFence | null;
|
|
55
|
+
open_tagged_block: OpenTaggedBlock | null;
|
|
56
|
+
pending_tag_set: PendingTagSet | null;
|
|
57
|
+
title: string;
|
|
58
|
+
};
|
|
59
|
+
import type { TaggedFencedBlocksInput } from './tagged-fenced-blocks.types.ts';
|
|
60
|
+
import type { TaggedFencedBlockFile } from './tagged-fenced-blocks.types.ts';
|
|
61
|
+
import type { TaggedFencedBlock } from './tagged-fenced-blocks.types.ts';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tagged fenced block public API.
|
|
3
|
+
*
|
|
4
|
+
* Loads or extracts one markdown file worth of tagged fenced blocks and
|
|
5
|
+
* provides exact-match selection helpers.
|
|
6
|
+
*
|
|
7
|
+
* Kind: parse
|
|
8
|
+
* Status: active
|
|
9
|
+
* Tracked in: ../docs/plans/v0/tagged-fenced-block-extraction.md
|
|
10
|
+
* Decided by: ../docs/decisions/tagged-fenced-block-extraction.md
|
|
11
|
+
* @patram
|
|
12
|
+
* @see {@link ../docs/decisions/tagged-fenced-block-extraction.md}
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* @param {TaggedFencedBlocksInput} input
|
|
16
|
+
* @returns {TaggedFencedBlockFile}
|
|
17
|
+
*/
|
|
18
|
+
export function extractTaggedFencedBlocks(input: TaggedFencedBlocksInput): TaggedFencedBlockFile;
|
|
19
|
+
/**
|
|
20
|
+
* @param {string} file_path
|
|
21
|
+
* @returns {Promise<TaggedFencedBlockFile>}
|
|
22
|
+
*/
|
|
23
|
+
export function loadTaggedFencedBlocks(file_path: string): Promise<TaggedFencedBlockFile>;
|
|
24
|
+
/**
|
|
25
|
+
* @param {TaggedFencedBlock[]} blocks
|
|
26
|
+
* @param {TaggedFencedBlockCriteria} criteria
|
|
27
|
+
* @returns {TaggedFencedBlock[]}
|
|
28
|
+
*/
|
|
29
|
+
export function selectTaggedBlocks(blocks: TaggedFencedBlock[], criteria: TaggedFencedBlockCriteria): TaggedFencedBlock[];
|
|
30
|
+
/**
|
|
31
|
+
* @param {TaggedFencedBlock[]} blocks
|
|
32
|
+
* @param {TaggedFencedBlockCriteria} criteria
|
|
33
|
+
* @returns {TaggedFencedBlock}
|
|
34
|
+
*/
|
|
35
|
+
export function selectTaggedBlock(blocks: TaggedFencedBlock[], criteria: TaggedFencedBlockCriteria): TaggedFencedBlock;
|
|
36
|
+
import type { TaggedFencedBlocksInput } from './tagged-fenced-blocks.types.ts';
|
|
37
|
+
import type { TaggedFencedBlockFile } from './tagged-fenced-blocks.types.ts';
|
|
38
|
+
import type { TaggedFencedBlock } from './tagged-fenced-blocks.types.ts';
|
|
39
|
+
import type { TaggedFencedBlockCriteria } from './tagged-fenced-blocks.types.ts';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface TaggedFencedBlocksInput {
|
|
2
|
+
file_path: string;
|
|
3
|
+
source_text: string;
|
|
4
|
+
}
|
|
5
|
+
export interface TaggedFencedBlockCriteria {
|
|
6
|
+
[key: string]: string;
|
|
7
|
+
}
|
|
8
|
+
export interface TaggedFencedBlockOrigin {
|
|
9
|
+
path: string;
|
|
10
|
+
line_start: number;
|
|
11
|
+
line_end: number;
|
|
12
|
+
tag_lines: number[];
|
|
13
|
+
}
|
|
14
|
+
export interface TaggedFencedBlockContext {
|
|
15
|
+
heading_path: string[];
|
|
16
|
+
}
|
|
17
|
+
export interface TaggedFencedBlock {
|
|
18
|
+
id: string;
|
|
19
|
+
lang: string;
|
|
20
|
+
value: string;
|
|
21
|
+
metadata: Record<string, string>;
|
|
22
|
+
origin: TaggedFencedBlockOrigin;
|
|
23
|
+
context: TaggedFencedBlockContext;
|
|
24
|
+
}
|
|
25
|
+
export interface TaggedFencedBlockFile {
|
|
26
|
+
path: string;
|
|
27
|
+
title: string;
|
|
28
|
+
blocks: TaggedFencedBlock[];
|
|
29
|
+
}
|
|
30
|
+
export interface TaggedFencedBlockError extends Error {
|
|
31
|
+
code: string;
|
|
32
|
+
}
|
package/package.json
CHANGED
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "patram",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./lib/patram.js",
|
|
6
|
+
"types": "./lib/patram.d.ts",
|
|
6
7
|
"exports": {
|
|
7
|
-
".":
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./lib/patram.d.ts",
|
|
10
|
+
"default": "./lib/patram.js"
|
|
11
|
+
},
|
|
8
12
|
"./bin/patram.js": "./bin/patram.js"
|
|
9
13
|
},
|
|
10
14
|
"files": [
|
|
11
15
|
"bin/patram.js",
|
|
16
|
+
"lib/**/*.d.ts",
|
|
12
17
|
"lib/**/*.js",
|
|
13
18
|
"lib/**/*.ts",
|
|
19
|
+
"!bin/**/*.test.d.ts",
|
|
20
|
+
"!bin/**/*.test-helpers.d.ts",
|
|
14
21
|
"!bin/**/*.test.js",
|
|
15
22
|
"!bin/**/*.test-helpers.js",
|
|
23
|
+
"!lib/**/*.test.d.ts",
|
|
24
|
+
"!lib/**/*.test-helpers.d.ts",
|
|
16
25
|
"!lib/**/*.test.js",
|
|
17
26
|
"!lib/**/*.test-helpers.js"
|
|
18
27
|
],
|
|
@@ -37,6 +46,8 @@
|
|
|
37
46
|
"check:staged": "lint-staged",
|
|
38
47
|
"check:types": "tsc",
|
|
39
48
|
"postversion": "git push && git push --tags",
|
|
49
|
+
"postpack": "node scripts/clean-package-api-declarations.js",
|
|
50
|
+
"prepack": "node scripts/build-package-api-declarations.js",
|
|
40
51
|
"preversion": "npm run all",
|
|
41
52
|
"prepare": "husky",
|
|
42
53
|
"test": "vitest run",
|