@erclx/aitk 0.77.0 → 0.77.1
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.
|
@@ -45,7 +45,7 @@ A fence answers that test for itself, because every scan here skips a fenced lin
|
|
|
45
45
|
|
|
46
46
|
The opening delimiter decides that for the whole block rather than each line deciding for itself. A blank line inside an indented fence carries no indentation to read, and a content line may sit at column zero inside one because CommonMark strips the fence's own indent and nothing further. Reading either as unindented ends a run that should have continued, which costs findings rather than inventing them, so no corpus count moves when it is wrong.
|
|
47
47
|
|
|
48
|
-
Two fenced blocks with nothing between them
|
|
48
|
+
Two fenced blocks with nothing between them are one contiguous run of fenced lines, so the mark alone cannot say where the first ends. The line walker reports which block each line sits in, and the boundary re-reads indentation whenever that number changes, so an unindented block written directly behind an indented one ends the run rather than inheriting the answer above it. No markdown file this repository tracks holds that shape, because a formatter inserts a blank line between two fences on contact, and a target running these commands over an unformatted tree still can.
|
|
49
49
|
|
|
50
50
|
Precision is the whole value, so recall is the accepted exposure, and two shapes are knowingly out of reach. A narration written as one bullet carrying its own before and after slips through, and nothing else sees it either. So does the perfect passive, since `has been superseded` narrates a supersession and the copula guard rejects it with the passives it exists for. A rejected alternative is a back-reference in the past tense by construction, and the standard keeps what was tried and why it lost, so a legitimate hit exists and no measure separates it from a violation. The report states that on every run, which is why the finding names a line to read rather than a line to delete. The JSON record carries the findings per entry as `entries[].narration` and the sets as `checkpoints.narration`, which is absent under `--citations-only` where the run never loads them and null where no rule publishes both.
|
|
51
51
|
|
package/package.json
CHANGED
package/src/context/audit.ts
CHANGED
|
@@ -306,7 +306,8 @@ function narration(
|
|
|
306
306
|
|
|
307
307
|
const findings: NarrationFinding[] = []
|
|
308
308
|
let following = false
|
|
309
|
-
let
|
|
309
|
+
let fenceBlock: number | undefined
|
|
310
|
+
let fenceInsideList = false
|
|
310
311
|
|
|
311
312
|
for (const line of lines) {
|
|
312
313
|
// A fenced line is never a bullet, but an unindented block still ends the
|
|
@@ -314,29 +315,25 @@ function narration(
|
|
|
314
315
|
// the bullets around it are two lists and the second has no antecedent
|
|
315
316
|
// above it. A block indented under its bullet stays inside the item.
|
|
316
317
|
//
|
|
317
|
-
// The
|
|
318
|
-
//
|
|
319
|
-
//
|
|
320
|
-
//
|
|
321
|
-
// indent is stripped.
|
|
318
|
+
// The opening delimiter decides for every line of its own block. Reading
|
|
319
|
+
// each line instead ends the run on a blank line inside an indented fence,
|
|
320
|
+
// which has no indentation to read, and on a content line at column zero,
|
|
321
|
+
// which CommonMark permits since only the fence's own indent is stripped.
|
|
322
322
|
//
|
|
323
|
-
//
|
|
324
|
-
//
|
|
325
|
-
//
|
|
326
|
-
//
|
|
327
|
-
//
|
|
328
|
-
// away after its first pair disagreed. That fix belongs in
|
|
329
|
-
// `src/markdown/scan.ts` rather than in a copy of it.
|
|
323
|
+
// The block index is what re-opens that decision, so two blocks written
|
|
324
|
+
// with nothing between them are answered separately rather than the second
|
|
325
|
+
// inheriting the first. Indentation stays the test here because what
|
|
326
|
+
// interrupts a list is this check's own judgment, and the walker only says
|
|
327
|
+
// which lines share a block.
|
|
330
328
|
if (line.fenced) {
|
|
331
|
-
if (
|
|
329
|
+
if (line.fenceBlock !== fenceBlock) {
|
|
330
|
+
fenceBlock = line.fenceBlock
|
|
332
331
|
fenceInsideList = INSIDE_LIST.test(line.text)
|
|
333
332
|
}
|
|
334
333
|
if (!fenceInsideList) following = false
|
|
335
334
|
continue
|
|
336
335
|
}
|
|
337
336
|
|
|
338
|
-
fenceInsideList = undefined
|
|
339
|
-
|
|
340
337
|
if (line.text.trim() === '') continue
|
|
341
338
|
|
|
342
339
|
const bullet = line.text.match(TOP_BULLET)
|
package/src/markdown/scan.ts
CHANGED
|
@@ -39,6 +39,17 @@ export interface BodyLine {
|
|
|
39
39
|
readonly text: string
|
|
40
40
|
/** True on a fence delimiter and on every line between one pair. */
|
|
41
41
|
readonly fenced: boolean
|
|
42
|
+
/**
|
|
43
|
+
* Which fenced block the line sits in, counted from one, and undefined
|
|
44
|
+
* outside one. Two blocks written with nothing between them are one
|
|
45
|
+
* contiguous run of fenced lines, so this is the only field telling them
|
|
46
|
+
* apart. Counting from one keeps the outside answer from reading as a block.
|
|
47
|
+
*
|
|
48
|
+
* The name carries the fence because `block` alone already names a run of
|
|
49
|
+
* `BodyLine` values in `src/markdown/structure.ts`, and one word meaning both
|
|
50
|
+
* an aggregate of lines and an index on each line reads as a bug.
|
|
51
|
+
*/
|
|
52
|
+
readonly fenceBlock: number | undefined
|
|
42
53
|
}
|
|
43
54
|
|
|
44
55
|
export type BanKind = 'character' | 'word' | 'spelling'
|
|
@@ -58,17 +69,25 @@ export interface BanSets {
|
|
|
58
69
|
}
|
|
59
70
|
|
|
60
71
|
/**
|
|
61
|
-
* Marks which lines sit inside a fence without dropping them
|
|
72
|
+
* Marks which lines sit inside a fence without dropping them, and which block
|
|
73
|
+
* each of those lines belongs to.
|
|
62
74
|
*
|
|
63
75
|
* Each measure excludes a fence for its own reason and needs a different
|
|
64
76
|
* response. The depth measure skips a fenced line so an example cannot break
|
|
65
77
|
* the run around it, bullet folding treats one as a break so a bullet does not
|
|
66
78
|
* absorb the block below it, and the ban scan ignores it outright. Returning
|
|
67
79
|
* the mark rather than a filtered list is what lets one walk serve all three.
|
|
80
|
+
*
|
|
81
|
+
* The block index answers the consumer that has to decide per block rather
|
|
82
|
+
* than per contiguous run, since two adjacent blocks are indistinguishable
|
|
83
|
+
* through the mark alone. It is counted here because the walk already holds
|
|
84
|
+
* the opening delimiter, and a consumer parsing its own would be the second
|
|
85
|
+
* fence walker this repository consolidated away.
|
|
68
86
|
*/
|
|
69
87
|
function markFences(texts: readonly string[], offset: number): BodyLine[] {
|
|
70
88
|
const lines: BodyLine[] = []
|
|
71
89
|
let fence: string | undefined
|
|
90
|
+
let fenceBlock = 0
|
|
72
91
|
|
|
73
92
|
for (const [index, text] of texts.entries()) {
|
|
74
93
|
const match = FENCE.exec(text.trim())
|
|
@@ -82,9 +101,15 @@ function markFences(texts: readonly string[], offset: number): BodyLine[] {
|
|
|
82
101
|
} else if (match) {
|
|
83
102
|
fenced = true
|
|
84
103
|
fence = match[1]
|
|
104
|
+
fenceBlock += 1
|
|
85
105
|
}
|
|
86
106
|
|
|
87
|
-
lines.push({
|
|
107
|
+
lines.push({
|
|
108
|
+
number: offset + index + 1,
|
|
109
|
+
text,
|
|
110
|
+
fenced,
|
|
111
|
+
fenceBlock: fenced ? fenceBlock : undefined,
|
|
112
|
+
})
|
|
88
113
|
}
|
|
89
114
|
|
|
90
115
|
return lines
|