@blundergoat/gruff-ts 0.1.0 → 0.1.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.
- package/CHANGELOG.md +14 -2
- package/CONTRIBUTING.md +3 -3
- package/README.md +140 -182
- package/docs/README.md +23 -0
- package/docs/ci-integration.md +63 -0
- package/docs/{CONFIGURATION.md → configuration.md} +2 -19
- package/docs/dashboard.md +29 -0
- package/docs/output-formats.md +65 -0
- package/docs/{RELEASING.md → releasing.md} +12 -10
- package/docs/rules.md +177 -0
- package/package.json +2 -2
- package/scripts/bump-version.sh +67 -18
- package/scripts/dependency-install.sh +96 -0
- package/scripts/dependency-update.sh +177 -0
- package/scripts/preflight-checks.sh +75 -0
- package/src/analyser.ts +5 -20
- package/src/blocks.ts +4 -4
- package/src/class-rules.ts +5 -6
- package/src/cli-program.ts +125 -12
- package/src/cli.ts +4 -1
- package/src/comment-rules.ts +2 -0
- package/src/config.ts +2 -4
- package/src/constants.ts +1 -1
- package/src/dead-code-rules.ts +2 -2
- package/src/init-config.ts +248 -0
- package/src/line-rules.ts +6 -8
- package/src/naming-pushers.ts +0 -31
- package/src/project-config-rules.ts +1 -1
- package/src/report-renderers.ts +60 -11
- package/src/rule-list.ts +1 -0
- package/src/rules.ts +14 -16
- package/src/safety-rules.ts +3 -3
- package/src/scoring.ts +4 -4
- package/src/test-fixtures.ts +0 -2
- package/src/text-scans.ts +1 -152
- package/src/types.ts +1 -2
- /package/docs/{REPORTS_AND_CI.md → reports-and-ci.md} +0 -0
package/src/rules.ts
CHANGED
|
@@ -27,7 +27,6 @@ const RULE_DESCRIPTORS: readonly RuleDescriptor[] = [
|
|
|
27
27
|
{ ruleId: "docs.stale-comment", pillar: "documentation", severity: "advisory", confidence: "medium", description: "Flags comments that reference missing files, unknown rules, stale CLI flags, or the wrong declaration.", remediation: "Update the comment or add historical context explaining why it remains useful." },
|
|
28
28
|
{ ruleId: "docs.stale-param-tag", pillar: "documentation", severity: "advisory", confidence: "medium", description: "Flags @param tags for parameters no longer in the signature.", remediation: "Remove stale tags or update the function signature." },
|
|
29
29
|
{ ruleId: "docs.suppression-without-rationale", pillar: "documentation", severity: "advisory", confidence: "medium", description: "Flags lint, formatter, coverage, or tool suppressions without a maintainer rationale.", remediation: "Explain why the suppression is intentional, a false positive, or tracked elsewhere." },
|
|
30
|
-
{ ruleId: "docs.todo-density", pillar: "documentation", severity: "advisory", confidence: "high", description: "Flags files with a high count of TODO/FIXME markers (opt-in, disabled by default).", remediation: "Resolve stale markers, link them to tracked work, or enable docs.todo-without-tracking for context-aware coverage.", threshold: 4 },
|
|
31
30
|
{ ruleId: "docs.todo-without-tracking", pillar: "documentation", severity: "advisory", confidence: "high", description: "Flags TODO, FIXME, HACK, and XXX comments without tracking context.", remediation: "Attach a tracking URL, issue id, owner, date, ADR, or .goat-flow task reference." },
|
|
32
31
|
{ ruleId: "docs.useless-docblock", pillar: "documentation", severity: "advisory", confidence: "medium", description: "Flags comments or docblocks that only restate the symbol name.", remediation: "Replace the comment with useful contract or behavior detail." },
|
|
33
32
|
{ ruleId: "modernisation.date-now-candidate", pillar: "modernisation", severity: "advisory", confidence: "high", description: "Flags verbose current-time expressions that can use Date.now().", remediation: "Use Date.now() for current epoch milliseconds." },
|
|
@@ -44,7 +43,6 @@ const RULE_DESCRIPTORS: readonly RuleDescriptor[] = [
|
|
|
44
43
|
{ ruleId: "modernisation.tsconfig-index-safety-disabled", pillar: "modernisation", severity: "warning", confidence: "high", description: "Flags tsconfig files without noUncheckedIndexedAccess enabled.", remediation: "Enable noUncheckedIndexedAccess unless migration is blocked." },
|
|
45
44
|
{ ruleId: "modernisation.tsconfig-strict-disabled", pillar: "modernisation", severity: "warning", confidence: "high", description: "Flags tsconfig files without strict mode enabled.", remediation: "Enable strict unless migration is blocked." },
|
|
46
45
|
{ ruleId: "modernisation.var-declaration", pillar: "modernisation", severity: "advisory", confidence: "high", description: "Flags var declarations.", remediation: "Use let or const with the narrowest useful scope." },
|
|
47
|
-
{ ruleId: "naming.abbreviation", pillar: "naming", severity: "advisory", confidence: "medium", description: "Flags identifiers in the project abbreviation denylist (opt-in, disabled by default).", remediation: "Use the full domain term or add the abbreviation to allowlists.acceptedAbbreviations." },
|
|
48
46
|
{ ruleId: "naming.acronym-case", pillar: "naming", severity: "advisory", confidence: "medium", description: "Flags mixed casings of a known acronym in one file.", remediation: "Use one casing for each acronym throughout the file." },
|
|
49
47
|
{ ruleId: "naming.boolean-prefix", pillar: "naming", severity: "advisory", confidence: "medium", description: "Flags boolean names without intent-revealing prefixes on declarations, function parameters (typed `: boolean` or with `= true|false` default), and interface/type-literal fields.", remediation: "Use prefixes such as is, has, can, should, or will." },
|
|
50
48
|
{ ruleId: "naming.class-file-mismatch", pillar: "naming", severity: "advisory", confidence: "medium", description: "Flags exported classes whose name differs from the file name.", remediation: "Rename the class or file so the primary export is easy to locate." },
|
|
@@ -109,20 +107,20 @@ const RULE_DESCRIPTORS: readonly RuleDescriptor[] = [
|
|
|
109
107
|
{ ruleId: "test-quality.snapshot-only-test", pillar: "test-quality", severity: "advisory", confidence: "high", description: "Flags tests that rely only on snapshots.", remediation: "Add targeted assertions for important behavior." },
|
|
110
108
|
{ ruleId: "test-quality.trivial-assertion", pillar: "test-quality", severity: "warning", confidence: "high", description: "Flags tautological assertions.", remediation: "Assert a real result from the system under test." },
|
|
111
109
|
{ ruleId: "test-quality.unused-mock", pillar: "test-quality", severity: "advisory", confidence: "medium", description: "Flags mocks created but not used.", remediation: "Remove unused mocks or wire them into the behavior under test." },
|
|
112
|
-
{ ruleId: "waste.any-type", pillar: "
|
|
113
|
-
{ ruleId: "waste.broad-runtime-version", pillar: "
|
|
114
|
-
{ ruleId: "waste.commented-out-code", pillar: "
|
|
115
|
-
{ ruleId: "waste.console-log", pillar: "
|
|
116
|
-
{ ruleId: "waste.empty-function", pillar: "
|
|
117
|
-
{ ruleId: "waste.exported-any", pillar: "
|
|
118
|
-
{ ruleId: "waste.redundant-boolean-cast", pillar: "
|
|
119
|
-
{ ruleId: "waste.redundant-variable", pillar: "
|
|
120
|
-
{ ruleId: "waste.swallowed-catch", pillar: "
|
|
121
|
-
{ ruleId: "waste.useless-catch", pillar: "
|
|
122
|
-
{ ruleId: "waste.useless-return", pillar: "
|
|
123
|
-
{ ruleId: "waste.unreachable-code", pillar: "
|
|
124
|
-
{ ruleId: "waste.unused-import", pillar: "
|
|
125
|
-
{ ruleId: "waste.unused-parameter", pillar: "
|
|
110
|
+
{ ruleId: "waste.any-type", pillar: "maintainability", severity: "warning", confidence: "high", description: "Flags any type usage.", remediation: "Use unknown with validation or a precise type." },
|
|
111
|
+
{ ruleId: "waste.broad-runtime-version", pillar: "maintainability", severity: "advisory", confidence: "medium", description: "Flags broad runtime dependency version ranges.", remediation: "Use bounded semver ranges and lockfiles." },
|
|
112
|
+
{ ruleId: "waste.commented-out-code", pillar: "maintainability", severity: "advisory", confidence: "high", description: "Flags comments that appear to contain disabled code.", remediation: "Delete dead code or restore it behind a real feature path." },
|
|
113
|
+
{ ruleId: "waste.console-log", pillar: "maintainability", severity: "advisory", confidence: "high", description: "Flags console log/debug calls in source.", remediation: "Remove debug logging or route through structured logging." },
|
|
114
|
+
{ ruleId: "waste.empty-function", pillar: "maintainability", severity: "advisory", confidence: "high", description: "Flags functions with no executable body.", remediation: "Delete the function or add the missing implementation." },
|
|
115
|
+
{ ruleId: "waste.exported-any", pillar: "maintainability", severity: "warning", confidence: "medium", description: "Flags exported APIs exposing any.", remediation: "Use a named interface, unknown with validation, or precise generics." },
|
|
116
|
+
{ ruleId: "waste.redundant-boolean-cast", pillar: "maintainability", severity: "advisory", confidence: "medium", description: "Flags redundant boolean casts in condition expressions.", remediation: "Use the condition value directly or name the boolean conversion." },
|
|
117
|
+
{ ruleId: "waste.redundant-variable", pillar: "maintainability", severity: "advisory", confidence: "medium", description: "Flags variables returned immediately after assignment.", remediation: "Return the expression directly." },
|
|
118
|
+
{ ruleId: "waste.swallowed-catch", pillar: "maintainability", severity: "warning", confidence: "medium", description: "Flags empty catch blocks.", remediation: "Handle, report, rethrow, or document intentional ignore paths." },
|
|
119
|
+
{ ruleId: "waste.useless-catch", pillar: "maintainability", severity: "advisory", confidence: "high", description: "Flags catch blocks that only rethrow the caught value.", remediation: "Remove the catch block or add meaningful handling." },
|
|
120
|
+
{ ruleId: "waste.useless-return", pillar: "maintainability", severity: "advisory", confidence: "medium", description: "Flags terminal bare return statements in void functions.", remediation: "Remove the final return statement." },
|
|
121
|
+
{ ruleId: "waste.unreachable-code", pillar: "maintainability", severity: "warning", confidence: "high", description: "Flags statements after terminating statements.", remediation: "Delete unreachable code or restructure the control flow." },
|
|
122
|
+
{ ruleId: "waste.unused-import", pillar: "maintainability", severity: "advisory", confidence: "medium", description: "Flags named imports with no apparent usage.", remediation: "Remove unused imports." },
|
|
123
|
+
{ ruleId: "waste.unused-parameter", pillar: "maintainability", severity: "advisory", confidence: "medium", description: "Flags parameters with no apparent usage.", remediation: "Remove the parameter or prefix it with _ if intentional." },
|
|
126
124
|
];
|
|
127
125
|
|
|
128
126
|
/**
|
package/src/safety-rules.ts
CHANGED
|
@@ -38,7 +38,7 @@ export function analyseUselessCatches(file: SourceFile, source: string, findings
|
|
|
38
38
|
filePath: file.displayPath,
|
|
39
39
|
line: byteLine(source, match.index ?? 0),
|
|
40
40
|
severity: "advisory",
|
|
41
|
-
pillar: "
|
|
41
|
+
pillar: "maintainability",
|
|
42
42
|
confidence: "high",
|
|
43
43
|
remediation: "Remove the catch block or add meaningful handling.",
|
|
44
44
|
metadata: { binding },
|
|
@@ -67,7 +67,7 @@ export function analyseSwallowedCatches(file: SourceFile, rawSource: string, cod
|
|
|
67
67
|
filePath: file.displayPath,
|
|
68
68
|
line: byteLine(rawSource, match.index ?? 0),
|
|
69
69
|
severity: "warning",
|
|
70
|
-
pillar: "
|
|
70
|
+
pillar: "maintainability",
|
|
71
71
|
confidence: "medium",
|
|
72
72
|
remediation: "Handle the error explicitly, rethrow it, or document an intentional ignore path.",
|
|
73
73
|
metadata: { ...(binding ? { binding } : {}) },
|
|
@@ -180,7 +180,7 @@ function pushExportedAnyFinding(file: SourceFile, codeLine: string, lineNumber:
|
|
|
180
180
|
filePath: file.displayPath,
|
|
181
181
|
line: lineNumber,
|
|
182
182
|
severity: "warning",
|
|
183
|
-
pillar: "
|
|
183
|
+
pillar: "maintainability",
|
|
184
184
|
confidence: "medium",
|
|
185
185
|
symbol: exportedAny,
|
|
186
186
|
remediation: "Use a named interface, unknown plus validation, or a precise generic type.",
|
package/src/scoring.ts
CHANGED
|
@@ -3,8 +3,9 @@ import { grade } from "./report-renderers.ts";
|
|
|
3
3
|
import type { AnalysisReport, FailThreshold, Finding, Pillar, Severity } from "./types.ts";
|
|
4
4
|
|
|
5
5
|
// Builds the per-pillar and per-file score breakdown that ships in `gruff.analysis.v1`. The composite
|
|
6
|
-
// score is the mean of pillar scores so adding a pillar shifts the headline number
|
|
7
|
-
//
|
|
6
|
+
// score is the mean of pillar scores so adding a pillar shifts the headline number. `topOffenders` is
|
|
7
|
+
// the full file list sorted worst-first; renderers cap it themselves (HTML/hotspot keep their 10-row
|
|
8
|
+
// UX, summary honours `--top`). The field shape is part of the `gruff.analysis.v1` schema contract.
|
|
8
9
|
function scoreReport(findings: Finding[]): AnalysisReport["score"] {
|
|
9
10
|
const byPillar = new Map<Pillar, Finding[]>();
|
|
10
11
|
const byFile = new Map<string, Finding[]>();
|
|
@@ -23,8 +24,7 @@ function scoreReport(findings: Finding[]): AnalysisReport["score"] {
|
|
|
23
24
|
score: Math.max(0, 100 - fileFindings.reduce((sum, finding) => sum + severityPenalty(finding.severity), 0)),
|
|
24
25
|
findings: fileFindings.length,
|
|
25
26
|
}))
|
|
26
|
-
.sort((left, right) => left.score - right.score)
|
|
27
|
-
.slice(0, 10);
|
|
27
|
+
.sort((left, right) => left.score - right.score);
|
|
28
28
|
return { composite, grade: grade(composite), pillars, topOffenders };
|
|
29
29
|
}
|
|
30
30
|
|
package/src/test-fixtures.ts
CHANGED
|
@@ -608,8 +608,6 @@ function catalogueCoverageOptions(): AnalyseProjectOptions {
|
|
|
608
608
|
"complexity.cyclomatic": { threshold: 2, severity: "warning" },
|
|
609
609
|
"complexity.npath": { threshold: 2, severity: "warning" },
|
|
610
610
|
"design.large-module-concentration": { threshold: 35, severity: "advisory", options: { minFiles: 4, minLines: 8 } },
|
|
611
|
-
"docs.todo-density": { enabled: true, threshold: 1, severity: "advisory" },
|
|
612
|
-
"naming.abbreviation": { enabled: true },
|
|
613
611
|
"size.file-length": { threshold: 8, severity: "warning" },
|
|
614
612
|
"size.function-length": { threshold: 8, severity: "warning" },
|
|
615
613
|
"size.parameter-count": { threshold: 3, severity: "warning" },
|
package/src/text-scans.ts
CHANGED
|
@@ -26,157 +26,6 @@ function firstLine(source: string, pattern: RegExp): number {
|
|
|
26
26
|
return source.split(/\r?\n/).findIndex((line) => pattern.test(line)) + 1 || 1;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
// Mutable lexer state threaded through the task-marker scanner. `quote === "\`"` survives across
|
|
30
|
-
// newlines because template literals can span lines; ordinary quotes reset at end of line.
|
|
31
|
-
interface TodoMarkerScanState {
|
|
32
|
-
isInBlockComment: boolean;
|
|
33
|
-
quote: string | undefined;
|
|
34
|
-
isEscaped: boolean;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// One scanner step yields the comment bytes for this position, how many extra characters to skip
|
|
38
|
-
// (e.g., to consume `*/`), and whether the rest of the line is comment text (no need to keep scanning).
|
|
39
|
-
interface CommentScanStep {
|
|
40
|
-
comment: string;
|
|
41
|
-
skip: number;
|
|
42
|
-
isDone: boolean;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Task-marker counter consumed by the density rule. Skipping strings is mandatory - markers inside
|
|
46
|
-
// string literals must not inflate the count, or every fixture string containing a task keyword
|
|
47
|
-
// would trip. `isScript` flips `#` line-comment recognition for shell-like config files.
|
|
48
|
-
function todoMarkerSummary(source: string, isScript: boolean): { count: number; firstLine: number } {
|
|
49
|
-
if (!source.includes("TODO") && !source.includes("FIXME")) {
|
|
50
|
-
return { count: 0, firstLine: 1 };
|
|
51
|
-
}
|
|
52
|
-
let count = 0;
|
|
53
|
-
let firstLine = 0;
|
|
54
|
-
const state: TodoMarkerScanState = { isInBlockComment: false, quote: undefined, isEscaped: false };
|
|
55
|
-
|
|
56
|
-
source.split(/\r?\n/).forEach((line, index) => {
|
|
57
|
-
const markerCount = countMatches(commentTextForLine(line, state, isScript), /\b(?:TODO|FIXME)\b/g);
|
|
58
|
-
if (markerCount === 0) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
count += markerCount;
|
|
62
|
-
if (firstLine === 0) {
|
|
63
|
-
firstLine = index + 1;
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
return { count, firstLine: firstLine || 1 };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Returns only the comment portions of `line` - strings, regex literals, and code are dropped.
|
|
71
|
-
// Mutates `state` so block comments and template literals can carry across line boundaries.
|
|
72
|
-
function commentTextForLine(line: string, state: TodoMarkerScanState, isScript: boolean): string {
|
|
73
|
-
let comment = "";
|
|
74
|
-
for (let index = 0; index < line.length; index += 1) {
|
|
75
|
-
const step = commentScanStep(line, index, state, isScript);
|
|
76
|
-
comment += step.comment;
|
|
77
|
-
index += step.skip;
|
|
78
|
-
if (step.isDone) {
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
if (state.quote !== "`") {
|
|
83
|
-
state.quote = undefined;
|
|
84
|
-
state.isEscaped = false;
|
|
85
|
-
}
|
|
86
|
-
return comment;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Three-state dispatcher: in a block comment, in a quoted string, or in executable code. Each
|
|
90
|
-
// branch must be exhaustive - falling through would let a task keyword inside a string get counted.
|
|
91
|
-
function commentScanStep(line: string, index: number, state: TodoMarkerScanState, isScript: boolean): CommentScanStep {
|
|
92
|
-
const character = line[index] ?? "";
|
|
93
|
-
const next = line[index + 1] ?? "";
|
|
94
|
-
if (state.isInBlockComment) {
|
|
95
|
-
return blockCommentScanStep(character, next, state);
|
|
96
|
-
}
|
|
97
|
-
if (state.quote) {
|
|
98
|
-
return quotedScanStep(character, state);
|
|
99
|
-
}
|
|
100
|
-
return openCodeCommentScanStep(line, index, state, isScript);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Priority order: quote → block opener → line comment. Quotes must come first because `/* ... */`
|
|
104
|
-
// inside a string is just text, and `// foo` inside a string would otherwise prematurely end scanning.
|
|
105
|
-
function openCodeCommentScanStep(line: string, index: number, state: TodoMarkerScanState, isScript: boolean): CommentScanStep {
|
|
106
|
-
const character = line[index] ?? "";
|
|
107
|
-
const next = line[index + 1] ?? "";
|
|
108
|
-
const quoteStep = quoteStartScanStep(character, state);
|
|
109
|
-
if (quoteStep) {
|
|
110
|
-
return quoteStep;
|
|
111
|
-
}
|
|
112
|
-
const blockStep = blockStartScanStep(character, next, state);
|
|
113
|
-
if (blockStep) {
|
|
114
|
-
return blockStep;
|
|
115
|
-
}
|
|
116
|
-
return lineCommentScanStep(line, index, character, next, isScript);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Detects opening quote of a string or template literal and mutates `state.quote` so subsequent
|
|
120
|
-
// characters are routed through `quotedScanStep` rather than the code branch.
|
|
121
|
-
function quoteStartScanStep(character: string, state: TodoMarkerScanState): CommentScanStep | undefined {
|
|
122
|
-
if (character === "\"" || character === "'" || character === "`") {
|
|
123
|
-
state.quote = character;
|
|
124
|
-
return emptyCommentScanStep();
|
|
125
|
-
}
|
|
126
|
-
return undefined;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Detects `/*` opener. Returns `skip: 1` so the caller advances past `*` and does not re-enter on
|
|
130
|
-
// the next character as if `*` were code.
|
|
131
|
-
function blockStartScanStep(character: string, next: string, state: TodoMarkerScanState): CommentScanStep | undefined {
|
|
132
|
-
if (character === "/" && next === "*") {
|
|
133
|
-
state.isInBlockComment = true;
|
|
134
|
-
return { comment: "", skip: 1, isDone: false };
|
|
135
|
-
}
|
|
136
|
-
return undefined;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Slices the comment payload after `//` (or `#` in config files) and signals `isDone: true` so the
|
|
140
|
-
// caller stops walking the line - everything to the right is comment text.
|
|
141
|
-
function lineCommentScanStep(line: string, index: number, character: string, next: string, isScript: boolean): CommentScanStep {
|
|
142
|
-
if (character === "/" && next === "/") {
|
|
143
|
-
return { comment: line.slice(index + 2), skip: line.length, isDone: true };
|
|
144
|
-
}
|
|
145
|
-
if (!isScript && character === "#") {
|
|
146
|
-
return { comment: line.slice(index + 1), skip: line.length, isDone: true };
|
|
147
|
-
}
|
|
148
|
-
return emptyCommentScanStep();
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Inside a block comment until `*/` is seen. Each character is treated as comment text so task
|
|
152
|
-
// markers inside the block contribute to the count.
|
|
153
|
-
function blockCommentScanStep(character: string, next: string, state: TodoMarkerScanState): CommentScanStep {
|
|
154
|
-
if (character === "*" && next === "/") {
|
|
155
|
-
state.isInBlockComment = false;
|
|
156
|
-
return { comment: "", skip: 1, isDone: false };
|
|
157
|
-
}
|
|
158
|
-
return { comment: character, skip: 0, isDone: false };
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Consumes the body of a string/template literal. `\` toggles `isEscaped` so the next character
|
|
162
|
-
// is not interpreted as the closing quote - necessary for sequences like `"\""` and `"\\\""`.
|
|
163
|
-
function quotedScanStep(character: string, state: TodoMarkerScanState): CommentScanStep {
|
|
164
|
-
if (state.isEscaped) {
|
|
165
|
-
state.isEscaped = false;
|
|
166
|
-
} else if (character === "\\") {
|
|
167
|
-
state.isEscaped = true;
|
|
168
|
-
} else if (character === state.quote) {
|
|
169
|
-
state.quote = undefined;
|
|
170
|
-
}
|
|
171
|
-
return emptyCommentScanStep();
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// No-op step used by branches that consumed a character but produced no comment text - keeps the
|
|
175
|
-
// caller loop branchless at the cost of one allocation per non-comment character.
|
|
176
|
-
function emptyCommentScanStep(): CommentScanStep {
|
|
177
|
-
return { comment: "", skip: 0, isDone: false };
|
|
178
|
-
}
|
|
179
|
-
|
|
180
29
|
// One-based line number containing byte offset `index`. Used to anchor findings extracted from
|
|
181
30
|
// regex match indices; off-by-one would shift every reported line in the resulting reports.
|
|
182
31
|
function byteLine(source: string, index: number): number {
|
|
@@ -190,4 +39,4 @@ function byteLine(source: string, index: number): number {
|
|
|
190
39
|
return line;
|
|
191
40
|
}
|
|
192
41
|
|
|
193
|
-
export { byteLine, countMatches, firstLine
|
|
42
|
+
export { byteLine, countMatches, firstLine };
|
package/src/types.ts
CHANGED
|
@@ -6,7 +6,7 @@ export type Pillar =
|
|
|
6
6
|
| "size"
|
|
7
7
|
| "complexity"
|
|
8
8
|
| "dead-code"
|
|
9
|
-
| "
|
|
9
|
+
| "maintainability"
|
|
10
10
|
| "naming"
|
|
11
11
|
| "documentation"
|
|
12
12
|
| "modernisation"
|
|
@@ -48,7 +48,6 @@ export interface Config {
|
|
|
48
48
|
booleanPrefixes: Set<string>;
|
|
49
49
|
hungarianPrefixes: Set<string>;
|
|
50
50
|
placeholderNames: Set<string>;
|
|
51
|
-
abbreviationDenylist: Set<string>;
|
|
52
51
|
negativeBooleanAllowed: Set<string>;
|
|
53
52
|
knownAcronyms: Set<string>;
|
|
54
53
|
rules: Map<string, { enabled?: boolean; threshold?: number; severity?: Severity; options: Map<string, number> }>;
|
|
File without changes
|