cabloy 5.1.199 → 5.1.200
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/.cabloy-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
5.1.
|
|
1
|
+
5.1.200
|
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -208,6 +208,50 @@ test('local Markdown destinations, fragments and reference links are checked', a
|
|
|
208
208
|
);
|
|
209
209
|
});
|
|
210
210
|
|
|
211
|
+
test('link destinations are not authority references but labels and prose remain audited', async t => {
|
|
212
|
+
const records = {
|
|
213
|
+
...BASELINE,
|
|
214
|
+
'rollout.md':
|
|
215
|
+
'# Rollout\n\n[WBS-MISSING-01](./evidence/WBS-DEMO-10-01-current-source.md) and `ATP-MISSING-01`.\n\n\n\n[WBS-DEMO-10-01][proof]\n\n[proof]: ./evidence/WBS-DEMO-10-01-referenced.md\n',
|
|
216
|
+
'evidence/WBS-DEMO-10-01-current-source.md': '# Current source\n',
|
|
217
|
+
'evidence/WBS-DEMO-10-01-image.md': '# Image\n',
|
|
218
|
+
'evidence/WBS-DEMO-10-01-referenced.md': '# Referenced\n',
|
|
219
|
+
};
|
|
220
|
+
const result = await auditPlanning(await fixture(t, records));
|
|
221
|
+
assert.deepEqual(
|
|
222
|
+
result.diagnostics.map(diagnostic => [
|
|
223
|
+
diagnostic.code,
|
|
224
|
+
diagnostic.file,
|
|
225
|
+
diagnostic.line,
|
|
226
|
+
diagnostic.id,
|
|
227
|
+
]),
|
|
228
|
+
[
|
|
229
|
+
['undefined-reference', 'rollout.md', 3, 'ATP-MISSING-01'],
|
|
230
|
+
['undefined-reference', 'rollout.md', 3, 'WBS-MISSING-01'],
|
|
231
|
+
['undefined-reference', 'rollout.md', 5, 'SRS-MISSING-01'],
|
|
232
|
+
],
|
|
233
|
+
);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
test('destination masking preserves local link and reference diagnostics', async t => {
|
|
237
|
+
const records = {
|
|
238
|
+
...BASELINE,
|
|
239
|
+
'rollout.md':
|
|
240
|
+
'# Rollout\n\n[Missing](./evidence/WBS-DEMO-10-01-missing.md)\n[Bad fragment](./evidence/WBS-DEMO-10-01-existing.md#absent)\n[Good fragment](./evidence/WBS-DEMO-10-01-existing.md#present)\n[Bad encoding](./evidence/WBS-DEMO-10-01-%ZZ.md)\n[Undefined][missing]\n\n[unused]: <./evidence/WBS-DEMO-10-01-unused.md>\n',
|
|
241
|
+
'evidence/WBS-DEMO-10-01-existing.md': '# Present\n',
|
|
242
|
+
};
|
|
243
|
+
const result = await auditPlanning(await fixture(t, records));
|
|
244
|
+
assert.deepEqual(
|
|
245
|
+
result.diagnostics.map(diagnostic => [diagnostic.code, diagnostic.line]),
|
|
246
|
+
[
|
|
247
|
+
['link-target', 3],
|
|
248
|
+
['link-fragment', 4],
|
|
249
|
+
['link-format', 6],
|
|
250
|
+
['link-reference', 7],
|
|
251
|
+
],
|
|
252
|
+
);
|
|
253
|
+
});
|
|
254
|
+
|
|
211
255
|
test('exact range endpoints do not masquerade as exact traceability', async t => {
|
|
212
256
|
const records = {
|
|
213
257
|
...BASELINE,
|
|
@@ -142,17 +142,31 @@ function headingIds(markdown) {
|
|
|
142
142
|
return slugs;
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
const LINK_DEFINITION = /^(\s*\[([^\]]+)\]:\s*)(<[^>]+>|\S+)/;
|
|
146
|
+
const INLINE_LINK = /(!?\[[^\]]*\]\(\s*)(<[^>]+>|[^\s)]+)((?:\s+["'][^\n]*["'])?\s*\))/g;
|
|
147
|
+
|
|
148
|
+
function referenceText(text) {
|
|
149
|
+
return text
|
|
150
|
+
.replace(
|
|
151
|
+
LINK_DEFINITION,
|
|
152
|
+
(_, start, _label, destination) => `${start}${' '.repeat(destination.length)}`,
|
|
153
|
+
)
|
|
154
|
+
.replace(
|
|
155
|
+
INLINE_LINK,
|
|
156
|
+
(_, start, destination, end) => `${start}${' '.repeat(destination.length)}${end}`,
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
145
160
|
function markdownLinks(markdown) {
|
|
146
161
|
const lines = markdownLines(markdown);
|
|
147
162
|
const references = new Map();
|
|
148
163
|
const links = [];
|
|
149
164
|
for (const { text, line } of lines) {
|
|
150
|
-
const declaration = text.match(
|
|
165
|
+
const declaration = text.match(LINK_DEFINITION);
|
|
151
166
|
if (declaration)
|
|
152
|
-
references.set(declaration[
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
links.push({ destination: match[1].replace(/^<|>$/g, ''), line });
|
|
167
|
+
references.set(declaration[2].trim().toLowerCase(), declaration[3].replace(/^<|>$/g, ''));
|
|
168
|
+
for (const match of text.matchAll(INLINE_LINK))
|
|
169
|
+
links.push({ destination: match[2].replace(/^<|>$/g, ''), line });
|
|
156
170
|
const referenced = /!?\[([^\]]+)\]\[([^\]]*)\]/g;
|
|
157
171
|
for (const match of text.matchAll(referenced))
|
|
158
172
|
links.push({ reference: (match[2] || match[1]).trim().toLowerCase(), line });
|
|
@@ -260,7 +274,7 @@ export async function auditPlanning(
|
|
|
260
274
|
for (const [file, markdown] of records) {
|
|
261
275
|
for (const { text, line } of markdownLines(markdown)) {
|
|
262
276
|
for (const prefix of OWNERS.keys()) {
|
|
263
|
-
for (const id of findIdentifiers(text, prefix)) {
|
|
277
|
+
for (const id of findIdentifiers(referenceText(text), prefix)) {
|
|
264
278
|
if (!definitions.has(id)) {
|
|
265
279
|
report(
|
|
266
280
|
'undefined-reference',
|