patram 0.0.2 → 0.2.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/bin/patram.js +25 -147
- package/lib/build-graph-identity.js +270 -0
- package/lib/build-graph.js +156 -77
- package/lib/check-graph.js +23 -7
- package/lib/claim-helpers.js +55 -0
- package/lib/cli-help-metadata.js +552 -0
- package/lib/command-output.js +83 -0
- package/lib/derived-summary.js +278 -0
- package/lib/format-derived-summary-row.js +9 -0
- package/lib/format-node-header.js +19 -0
- package/lib/format-output-item-block.js +22 -0
- package/lib/format-output-metadata.js +62 -0
- package/lib/layout-stored-queries.js +361 -0
- package/lib/list-queries.js +18 -0
- package/lib/list-source-files.js +50 -15
- package/lib/load-patram-config.js +505 -18
- package/lib/load-patram-config.types.ts +40 -0
- package/lib/load-project-graph.js +124 -0
- package/lib/output-view.types.ts +88 -0
- package/lib/parse-claims.js +38 -158
- package/lib/parse-claims.types.ts +7 -0
- package/lib/parse-cli-arguments-helpers.js +446 -0
- package/lib/parse-cli-arguments.js +266 -0
- package/lib/parse-cli-arguments.types.ts +69 -0
- package/lib/parse-cli-color-options.js +44 -0
- package/lib/parse-cli-query-pagination.js +49 -0
- package/lib/parse-jsdoc-blocks.js +184 -0
- package/lib/parse-jsdoc-claims.js +280 -0
- package/lib/parse-jsdoc-prose.js +111 -0
- package/lib/parse-markdown-claims.js +242 -0
- package/lib/parse-markdown-directives.js +136 -0
- package/lib/parse-where-clause.js +707 -0
- package/lib/parse-where-clause.types.ts +70 -0
- package/lib/patram-cli.js +464 -0
- package/lib/patram-config.js +3 -1
- package/lib/patram-config.types.ts +2 -1
- package/lib/patram.js +6 -0
- package/lib/query-graph.js +368 -0
- package/lib/query-inspection.js +523 -0
- package/lib/render-check-output.js +315 -0
- package/lib/render-cli-help.js +419 -0
- package/lib/render-json-output.js +161 -0
- package/lib/render-output-view.js +222 -0
- package/lib/render-plain-output.js +182 -0
- package/lib/render-rich-output.js +240 -0
- package/lib/render-rich-source.js +1333 -0
- package/lib/resolve-check-target.js +190 -0
- package/lib/resolve-output-mode.js +60 -0
- package/lib/resolve-patram-graph-config.js +88 -0
- package/lib/resolve-where-clause.js +66 -0
- package/lib/show-document.js +311 -0
- package/lib/source-file-defaults.js +28 -0
- package/lib/tagged-fenced-block-error.js +17 -0
- package/lib/tagged-fenced-block-markdown.js +111 -0
- package/lib/tagged-fenced-block-metadata.js +97 -0
- package/lib/tagged-fenced-block-parser.js +292 -0
- package/lib/tagged-fenced-blocks.js +100 -0
- package/lib/tagged-fenced-blocks.types.ts +38 -0
- package/lib/write-paged-output.js +87 -0
- package/package.json +28 -12
- package/bin/patram.test.js +0 -184
- package/lib/build-graph.test.js +0 -141
- package/lib/check-graph.test.js +0 -103
- package/lib/list-source-files.test.js +0 -101
- package/lib/load-patram-config.test.js +0 -211
- package/lib/parse-claims.test.js +0 -113
- package/lib/patram-config.test.js +0 -147
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import { PatramClaimFields } from './parse-claims.types.ts';
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const JSDOC_SENTENCE_PATTERN = /^(.+?[.!?])(?:\s+|$)([\s\S]*)$/du;
|
|
6
|
+
const JSDOC_TITLE_LENGTH_LIMIT = 120;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {Array<Array<{ column: number, content: string, line: number }>>} prose_paragraphs
|
|
10
|
+
* @param {Array<{ column: number, content: string, line: number }>} paragraph_lines
|
|
11
|
+
*/
|
|
12
|
+
export function pushJsdocParagraph(prose_paragraphs, paragraph_lines) {
|
|
13
|
+
if (paragraph_lines.length > 0) {
|
|
14
|
+
prose_paragraphs.push(paragraph_lines);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {string} file_path
|
|
20
|
+
* @param {Array<Array<{ column: number, content: string, line: number }>>} prose_paragraphs
|
|
21
|
+
* @returns {Array<{ claim_fields: PatramClaimFields, claim_type: string, order: number }>}
|
|
22
|
+
*/
|
|
23
|
+
export function createJsdocProseClaimEntries(file_path, prose_paragraphs) {
|
|
24
|
+
if (prose_paragraphs.length === 0) {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const first_paragraph = prose_paragraphs[0];
|
|
29
|
+
const first_origin = {
|
|
30
|
+
column: first_paragraph[0].column,
|
|
31
|
+
line: first_paragraph[0].line,
|
|
32
|
+
path: file_path,
|
|
33
|
+
};
|
|
34
|
+
const title_result = splitJsdocParagraphTitle(
|
|
35
|
+
first_paragraph.map((line) => line.content).join(' '),
|
|
36
|
+
);
|
|
37
|
+
/** @type {Array<{ claim_fields: PatramClaimFields, claim_type: string, order: number }>} */
|
|
38
|
+
const claim_entries = [
|
|
39
|
+
{
|
|
40
|
+
claim_fields: {
|
|
41
|
+
origin: first_origin,
|
|
42
|
+
value: title_result.title,
|
|
43
|
+
},
|
|
44
|
+
claim_type: 'document.title',
|
|
45
|
+
order: 0,
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
/** @type {string[]} */
|
|
49
|
+
const description_parts = [];
|
|
50
|
+
/** @type {{ column: number, line: number, path: string } | null} */
|
|
51
|
+
let description_origin = null;
|
|
52
|
+
|
|
53
|
+
if (title_result.remainder.length > 0) {
|
|
54
|
+
description_parts.push(title_result.remainder);
|
|
55
|
+
description_origin = first_origin;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for (const paragraph_lines of prose_paragraphs.slice(1)) {
|
|
59
|
+
if (description_origin === null) {
|
|
60
|
+
description_origin = {
|
|
61
|
+
column: paragraph_lines[0].column,
|
|
62
|
+
line: paragraph_lines[0].line,
|
|
63
|
+
path: file_path,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
description_parts.push(
|
|
68
|
+
paragraph_lines.map((line) => line.content).join(' '),
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (description_origin && description_parts.length > 0) {
|
|
73
|
+
claim_entries.push({
|
|
74
|
+
claim_fields: {
|
|
75
|
+
origin: description_origin,
|
|
76
|
+
value: description_parts.join('\n\n'),
|
|
77
|
+
},
|
|
78
|
+
claim_type: 'document.description',
|
|
79
|
+
order: 1,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return claim_entries;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @param {string} paragraph_text
|
|
88
|
+
* @returns {{ remainder: string, title: string }}
|
|
89
|
+
*/
|
|
90
|
+
function splitJsdocParagraphTitle(paragraph_text) {
|
|
91
|
+
if (paragraph_text.length <= JSDOC_TITLE_LENGTH_LIMIT) {
|
|
92
|
+
return {
|
|
93
|
+
remainder: '',
|
|
94
|
+
title: paragraph_text,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const sentence_match = paragraph_text.match(JSDOC_SENTENCE_PATTERN);
|
|
99
|
+
|
|
100
|
+
if (!sentence_match) {
|
|
101
|
+
return {
|
|
102
|
+
remainder: '',
|
|
103
|
+
title: paragraph_text,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
remainder: sentence_match[2].trim(),
|
|
109
|
+
title: sentence_match[1].trim(),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import { PatramClaim, ParseClaimsInput, PatramClaimFields } from './parse-claims.types.ts';
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createClaim, isPathLikeTarget } from './claim-helpers.js';
|
|
6
|
+
import {
|
|
7
|
+
matchHiddenDirectiveFields,
|
|
8
|
+
matchVisibleDirectiveFields,
|
|
9
|
+
parseFrontMatterDirectiveFields,
|
|
10
|
+
} from './parse-markdown-directives.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Markdown claim parsing.
|
|
14
|
+
*
|
|
15
|
+
* Extracts document titles, directives, and links from markdown source while
|
|
16
|
+
* ignoring fenced-code link noise.
|
|
17
|
+
*
|
|
18
|
+
* Kind: parse
|
|
19
|
+
* Status: active
|
|
20
|
+
* Tracked in: ../docs/plans/v0/source-anchor-dogfooding.md
|
|
21
|
+
* Decided by: ../docs/decisions/markdown-metadata-directive-syntax.md
|
|
22
|
+
* Decided by: ../docs/decisions/markdown-link-claim-scope.md
|
|
23
|
+
* @patram
|
|
24
|
+
* @see {@link ./parse-claims.js}
|
|
25
|
+
* @see {@link ../docs/decisions/markdown-metadata-directive-syntax.md}
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
const HEADING_PATTERN = /^#\s+(.+)$/du;
|
|
29
|
+
const MARKDOWN_FENCE_PATTERN = /^([`~]{3,})/du;
|
|
30
|
+
const MARKDOWN_LINK_PATTERN = /\[([^\]]+)\]\(([^)]+)\)/dgu;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {ParseClaimsInput} parse_input
|
|
34
|
+
* @returns {PatramClaim[]}
|
|
35
|
+
*/
|
|
36
|
+
export function parseMarkdownClaims(parse_input) {
|
|
37
|
+
const lines = parse_input.source.split('\n');
|
|
38
|
+
|
|
39
|
+
/** @type {PatramClaim[]} */
|
|
40
|
+
const claims = [];
|
|
41
|
+
const front_matter_result = parseFrontMatterDirectiveFields(
|
|
42
|
+
parse_input.path,
|
|
43
|
+
lines,
|
|
44
|
+
);
|
|
45
|
+
/** @type {{ character: string, length: number } | null} */
|
|
46
|
+
let open_fence = null;
|
|
47
|
+
const title_result = getMarkdownTitle(lines, front_matter_result.body_start);
|
|
48
|
+
|
|
49
|
+
if (title_result) {
|
|
50
|
+
claims.push(
|
|
51
|
+
createClaim(parse_input.path, claims.length + 1, 'document.title', {
|
|
52
|
+
origin: {
|
|
53
|
+
column: 1,
|
|
54
|
+
line: title_result.line,
|
|
55
|
+
path: parse_input.path,
|
|
56
|
+
},
|
|
57
|
+
value: title_result.value,
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
for (const directive_fields of front_matter_result.directive_fields) {
|
|
63
|
+
claims.push(
|
|
64
|
+
createClaim(parse_input.path, claims.length + 1, 'directive', {
|
|
65
|
+
...directive_fields,
|
|
66
|
+
}),
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
for (const [line_index, line] of lines.entries()) {
|
|
71
|
+
if (line_index < front_matter_result.body_start) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const line_number = line_index + 1;
|
|
76
|
+
|
|
77
|
+
if (open_fence) {
|
|
78
|
+
if (isClosingMarkdownFence(line, open_fence)) {
|
|
79
|
+
open_fence = null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
open_fence = parseOpeningMarkdownFence(line);
|
|
86
|
+
|
|
87
|
+
if (open_fence) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
collectMarkdownLinkClaims(parse_input.path, line, line_number, claims);
|
|
92
|
+
collectVisibleDirectiveClaims(parse_input.path, line, line_number, claims);
|
|
93
|
+
collectHiddenDirectiveClaims(parse_input.path, line, line_number, claims);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return claims;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @param {string} file_path
|
|
101
|
+
* @param {string} line
|
|
102
|
+
* @param {number} line_number
|
|
103
|
+
* @param {PatramClaim[]} claims
|
|
104
|
+
*/
|
|
105
|
+
function collectMarkdownLinkClaims(file_path, line, line_number, claims) {
|
|
106
|
+
for (const link_match of line.matchAll(MARKDOWN_LINK_PATTERN)) {
|
|
107
|
+
const link_text = link_match[1];
|
|
108
|
+
const target_value = link_match[2];
|
|
109
|
+
|
|
110
|
+
if (!isPathLikeTarget(target_value)) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const column_number =
|
|
115
|
+
link_match.index === undefined ? 1 : link_match.index + 1;
|
|
116
|
+
|
|
117
|
+
claims.push(
|
|
118
|
+
createClaim(file_path, claims.length + 1, 'markdown.link', {
|
|
119
|
+
origin: {
|
|
120
|
+
column: column_number,
|
|
121
|
+
line: line_number,
|
|
122
|
+
path: file_path,
|
|
123
|
+
},
|
|
124
|
+
value: {
|
|
125
|
+
target: target_value,
|
|
126
|
+
text: link_text,
|
|
127
|
+
},
|
|
128
|
+
}),
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @param {string} file_path
|
|
135
|
+
* @param {string} line
|
|
136
|
+
* @param {number} line_number
|
|
137
|
+
* @param {PatramClaim[]} claims
|
|
138
|
+
*/
|
|
139
|
+
function collectVisibleDirectiveClaims(file_path, line, line_number, claims) {
|
|
140
|
+
const directive_fields = matchVisibleDirectiveFields(
|
|
141
|
+
file_path,
|
|
142
|
+
line,
|
|
143
|
+
line_number,
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
if (directive_fields) {
|
|
147
|
+
pushDirectiveClaim(file_path, claims, directive_fields);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* @param {string} file_path
|
|
153
|
+
* @param {string} line
|
|
154
|
+
* @param {number} line_number
|
|
155
|
+
* @param {PatramClaim[]} claims
|
|
156
|
+
*/
|
|
157
|
+
function collectHiddenDirectiveClaims(file_path, line, line_number, claims) {
|
|
158
|
+
const directive_fields = matchHiddenDirectiveFields(
|
|
159
|
+
file_path,
|
|
160
|
+
line,
|
|
161
|
+
line_number,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
if (directive_fields) {
|
|
165
|
+
pushDirectiveClaim(file_path, claims, directive_fields);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* @param {string[]} lines
|
|
171
|
+
* @param {number} start_line_index
|
|
172
|
+
* @returns {{ line: number, value: string } | null}
|
|
173
|
+
*/
|
|
174
|
+
function getMarkdownTitle(lines, start_line_index) {
|
|
175
|
+
const first_line = lines[start_line_index];
|
|
176
|
+
|
|
177
|
+
if (first_line === undefined) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const trimmed_line = first_line.trim();
|
|
182
|
+
|
|
183
|
+
if (trimmed_line.length === 0) {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const heading_match = trimmed_line.match(HEADING_PATTERN);
|
|
188
|
+
|
|
189
|
+
if (heading_match) {
|
|
190
|
+
return {
|
|
191
|
+
line: start_line_index + 1,
|
|
192
|
+
value: heading_match[1].trim(),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
line: start_line_index + 1,
|
|
198
|
+
value: trimmed_line,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* @param {string} line
|
|
204
|
+
* @returns {{ character: string, length: number } | null}
|
|
205
|
+
*/
|
|
206
|
+
function parseOpeningMarkdownFence(line) {
|
|
207
|
+
const trimmed_line = line.trimStart();
|
|
208
|
+
const fence_match = trimmed_line.match(MARKDOWN_FENCE_PATTERN);
|
|
209
|
+
|
|
210
|
+
if (!fence_match) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
character: fence_match[1][0],
|
|
216
|
+
length: fence_match[1].length,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* @param {string} line
|
|
222
|
+
* @param {{ character: string, length: number }} open_fence
|
|
223
|
+
* @returns {boolean}
|
|
224
|
+
*/
|
|
225
|
+
function isClosingMarkdownFence(line, open_fence) {
|
|
226
|
+
const trimmed_line = line.trimStart();
|
|
227
|
+
|
|
228
|
+
return trimmed_line.startsWith(
|
|
229
|
+
open_fence.character.repeat(open_fence.length),
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* @param {string} file_path
|
|
235
|
+
* @param {PatramClaim[]} claims
|
|
236
|
+
* @param {PatramClaimFields} directive_fields
|
|
237
|
+
*/
|
|
238
|
+
function pushDirectiveClaim(file_path, claims, directive_fields) {
|
|
239
|
+
claims.push(
|
|
240
|
+
createClaim(file_path, claims.length + 1, 'directive', directive_fields),
|
|
241
|
+
);
|
|
242
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import { PatramClaimFields } from './parse-claims.types.ts';
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const FRONT_MATTER_BOUNDARY_PATTERN = /^---$/du;
|
|
6
|
+
const FRONT_MATTER_DIRECTIVE_PATTERN = /^([A-Za-z][A-Za-z0-9 _-]*):\s+(.+)$/du;
|
|
7
|
+
const MARKDOWN_HIDDEN_DIRECTIVE_PATTERN =
|
|
8
|
+
/^\[patram\s+([A-Za-z][A-Za-z0-9 _-]*)=(.+)\]:\s*#\s*$/du;
|
|
9
|
+
const VISIBLE_DIRECTIVE_PATTERN = /^(?:-\s+)?([A-Z][A-Za-z _-]*):\s+(.+)$/du;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} file_path
|
|
13
|
+
* @param {string[]} lines
|
|
14
|
+
* @returns {{ body_start: number, directive_fields: PatramClaimFields[] }}
|
|
15
|
+
*/
|
|
16
|
+
export function parseFrontMatterDirectiveFields(file_path, lines) {
|
|
17
|
+
if (lines[0] !== '---') {
|
|
18
|
+
return {
|
|
19
|
+
body_start: 0,
|
|
20
|
+
directive_fields: [],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const closing_line_index = findFrontMatterClosingLineIndex(lines);
|
|
25
|
+
|
|
26
|
+
if (closing_line_index < 0) {
|
|
27
|
+
return {
|
|
28
|
+
body_start: 0,
|
|
29
|
+
directive_fields: [],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** @type {PatramClaimFields[]} */
|
|
34
|
+
const directive_fields = [];
|
|
35
|
+
|
|
36
|
+
for (let line_index = 1; line_index < closing_line_index; line_index += 1) {
|
|
37
|
+
const directive_fields_match = matchDirectiveFields(
|
|
38
|
+
FRONT_MATTER_DIRECTIVE_PATTERN,
|
|
39
|
+
file_path,
|
|
40
|
+
lines[line_index],
|
|
41
|
+
line_index + 1,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
if (!directive_fields_match) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
directive_fields.push(directive_fields_match);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
body_start: closing_line_index + 1,
|
|
53
|
+
directive_fields,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @param {string} file_path
|
|
59
|
+
* @param {string} line
|
|
60
|
+
* @param {number} line_number
|
|
61
|
+
* @returns {PatramClaimFields | null}
|
|
62
|
+
*/
|
|
63
|
+
export function matchVisibleDirectiveFields(file_path, line, line_number) {
|
|
64
|
+
return matchDirectiveFields(
|
|
65
|
+
VISIBLE_DIRECTIVE_PATTERN,
|
|
66
|
+
file_path,
|
|
67
|
+
line,
|
|
68
|
+
line_number,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @param {string} file_path
|
|
74
|
+
* @param {string} line
|
|
75
|
+
* @param {number} line_number
|
|
76
|
+
* @returns {PatramClaimFields | null}
|
|
77
|
+
*/
|
|
78
|
+
export function matchHiddenDirectiveFields(file_path, line, line_number) {
|
|
79
|
+
return matchDirectiveFields(
|
|
80
|
+
MARKDOWN_HIDDEN_DIRECTIVE_PATTERN,
|
|
81
|
+
file_path,
|
|
82
|
+
line,
|
|
83
|
+
line_number,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @param {string[]} lines
|
|
89
|
+
* @returns {number}
|
|
90
|
+
*/
|
|
91
|
+
function findFrontMatterClosingLineIndex(lines) {
|
|
92
|
+
for (let line_index = 1; line_index < lines.length; line_index += 1) {
|
|
93
|
+
if (FRONT_MATTER_BOUNDARY_PATTERN.test(lines[line_index])) {
|
|
94
|
+
return line_index;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return -1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @param {RegExp} pattern
|
|
103
|
+
* @param {string} file_path
|
|
104
|
+
* @param {string} line
|
|
105
|
+
* @param {number} line_number
|
|
106
|
+
* @returns {PatramClaimFields | null}
|
|
107
|
+
*/
|
|
108
|
+
function matchDirectiveFields(pattern, file_path, line, line_number) {
|
|
109
|
+
const directive_match = line.match(pattern);
|
|
110
|
+
|
|
111
|
+
if (!directive_match) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
name: normalizeDirectiveName(directive_match[1]),
|
|
117
|
+
origin: {
|
|
118
|
+
column: 1,
|
|
119
|
+
line: line_number,
|
|
120
|
+
path: file_path,
|
|
121
|
+
},
|
|
122
|
+
parser: 'markdown',
|
|
123
|
+
value: directive_match[2].trim(),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @param {string} directive_label
|
|
129
|
+
* @returns {string}
|
|
130
|
+
*/
|
|
131
|
+
export function normalizeDirectiveName(directive_label) {
|
|
132
|
+
return directive_label
|
|
133
|
+
.trim()
|
|
134
|
+
.toLowerCase()
|
|
135
|
+
.replaceAll(/[\s-]+/dgu, '_');
|
|
136
|
+
}
|