parseman 0.46.0 → 0.47.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/README.md +8 -3
- package/dist/analysis/choice-cost-render.d.ts +12 -4
- package/dist/analysis/choice-cost-render.d.ts.map +1 -1
- package/dist/analysis/choice-cost.d.ts +2 -2
- package/dist/analysis/choice-cost.d.ts.map +1 -1
- package/dist/analysis/commitment.d.ts +131 -0
- package/dist/analysis/commitment.d.ts.map +1 -0
- package/dist/analysis/diagnostics.cjs +9929 -7465
- package/dist/analysis/diagnostics.cjs.map +3 -4
- package/dist/analysis/diagnostics.d.ts +2 -2
- package/dist/analysis/diagnostics.js +9929 -7465
- package/dist/analysis/diagnostics.js.map +3 -4
- package/dist/analysis/duplication.d.ts.map +1 -1
- package/dist/analysis/fix.d.ts +3 -3
- package/dist/analysis/fix.d.ts.map +1 -1
- package/dist/analysis/format-number.d.ts +23 -0
- package/dist/analysis/format-number.d.ts.map +1 -0
- package/dist/analysis/gating.d.ts +39 -2
- package/dist/analysis/gating.d.ts.map +1 -1
- package/dist/analysis/rebuild.d.ts.map +1 -1
- package/dist/analysis/terminal.d.ts +5 -2
- package/dist/analysis/terminal.d.ts.map +1 -1
- package/dist/cli/index.cjs +10865 -8535
- package/dist/cli/index.cjs.map +3 -4
- package/dist/cli/index.js +10865 -8535
- package/dist/cli/index.js.map +3 -4
- package/dist/combinators/adjacency.d.ts +100 -0
- package/dist/combinators/adjacency.d.ts.map +1 -0
- package/dist/combinators/choice.d.ts.map +1 -1
- package/dist/combinators/completions.d.ts.map +1 -1
- package/dist/combinators/dispatch.d.ts +8 -1
- package/dist/combinators/dispatch.d.ts.map +1 -1
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/gate.d.ts.map +1 -1
- package/dist/combinators/grammar.d.ts +22 -0
- package/dist/combinators/grammar.d.ts.map +1 -1
- package/dist/combinators/literal.d.ts +8 -0
- package/dist/combinators/literal.d.ts.map +1 -1
- package/dist/combinators/map.d.ts +0 -1
- package/dist/combinators/map.d.ts.map +1 -1
- package/dist/combinators/node.d.ts +13 -3
- package/dist/combinators/node.d.ts.map +1 -1
- package/dist/combinators/parser.d.ts +1 -1
- package/dist/combinators/parser.d.ts.map +1 -1
- package/dist/combinators/ref.d.ts.map +1 -1
- package/dist/combinators/regex.d.ts +1 -16
- package/dist/combinators/regex.d.ts.map +1 -1
- package/dist/combinators/repeat.d.ts +30 -2
- package/dist/combinators/repeat.d.ts.map +1 -1
- package/dist/combinators/scanTo.d.ts +71 -1
- package/dist/combinators/scanTo.d.ts.map +1 -1
- package/dist/combinators/sequence.d.ts.map +1 -1
- package/dist/combinators/token.d.ts.map +1 -1
- package/dist/combinators/trivia-boundary.d.ts +26 -0
- package/dist/combinators/trivia-boundary.d.ts.map +1 -0
- package/dist/combinators/trivia-skip.d.ts +40 -1
- package/dist/combinators/trivia-skip.d.ts.map +1 -1
- package/dist/combinators/withCtx.d.ts.map +1 -1
- package/dist/compiler/compile-linkable-table.d.ts +104 -0
- package/dist/compiler/compile-linkable-table.d.ts.map +1 -0
- package/dist/compiler/degradation.d.ts +0 -2
- package/dist/compiler/degradation.d.ts.map +1 -1
- package/dist/compiler/fields.d.ts +13 -0
- package/dist/compiler/fields.d.ts.map +1 -1
- package/dist/compiler/grammar-coverage-ids.d.ts +5 -5
- package/dist/compiler/grammar-coverage-ids.d.ts.map +1 -1
- package/dist/compiler/ir-serialize.d.ts.map +1 -1
- package/dist/compiler/linker.d.ts +47 -53
- package/dist/compiler/linker.d.ts.map +1 -1
- package/dist/compiler/token-alphabet.d.ts +81 -0
- package/dist/compiler/token-alphabet.d.ts.map +1 -0
- package/dist/compiler/token-dispatch.d.ts +95 -0
- package/dist/compiler/token-dispatch.d.ts.map +1 -0
- package/dist/compiler/token-scanner.d.ts +53 -0
- package/dist/compiler/token-scanner.d.ts.map +1 -0
- package/dist/compiler/value-usage.d.ts.map +1 -1
- package/dist/coverage.d.ts +1 -1
- package/dist/coverage.d.ts.map +1 -1
- package/dist/cst/capture-buffer.d.ts +35 -0
- package/dist/cst/capture-buffer.d.ts.map +1 -1
- package/dist/cst/reflection-attach.d.ts +8 -0
- package/dist/cst/reflection-attach.d.ts.map +1 -0
- package/dist/cst/reflection-symbols.d.ts +10 -0
- package/dist/cst/reflection-symbols.d.ts.map +1 -0
- package/dist/cst/reflection.d.ts +2 -4
- package/dist/cst/reflection.d.ts.map +1 -1
- package/dist/cst/root-trivia-scope.d.ts +26 -0
- package/dist/cst/root-trivia-scope.d.ts.map +1 -0
- package/dist/cst/trivia-charscan.d.ts +18 -0
- package/dist/cst/trivia-charscan.d.ts.map +1 -0
- package/dist/cst/trivia-kinds.d.ts +19 -0
- package/dist/cst/trivia-kinds.d.ts.map +1 -1
- package/dist/functional/doc.d.ts.map +1 -1
- package/dist/functional/run-tabled.d.ts +12 -0
- package/dist/functional/run-tabled.d.ts.map +1 -0
- package/dist/functional/run.d.ts +25 -42
- package/dist/functional/run.d.ts.map +1 -1
- package/dist/grammar-metadata.d.ts +3 -0
- package/dist/grammar-metadata.d.ts.map +1 -0
- package/dist/index.cjs +9224 -7203
- package/dist/index.cjs.map +3 -4
- package/dist/index.d.ts +18 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9219 -7198
- package/dist/index.js.map +3 -4
- package/dist/language-service/index.cjs +311 -121
- package/dist/language-service/index.cjs.map +3 -4
- package/dist/language-service/index.js +311 -121
- package/dist/language-service/index.js.map +3 -4
- package/dist/oracle/index.cjs.map +0 -1
- package/dist/oracle/index.js.map +0 -1
- package/dist/parse-context.d.ts +49 -0
- package/dist/parse-context.d.ts.map +1 -0
- package/dist/plugin/evaluator.d.ts +40 -1
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +11146 -9593
- package/dist/plugin/index.cjs.map +3 -4
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +11146 -9593
- package/dist/plugin/index.js.map +3 -4
- package/dist/regex/classes.d.ts +28 -0
- package/dist/regex/classes.d.ts.map +1 -1
- package/dist/regex/first-set.d.ts +14 -0
- package/dist/regex/first-set.d.ts.map +1 -1
- package/dist/run/index.cjs +136 -51
- package/dist/run/index.cjs.map +2 -3
- package/dist/run/index.js +136 -51
- package/dist/run/index.js.map +2 -3
- package/dist/spec/index.cjs +2898 -1623
- package/dist/spec/index.cjs.map +3 -4
- package/dist/spec/index.js +2898 -1623
- package/dist/spec/index.js.map +3 -4
- package/dist/spec/model.d.ts +8 -0
- package/dist/spec/model.d.ts.map +1 -1
- package/dist/table/assemble.d.ts +307 -0
- package/dist/table/assemble.d.ts.map +1 -0
- package/dist/table/cell.d.ts +42 -0
- package/dist/table/cell.d.ts.map +1 -0
- package/dist/table/child-slots.d.ts +30 -0
- package/dist/table/child-slots.d.ts.map +1 -0
- package/dist/table/compile-rule-map.d.ts +136 -0
- package/dist/table/compile-rule-map.d.ts.map +1 -0
- package/dist/table/compile.d.ts +56 -0
- package/dist/table/compile.d.ts.map +1 -0
- package/dist/table/duplication-hook.d.ts +32 -0
- package/dist/table/duplication-hook.d.ts.map +1 -0
- package/dist/table/emit-assembly.d.ts +139 -0
- package/dist/table/emit-assembly.d.ts.map +1 -0
- package/dist/table/emit.d.ts +113 -0
- package/dist/table/emit.d.ts.map +1 -0
- package/dist/table/encode-baseline.d.ts +16 -0
- package/dist/table/encode-baseline.d.ts.map +1 -0
- package/dist/table/encode.d.ts +71 -0
- package/dist/table/encode.d.ts.map +1 -0
- package/dist/table/exec-baseline.d.ts +9 -0
- package/dist/table/exec-baseline.d.ts.map +1 -0
- package/dist/table/exec.d.ts +72 -0
- package/dist/table/exec.d.ts.map +1 -0
- package/dist/table/fold.d.ts +25 -0
- package/dist/table/fold.d.ts.map +1 -0
- package/dist/table/index.cjs +11375 -0
- package/dist/table/index.cjs.map +6 -0
- package/dist/table/index.d.ts +100 -0
- package/dist/table/index.d.ts.map +1 -0
- package/dist/table/index.js +11352 -0
- package/dist/table/index.js.map +6 -0
- package/dist/table/inspect.d.ts +17 -0
- package/dist/table/inspect.d.ts.map +1 -0
- package/dist/table/ops.d.ts +446 -0
- package/dist/table/ops.d.ts.map +1 -0
- package/dist/table/program.d.ts +493 -0
- package/dist/table/program.d.ts.map +1 -0
- package/dist/table/run-support.d.ts +38 -0
- package/dist/table/run-support.d.ts.map +1 -0
- package/dist/{compiler/scannable-run.d.ts → table/scan-shapes.d.ts} +14 -13
- package/dist/table/scan-shapes.d.ts.map +1 -0
- package/dist/table/site-labels.d.ts +58 -0
- package/dist/table/site-labels.d.ts.map +1 -0
- package/dist/table/stamp.d.ts +70 -0
- package/dist/table/stamp.d.ts.map +1 -0
- package/dist/types.d.ts +80 -24
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +25 -2
- package/src/analysis/choice-cost-gate.ts +359 -0
- package/src/analysis/choice-cost-render.ts +293 -0
- package/src/analysis/choice-cost.ts +1008 -0
- package/src/analysis/commitment.ts +557 -0
- package/src/analysis/corpus.ts +130 -0
- package/src/analysis/diagnose-render.ts +625 -0
- package/src/analysis/diagnose.ts +317 -0
- package/src/analysis/diagnostics.ts +33 -0
- package/src/analysis/duplication.ts +1955 -0
- package/src/analysis/fix-render.ts +217 -0
- package/src/analysis/fix.ts +669 -0
- package/src/analysis/format-number.ts +31 -0
- package/src/analysis/gating.ts +792 -0
- package/src/analysis/grammar.ts +72 -0
- package/src/analysis/rebuild.ts +287 -0
- package/src/analysis/terminal.ts +336 -0
- package/src/cli/index.ts +413 -0
- package/src/combinators/adjacency.ts +171 -0
- package/src/combinators/attempt.ts +41 -0
- package/src/combinators/case-fold.ts +90 -0
- package/src/combinators/choice.ts +466 -0
- package/src/combinators/completions.ts +64 -0
- package/src/combinators/dispatch.ts +358 -0
- package/src/combinators/expect.ts +159 -0
- package/src/combinators/first-set.ts +322 -0
- package/src/combinators/gate.ts +50 -0
- package/src/combinators/grammar.ts +272 -0
- package/src/combinators/keywords.ts +145 -0
- package/src/combinators/literal.ts +102 -0
- package/src/combinators/map.ts +106 -0
- package/src/combinators/node.ts +345 -0
- package/src/combinators/not.ts +55 -0
- package/src/combinators/parser.ts +266 -0
- package/src/combinators/peek.ts +63 -0
- package/src/combinators/probe.ts +25 -0
- package/src/combinators/ref.ts +109 -0
- package/src/combinators/regex.ts +170 -0
- package/src/combinators/repeat.ts +561 -0
- package/src/combinators/scanTo.ts +393 -0
- package/src/combinators/sequence.ts +221 -0
- package/src/combinators/token.ts +120 -0
- package/src/combinators/trivia-boundary.ts +48 -0
- package/src/combinators/trivia-skip.ts +821 -0
- package/src/combinators/withCtx.ts +45 -0
- package/src/compiler/build-arity.ts +330 -0
- package/src/compiler/compile-linkable-table.ts +209 -0
- package/src/compiler/degradation.ts +266 -0
- package/src/compiler/fields.ts +191 -0
- package/src/compiler/grammar-coverage-ids.ts +129 -0
- package/src/compiler/ir-serialize.ts +615 -0
- package/src/compiler/linker.ts +954 -0
- package/src/compiler/token-alphabet.ts +209 -0
- package/src/compiler/token-dispatch.ts +353 -0
- package/src/compiler/token-scanner.ts +318 -0
- package/src/compiler/value-usage.ts +147 -0
- package/src/coverage.ts +383 -0
- package/src/cst/capture-buffer.ts +297 -0
- package/src/cst/host-mode.ts +69 -0
- package/src/cst/reflection-attach.ts +11 -0
- package/src/cst/reflection-symbols.ts +9 -0
- package/src/cst/reflection.ts +149 -0
- package/src/cst/relative-spans.ts +207 -0
- package/src/cst/root-trivia-scope.ts +30 -0
- package/src/cst/trivia-charscan.ts +312 -0
- package/src/cst/trivia-entries.ts +285 -0
- package/src/cst/trivia-index.ts +131 -0
- package/src/cst/trivia-kinds.ts +358 -0
- package/src/cst/types.ts +76 -0
- package/src/cst/walk.ts +101 -0
- package/src/functional/doc.ts +959 -0
- package/src/functional/run-tabled.ts +153 -0
- package/src/functional/run.ts +558 -0
- package/src/grammar-metadata.ts +2 -0
- package/src/index.ts +189 -0
- package/src/language-service/index.ts +221 -0
- package/src/line-index.ts +131 -0
- package/src/oracle/digest.ts +620 -0
- package/src/oracle/index.ts +55 -0
- package/src/parse-context.ts +91 -0
- package/src/plugin/direct-builder-static.ts +102 -0
- package/src/plugin/evaluator.ts +1505 -0
- package/src/plugin/free-identifiers.ts +338 -0
- package/src/plugin/index.ts +2281 -0
- package/src/plugin/reducer-resolver.ts +606 -0
- package/src/recovery/scan.ts +155 -0
- package/src/regex/classes.ts +183 -0
- package/src/regex/first-set.ts +316 -0
- package/src/run/index.ts +31 -0
- package/src/spec/ebnf.ts +128 -0
- package/src/spec/index.ts +54 -0
- package/src/spec/model.ts +636 -0
- package/src/spec/railroad-lib.ts +559 -0
- package/src/spec/railroad.ts +256 -0
- package/src/table/assemble.ts +2994 -0
- package/src/table/cell.ts +42 -0
- package/src/table/child-slots.ts +113 -0
- package/src/table/compile-rule-map.ts +336 -0
- package/src/table/compile.ts +244 -0
- package/src/table/duplication-hook.ts +89 -0
- package/src/table/emit-assembly.ts +1766 -0
- package/src/table/emit.ts +418 -0
- package/src/table/encode-baseline.ts +340 -0
- package/src/table/encode.ts +1569 -0
- package/src/table/exec-baseline.ts +537 -0
- package/src/table/exec.ts +1672 -0
- package/src/table/fold.ts +38 -0
- package/src/table/index.ts +108 -0
- package/src/table/inspect.ts +52 -0
- package/src/table/ops.ts +459 -0
- package/src/table/program.ts +855 -0
- package/src/table/run-support.ts +66 -0
- package/src/table/scan-shapes.ts +1578 -0
- package/src/table/site-labels.ts +228 -0
- package/src/table/stamp.ts +229 -0
- package/src/types.ts +563 -0
- package/src/version.ts +16 -0
- package/dist/compiler/codegen.d.ts +0 -334
- package/dist/compiler/codegen.d.ts.map +0 -1
- package/dist/compiler/inline-build.d.ts +0 -11
- package/dist/compiler/inline-build.d.ts.map +0 -1
- package/dist/compiler/inline-callback.d.ts +0 -21
- package/dist/compiler/inline-callback.d.ts.map +0 -1
- package/dist/compiler/line-index.d.ts +0 -2
- package/dist/compiler/line-index.d.ts.map +0 -1
- package/dist/compiler/module-hoist.d.ts +0 -106
- package/dist/compiler/module-hoist.d.ts.map +0 -1
- package/dist/compiler/scannable-run.d.ts.map +0 -1
- package/dist/compiler/scannable-terminal.d.ts +0 -23
- package/dist/compiler/scannable-terminal.d.ts.map +0 -1
- package/dist/compiler/trivia-fast-path.d.ts +0 -38
- package/dist/compiler/trivia-fast-path.d.ts.map +0 -1
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The human layer over `FixReport`.
|
|
3
|
+
*
|
|
4
|
+
* The claim this rendering has to carry is unusual, so it is made explicitly and never
|
|
5
|
+
* by implication: a fix shown here was APPLIED to the grammar, the grammar was
|
|
6
|
+
* RECOMPILED, the corpus was RE-PARSED, and the output did not move. Every offered
|
|
7
|
+
* rewrite prints that evidence next to it, with the sample and byte counts, because
|
|
8
|
+
* "proven" without a corpus size is a word, not a fact.
|
|
9
|
+
*
|
|
10
|
+
* The diff is the primary interface. `--apply` writing to a file is a second, explicit
|
|
11
|
+
* step; what a reader gets by default is what would change, in the form they would read
|
|
12
|
+
* it in a review.
|
|
13
|
+
*
|
|
14
|
+
* TWO STATES, MADE VISUALLY DISTINCT
|
|
15
|
+
* ----------------------------------
|
|
16
|
+
* ACTIONABLE and LOCATED are the whole model, and in the first cut they were two words
|
|
17
|
+
* in the same colour — which is to say, not a distinction at all until you read them.
|
|
18
|
+
* They now differ in glyph, colour and weight, so a reader triages the report by
|
|
19
|
+
* scanning the left margin rather than by parsing it. LOCATED prints the REASON and
|
|
20
|
+
* never advice: a site that cannot be rewritten is still worth knowing about, and that
|
|
21
|
+
* is the difference between "here is exactly where the problem is" and silence.
|
|
22
|
+
*
|
|
23
|
+
* Like `diagnose-render.ts`, this emits LINES OF SPANS and never an escape byte;
|
|
24
|
+
* `terminal.ts` owns every interaction with a terminal.
|
|
25
|
+
*/
|
|
26
|
+
import type { FixReport, VerifiedFix, LocatedFinding } from './fix.ts'
|
|
27
|
+
import {
|
|
28
|
+
DEFAULT_WIDTH, TONE, blank, codeFrame, groupDigits, render, rule, t, wrap,
|
|
29
|
+
type Line, type RenderTarget,
|
|
30
|
+
} from './terminal.ts'
|
|
31
|
+
|
|
32
|
+
export type FixRenderOptions = RenderTarget & {
|
|
33
|
+
name?: string
|
|
34
|
+
/**
|
|
35
|
+
* How many edits were WRITTEN to disk. A count, not a flag: `applyFixEdits` skips an
|
|
36
|
+
* edit whose span moved under it, so a run can write some of `r.verified` and skip the
|
|
37
|
+
* rest. A boolean here made the report say every verified change had been written
|
|
38
|
+
* whenever any one of them had been — the one number a reader checks after `--apply`,
|
|
39
|
+
* wrong in exactly the case that matters. Absent (or 0) means nothing was written.
|
|
40
|
+
*/
|
|
41
|
+
applied?: number
|
|
42
|
+
/** Absolute path of the edited source, used ONLY for the frame's terminal hyperlink. */
|
|
43
|
+
sourceRoot?: string
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function fixReportLines(r: FixReport, opts: FixRenderOptions = {}): Line[] {
|
|
47
|
+
const name = opts.name ?? 'grammar'
|
|
48
|
+
const width = opts.width ?? DEFAULT_WIDTH
|
|
49
|
+
const out: Line[] = []
|
|
50
|
+
|
|
51
|
+
if (!r.ok) {
|
|
52
|
+
out.push([t('✗ ', TONE.loud), t(name, TONE.strong),
|
|
53
|
+
t(' — nothing can be offered, because nothing could be checked', TONE.bad)])
|
|
54
|
+
for (const l of wrap(r.blocked ?? 'the verification loop could not run', width - 4, ' ')) out.push([t(l)])
|
|
55
|
+
out.push([t(' parseman only offers a change after it has applied it, rebuilt the parser and', TONE.quiet)])
|
|
56
|
+
out.push([t(' confirmed your files still parse to exactly the same thing. It could not do that', TONE.quiet)])
|
|
57
|
+
out.push([t(' here, so it is offering nothing rather than guessing.', TONE.quiet)])
|
|
58
|
+
return out
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const engines = r.engines.join(' + ')
|
|
62
|
+
if (r.verified.length === 0 && r.located.length === 0) {
|
|
63
|
+
out.push([t('✓ ', TONE.good), t(name, TONE.strong), t(' — nothing here can be rewritten', TONE.good)])
|
|
64
|
+
out.push([t(` Checked against ${groupDigits(r.corpus.samples)} of your files `
|
|
65
|
+
+ `(${groupDigits(r.corpus.bytes)} bytes). No change parseman knows how to make applies here.`,
|
|
66
|
+
TONE.quiet)])
|
|
67
|
+
return out
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// A count of edits actually written, and whether that is all of them. `skipped > 0` is
|
|
71
|
+
// the partial case: `applyFixEdits` declined an edit whose span no longer matched.
|
|
72
|
+
const written = opts.applied ?? 0
|
|
73
|
+
const wrote = written > 0
|
|
74
|
+
const skipped = wrote ? r.verified.length - written : 0
|
|
75
|
+
out.push([
|
|
76
|
+
t(wrote ? '✓ ' : '● ', wrote ? TONE.good : TONE.warn),
|
|
77
|
+
t(name, TONE.strong),
|
|
78
|
+
t(' — ', TONE.quiet),
|
|
79
|
+
t(`${groupDigits(r.verified.length)} change${r.verified.length === 1 ? '' : 's'} that `
|
|
80
|
+
+ `${r.verified.length === 1 ? 'is' : 'are'} safe to make`, TONE.good),
|
|
81
|
+
t(r.located.length > 0
|
|
82
|
+
? `, ${groupDigits(r.located.length)} place${r.located.length === 1 ? '' : 's'} that `
|
|
83
|
+
+ `${r.located.length === 1 ? 'needs' : 'need'} you`
|
|
84
|
+
: '', TONE.warn),
|
|
85
|
+
])
|
|
86
|
+
for (const l of wrap(
|
|
87
|
+
`Every change below was applied, the parser rebuilt, and your ${groupDigits(r.corpus.samples)} `
|
|
88
|
+
+ `file${r.corpus.samples === 1 ? '' : 's'} (${groupDigits(r.corpus.bytes)} bytes) parsed again with `
|
|
89
|
+
+ `${engines === 'interpreted + compiled' ? 'both engines' : engines} — the result was identical `
|
|
90
|
+
+ 'every time. A change that altered the result was thrown away and is not shown.',
|
|
91
|
+
width - 2, ' ')) out.push([t(l, TONE.faint)])
|
|
92
|
+
if (!wrote && r.verified.length > 0) {
|
|
93
|
+
out.push([t(' Nothing has been written. Add ', TONE.quiet),
|
|
94
|
+
t('--apply', TONE.strong), t(' to make these edits.', TONE.quiet)])
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
for (const f of r.verified) out.push(...verifiedLines(f, opts))
|
|
98
|
+
for (const l of r.located) out.push(...locatedLines(l, opts))
|
|
99
|
+
|
|
100
|
+
if (r.frozen.length > 0) {
|
|
101
|
+
out.push(blank())
|
|
102
|
+
for (const l of wrap(
|
|
103
|
+
`${groupDigits(r.frozen.length)} part(s) of the grammar were left untouched because parseman `
|
|
104
|
+
+ 'cannot rebuild them exactly and will not guess: '
|
|
105
|
+
+ r.frozen.slice(0, 6).map(f => `${f.rule} (${f.tag})`).join(', ')
|
|
106
|
+
+ (r.frozen.length > 6 ? ', …' : ''), width - 2, ' ')) out.push([t(l, TONE.faint)])
|
|
107
|
+
}
|
|
108
|
+
out.push(blank())
|
|
109
|
+
out.push([
|
|
110
|
+
t(wrote ? '✓ ' : '🔧 ', TONE.good),
|
|
111
|
+
t(`${groupDigits(r.verified.length)} safe to apply`, TONE.strong),
|
|
112
|
+
t(r.located.length > 0 ? `, ${groupDigits(r.located.length)} need you` : '', TONE.strong),
|
|
113
|
+
// Name the skipped edits. Silently reporting "written to disk" over a partial write
|
|
114
|
+
// is the failure this count exists to prevent: the reader would go on believing the
|
|
115
|
+
// file holds all of them.
|
|
116
|
+
t(wrote
|
|
117
|
+
? (skipped > 0
|
|
118
|
+
? ` · ${groupDigits(written)} written to disk, ${groupDigits(skipped)} skipped (the source moved under the edit)`
|
|
119
|
+
: ' · written to disk')
|
|
120
|
+
: ' · add --apply to make them · exiting 0 (nothing written)', TONE.faint),
|
|
121
|
+
])
|
|
122
|
+
return out
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function renderFixReport(r: FixReport, opts: FixRenderOptions = {}): string {
|
|
126
|
+
return render(fixReportLines(r, opts), opts)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function verifiedLines(f: VerifiedFix, opts: FixRenderOptions): Line[] {
|
|
130
|
+
const out: Line[] = []
|
|
131
|
+
const width = opts.width ?? DEFAULT_WIDTH
|
|
132
|
+
const b = f.benefit
|
|
133
|
+
const effects: string[] = []
|
|
134
|
+
if (b.antiPatternsAfter !== b.antiPatternsBefore) {
|
|
135
|
+
// The measured delta, not a hard-coded 1: the rewrite replaces a COMBINATOR, and a
|
|
136
|
+
// combinator shared by several arms removes a finding at each of them.
|
|
137
|
+
const removed = b.antiPatternsBefore - b.antiPatternsAfter
|
|
138
|
+
effects.push(`removes ${groupDigits(removed)} of the ${b.antiPatternsBefore} arms that hide their first character`)
|
|
139
|
+
}
|
|
140
|
+
if (b.ungatedChoicesAfter !== b.ungatedChoicesBefore) {
|
|
141
|
+
effects.push(`${b.ungatedChoicesBefore - b.ungatedChoicesAfter} fewer choice(s) the parser must guess at`)
|
|
142
|
+
}
|
|
143
|
+
if (b.gatedChoicesAfter !== b.gatedChoicesBefore) {
|
|
144
|
+
effects.push(`${b.gatedChoicesAfter - b.gatedChoicesBefore} more choice(s) decided from one character`)
|
|
145
|
+
}
|
|
146
|
+
// The first-set line earns its place only when the set MOVED. Printing `'i' → 'i'`
|
|
147
|
+
// under a heading called "why" is how a diagnostic loses trust.
|
|
148
|
+
if (f.armFirstSetBefore !== f.armFirstSetAfter) {
|
|
149
|
+
effects.push(`arm ${f.armIndex} now starts with a known character (${f.armFirstSetAfter})`)
|
|
150
|
+
}
|
|
151
|
+
if (f.choiceGatesBefore !== f.choiceGatesAfter) {
|
|
152
|
+
effects.push(`${f.choiceId} can now be decided from the next character alone`)
|
|
153
|
+
}
|
|
154
|
+
const effect = effects.join(' · ')
|
|
155
|
+
|
|
156
|
+
out.push(blank())
|
|
157
|
+
out.push(rule(width, TONE.frame))
|
|
158
|
+
out.push([
|
|
159
|
+
t(' 🔧 ', TONE.good),
|
|
160
|
+
t('SAFE TO APPLY', { color: 'green', bold: true }),
|
|
161
|
+
t(' '),
|
|
162
|
+
t(f.id, TONE.ident),
|
|
163
|
+
])
|
|
164
|
+
// The grammar SOURCE is the world this fix lives in, so it is a frame with the caret
|
|
165
|
+
// under the term being replaced rather than a bare `path:line:col`. The frame's own
|
|
166
|
+
// message carries the measured effect, so no line repeats the heading above it.
|
|
167
|
+
if (f.edit !== undefined) {
|
|
168
|
+
out.push(...codeFrame({
|
|
169
|
+
path: f.edit.path,
|
|
170
|
+
fullPath: opts.sourceRoot ?? f.edit.path,
|
|
171
|
+
line: f.edit.line,
|
|
172
|
+
column: f.edit.column,
|
|
173
|
+
// INCLUSIVE, per linecraft's CodeDebug (`highlightEnd - highlightStart + 1`), so the
|
|
174
|
+
// last underlined column is the last column of `oldText` — not the one after it.
|
|
175
|
+
endColumn: f.edit.column + Math.max(f.edit.oldText.length - 1, 0),
|
|
176
|
+
lineText: f.edit.lineText.replace(/\t/g, ' '),
|
|
177
|
+
message: effect,
|
|
178
|
+
shortMessage: `→ ${f.edit.newText}`,
|
|
179
|
+
type: 'info',
|
|
180
|
+
}, opts, ' '))
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
out.push([t(' - ', TONE.bad), t(f.before, TONE.bad)])
|
|
184
|
+
out.push([t(' + ', TONE.good), t(f.after, TONE.good)])
|
|
185
|
+
out.push([t(' effect ', TONE.quiet), t(effect, TONE.strong)])
|
|
186
|
+
}
|
|
187
|
+
if (b.artifactBytesBefore !== null && b.artifactBytesAfter !== null && b.artifactBytesAfter !== b.artifactBytesBefore) {
|
|
188
|
+
const d = b.artifactBytesAfter - b.artifactBytesBefore
|
|
189
|
+
out.push([t(' size ', TONE.faint),
|
|
190
|
+
t(`the generated parser ${d > 0 ? 'grows' : 'shrinks'} by ${groupDigits(Math.abs(d))} bytes`, TONE.faint)])
|
|
191
|
+
}
|
|
192
|
+
const checked = `this exact change was made, the parser rebuilt, and your `
|
|
193
|
+
+ `${groupDigits(f.evidence.samples)} file${f.evidence.samples === 1 ? '' : 's'} parsed again — `
|
|
194
|
+
+ 'identical result'
|
|
195
|
+
const cl = wrap(checked, width - 12, '')
|
|
196
|
+
out.push([t(' checked ', TONE.quiet), t(cl[0] ?? '', TONE.good)])
|
|
197
|
+
for (const x of cl.slice(1)) out.push([t(' '), t(x, TONE.good)])
|
|
198
|
+
return out
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function locatedLines(l: LocatedFinding, opts: FixRenderOptions): Line[] {
|
|
202
|
+
const out: Line[] = []
|
|
203
|
+
const width = opts.width ?? DEFAULT_WIDTH
|
|
204
|
+
out.push(blank())
|
|
205
|
+
out.push(rule(width, TONE.frame))
|
|
206
|
+
out.push([
|
|
207
|
+
t(' ✋ ', TONE.warn),
|
|
208
|
+
t('NEEDS YOU', { color: 'yellow', bold: true }),
|
|
209
|
+
t(' '),
|
|
210
|
+
t(l.id, TONE.ident),
|
|
211
|
+
])
|
|
212
|
+
out.push([t(' here ', TONE.faint), t(l.site, TONE.quiet)])
|
|
213
|
+
const lines = wrap(`No change can be offered here: ${l.reason}`, width - 12, '')
|
|
214
|
+
out.push([t(' why ', TONE.quiet), t(lines[0] ?? '', TONE.warn)])
|
|
215
|
+
for (const x of lines.slice(1)) out.push([t(' '), t(x, TONE.warn)])
|
|
216
|
+
return out
|
|
217
|
+
}
|