taste-lint 0.0.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/LICENSE.md +9 -0
- package/README.md +141 -0
- package/data/config.schema.json +123 -0
- package/data/corpus/blode-co-review.jsonl +80 -0
- package/data/corpus/copywriting.jsonl +139 -0
- package/data/corpus/typography.jsonl +53 -0
- package/data/rule-drafts/README.md +9 -0
- package/data/rule-drafts/interaction/interaction-layout-shift.yaml +54 -0
- package/data/rule-drafts/typography/typography-long-content-safety.yaml +60 -0
- package/data/rules/authoring/authoring-approval-every-step.yaml +44 -0
- package/data/rules/authoring/authoring-fixed-agent-quota.yaml +44 -0
- package/data/rules/authoring/authoring-generic-coding-advice.yaml +44 -0
- package/data/rules/authoring/authoring-generic-verification.yaml +45 -0
- package/data/rules/authoring/authoring-plan-vague-acceptance.yaml +43 -0
- package/data/rules/copywriting/copywriting-announced-honesty.yaml +43 -0
- package/data/rules/copywriting/copywriting-anthropomorphism.yaml +29 -0
- package/data/rules/copywriting/copywriting-artificial-balance.yaml +35 -0
- package/data/rules/copywriting/copywriting-bare-confirm-label.yaml +23 -0
- package/data/rules/copywriting/copywriting-boilerplate-offer.yaml +38 -0
- package/data/rules/copywriting/copywriting-canned-phrasing.yaml +53 -0
- package/data/rules/copywriting/copywriting-changed-supplied-facts.yaml +31 -0
- package/data/rules/copywriting/copywriting-claim-without-evidence.yaml +59 -0
- package/data/rules/copywriting/copywriting-click-here-links.yaml +22 -0
- package/data/rules/copywriting/copywriting-conditions-first.yaml +50 -0
- package/data/rules/copywriting/copywriting-confirmshaming.yaml +43 -0
- package/data/rules/copywriting/copywriting-cta-names-outcome.yaml +54 -0
- package/data/rules/copywriting/copywriting-dead-weight-hedges.yaml +58 -0
- package/data/rules/copywriting/copywriting-drafting-instruction-echo.yaml +31 -0
- package/data/rules/copywriting/copywriting-emoji-in-ui.yaml +20 -0
- package/data/rules/copywriting/copywriting-empty-state-no-action.yaml +51 -0
- package/data/rules/copywriting/copywriting-error-descriptions.yaml +53 -0
- package/data/rules/copywriting/copywriting-excessive-hedging.yaml +48 -0
- package/data/rules/copywriting/copywriting-fabricated-specificity.yaml +35 -0
- package/data/rules/copywriting/copywriting-filler-words.yaml +55 -0
- package/data/rules/copywriting/copywriting-flat-description.yaml +37 -0
- package/data/rules/copywriting/copywriting-friction-cta.yaml +53 -0
- package/data/rules/copywriting/copywriting-generic-audience.yaml +55 -0
- package/data/rules/copywriting/copywriting-generic-framing.yaml +35 -0
- package/data/rules/copywriting/copywriting-generic-language.yaml +35 -0
- package/data/rules/copywriting/copywriting-generic-validation.yaml +46 -0
- package/data/rules/copywriting/copywriting-idea-repetition.yaml +34 -0
- package/data/rules/copywriting/copywriting-latinisms.yaml +25 -0
- package/data/rules/copywriting/copywriting-leaked-error-message.yaml +23 -0
- package/data/rules/copywriting/copywriting-live-region-feedback.yaml +24 -0
- package/data/rules/copywriting/copywriting-machine-prose.yaml +73 -0
- package/data/rules/copywriting/copywriting-mechanism-over-outcome.yaml +33 -0
- package/data/rules/copywriting/copywriting-meta-commentary.yaml +48 -0
- package/data/rules/copywriting/copywriting-missing-reasoning-link.yaml +33 -0
- package/data/rules/copywriting/copywriting-nominalisations.yaml +45 -0
- package/data/rules/copywriting/copywriting-over-explanation.yaml +34 -0
- package/data/rules/copywriting/copywriting-passive-voice.yaml +53 -0
- package/data/rules/copywriting/copywriting-permission-benefit.yaml +43 -0
- package/data/rules/copywriting/copywriting-profile-register-mismatch.yaml +31 -0
- package/data/rules/copywriting/copywriting-promotional-docs-voice.yaml +58 -0
- package/data/rules/copywriting/copywriting-prompt-restatement.yaml +35 -0
- package/data/rules/copywriting/copywriting-punctuation-tics.yaml +35 -0
- package/data/rules/copywriting/copywriting-reader-first.yaml +59 -0
- package/data/rules/copywriting/copywriting-register-shift.yaml +58 -0
- package/data/rules/copywriting/copywriting-repetitive-transitions.yaml +48 -0
- package/data/rules/copywriting/copywriting-requirements-language.yaml +50 -0
- package/data/rules/copywriting/copywriting-searchable-headings.yaml +52 -0
- package/data/rules/copywriting/copywriting-semantic-links.yaml +23 -0
- package/data/rules/copywriting/copywriting-structural-symmetry.yaml +35 -0
- package/data/rules/copywriting/copywriting-success-state-specific.yaml +43 -0
- package/data/rules/copywriting/copywriting-temporal-words.yaml +55 -0
- package/data/rules/copywriting/copywriting-toast-successfully.yaml +22 -0
- package/data/rules/copywriting/copywriting-unexplained-action.yaml +33 -0
- package/data/rules/copywriting/copywriting-unnatural-polish.yaml +48 -0
- package/data/rules/copywriting/copywriting-unraised-objection.yaml +43 -0
- package/data/rules/copywriting/copywriting-unverifiable-proof.yaml +23 -0
- package/data/rules/copywriting/copywriting-vague-error.yaml +58 -0
- package/data/rules/copywriting/copywriting-vague-personal-request.yaml +43 -0
- package/data/rules/copywriting/copywriting-visual-direction-instruction.yaml +43 -0
- package/data/rules/craft/craft-affordance-mismatch.yaml +23 -0
- package/data/rules/craft/craft-decoration-no-role.yaml +27 -0
- package/data/rules/craft/craft-faux-product-chrome.yaml +22 -0
- package/data/rules/craft/craft-hover-only-affordance.yaml +23 -0
- package/data/rules/craft/craft-i18n-rtl-untested.yaml +23 -0
- package/data/rules/craft/craft-i18n-untested.yaml +28 -0
- package/data/rules/craft/craft-image-dimensions-and-priority.yaml +23 -0
- package/data/rules/craft/craft-inline-styles.yaml +24 -0
- package/data/rules/craft/craft-lazy-load-offscreen.yaml +28 -0
- package/data/rules/craft/craft-near-duplicate-scale.yaml +29 -0
- package/data/rules/craft/craft-token-drift.yaml +22 -0
- package/data/rules/craft/craft-viewport-scaling.yaml +25 -0
- package/data/rules/craft/craft-virtualize-large-lists.yaml +24 -0
- package/data/rules/interaction/interaction-a11y-color-only-meaning.yaml +23 -0
- package/data/rules/interaction/interaction-a11y-data-table-semantics.yaml +24 -0
- package/data/rules/interaction/interaction-a11y-disabled-control-tooltip.yaml +23 -0
- package/data/rules/interaction/interaction-a11y-document-language.yaml +24 -0
- package/data/rules/interaction/interaction-a11y-icon-controls-labeled.yaml +23 -0
- package/data/rules/interaction/interaction-a11y-image-alt-text.yaml +24 -0
- package/data/rules/interaction/interaction-a11y-media-captions.yaml +24 -0
- package/data/rules/interaction/interaction-a11y-semantic-html-first.yaml +23 -0
- package/data/rules/interaction/interaction-a11y-skip-link-heading-order.yaml +24 -0
- package/data/rules/interaction/interaction-a11y-tooltip-no-interactive.yaml +23 -0
- package/data/rules/interaction/interaction-broken-focus-trap.yaml +25 -0
- package/data/rules/interaction/interaction-dont-block-paste-ime.yaml +23 -0
- package/data/rules/interaction/interaction-error-association.yaml +24 -0
- package/data/rules/interaction/interaction-focus-visible.yaml +25 -0
- package/data/rules/interaction/interaction-inline-errors-first-focus.yaml +24 -0
- package/data/rules/interaction/interaction-input-affix-hit-target.yaml +23 -0
- package/data/rules/interaction/interaction-keyboard-operable.yaml +23 -0
- package/data/rules/interaction/interaction-labels-and-autocomplete.yaml +23 -0
- package/data/rules/interaction/interaction-lost-data-on-error.yaml +23 -0
- package/data/rules/interaction/interaction-mobile-input-font-size.yaml +24 -0
- package/data/rules/interaction/interaction-no-disable-while-submitting.yaml +23 -0
- package/data/rules/interaction/interaction-no-empty-state.yaml +26 -0
- package/data/rules/interaction/interaction-no-error-boundary.yaml +27 -0
- package/data/rules/interaction/interaction-no-error-state.yaml +26 -0
- package/data/rules/interaction/interaction-no-suspense-boundary.yaml +23 -0
- package/data/rules/interaction/interaction-not-restored.yaml +25 -0
- package/data/rules/interaction/interaction-on-dynamic-content.yaml +25 -0
- package/data/rules/interaction/interaction-optimistic-without-rollback.yaml +23 -0
- package/data/rules/interaction/interaction-out-of-order-responses.yaml +27 -0
- package/data/rules/interaction/interaction-target-size.yaml +26 -0
- package/data/rules/interaction/interaction-use-form-status-misuse.yaml +23 -0
- package/data/rules/product/product-nested-modals.yaml +26 -0
- package/data/rules/product/product-select-for-few-options.yaml +24 -0
- package/data/rules/schema/rule.schema.json +262 -0
- package/data/rules/tuning.json +1 -0
- package/data/rules/typography/typography-dashes.yaml +28 -0
- package/data/rules/typography/typography-ellipsis.yaml +27 -0
- package/data/rules/typography/typography-hover-weight-shift.yaml +24 -0
- package/data/rules/typography/typography-midpoint-separators.yaml +21 -0
- package/data/rules/typography/typography-multiplication-sign.yaml +27 -0
- package/data/rules/typography/typography-nbsp-value-unit.yaml +27 -0
- package/data/rules/typography/typography-readable-scale.yaml +23 -0
- package/data/rules/typography/typography-straight-quotes.yaml +37 -0
- package/data/rules/typography/typography-title-case-heading.yaml +49 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +6317 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +736 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5330 -0
- package/dist/index.js.map +1 -0
- package/package.json +87 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,736 @@
|
|
|
1
|
+
//#region src/analysis/repository.d.ts
|
|
2
|
+
interface DocumentNode {
|
|
3
|
+
type: string;
|
|
4
|
+
value?: string;
|
|
5
|
+
url?: string;
|
|
6
|
+
identifier?: string;
|
|
7
|
+
depth?: number;
|
|
8
|
+
lang?: string | null;
|
|
9
|
+
children?: DocumentNode[];
|
|
10
|
+
position?: {
|
|
11
|
+
start: {
|
|
12
|
+
offset?: number;
|
|
13
|
+
};
|
|
14
|
+
end: {
|
|
15
|
+
offset?: number;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
interface ImportFact {
|
|
20
|
+
name: string;
|
|
21
|
+
offset: number;
|
|
22
|
+
typeOnly: boolean;
|
|
23
|
+
}
|
|
24
|
+
interface SourceFacts {
|
|
25
|
+
document?: DocumentNode;
|
|
26
|
+
imports?: ImportFact[];
|
|
27
|
+
parseError?: string;
|
|
28
|
+
repository: Pick<Repository, "root" | "read" | "resolve" | "exists" | "manifest" | "policy">;
|
|
29
|
+
}
|
|
30
|
+
declare class Repository {
|
|
31
|
+
readonly root: string;
|
|
32
|
+
private readonly contents;
|
|
33
|
+
readonly policy?: ArchitecturePolicy;
|
|
34
|
+
constructor(root: string, policy?: ArchitecturePolicy);
|
|
35
|
+
resolve(file: string, target: string): string | undefined;
|
|
36
|
+
read(file: string): string | undefined;
|
|
37
|
+
exists(file: string): boolean;
|
|
38
|
+
manifest(file: string): {
|
|
39
|
+
file: string;
|
|
40
|
+
value: Record<string, unknown>;
|
|
41
|
+
} | undefined;
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/types.d.ts
|
|
45
|
+
declare const DOMAINS: readonly ["typography", "craft", "copywriting", "interaction", "motion", "product", "architecture", "dx", "authoring"];
|
|
46
|
+
type Domain = (typeof DOMAINS)[number];
|
|
47
|
+
declare const UNIT_KINDS: readonly ["paragraph", "heading", "jsx-text", "attr-string", "class-list", "element",
|
|
48
|
+
/** The whole file, for mechanical-only regex rules over raw source. */
|
|
49
|
+
"source",
|
|
50
|
+
/** A file that did not parse; carries the error and nothing else. */
|
|
51
|
+
"file"];
|
|
52
|
+
/** Kinds that are not a piece of copy and never count as units in a report. */
|
|
53
|
+
declare const STRUCTURAL_KINDS: readonly UnitKind[];
|
|
54
|
+
type UnitKind = (typeof UNIT_KINDS)[number];
|
|
55
|
+
declare const TIERS: readonly ["mechanical", "jev", "both"];
|
|
56
|
+
type Tier = (typeof TIERS)[number];
|
|
57
|
+
declare const SEVERITIES: readonly ["major", "minor"];
|
|
58
|
+
type Severity = (typeof SEVERITIES)[number];
|
|
59
|
+
/** Lower is more severe; the single owner of severity ordering. */
|
|
60
|
+
declare const SEVERITY_RANK: Record<Severity, number>;
|
|
61
|
+
declare const RULE_STATUSES: readonly ["active", "draft", "review-only"];
|
|
62
|
+
type RuleStatus = (typeof RULE_STATUSES)[number];
|
|
63
|
+
declare const DOC_TYPES: readonly ["tutorial", "howto", "reference", "explanation", "agent-instructions", "lesson", "marketing", "ui", "readme", "skill", "plan", "personal", "pr", "slides", "unknown"];
|
|
64
|
+
type DocType = (typeof DOC_TYPES)[number];
|
|
65
|
+
declare const ROLES: readonly ["heading", "body", "list-item", "cell", "button", "link", "label", "placeholder", "aria", "literal-copy", "caption", "unknown"];
|
|
66
|
+
type Role = (typeof ROLES)[number];
|
|
67
|
+
declare const CONTEXT_KEYS: readonly ["section", "headingAbove", "docType", "element", "role", "neighbours", "writingFacts", "writingProfile", "writingInstructions"];
|
|
68
|
+
type ContextKey = (typeof CONTEXT_KEYS)[number];
|
|
69
|
+
type Band = "act" | "review" | "silent";
|
|
70
|
+
interface RuleSource {
|
|
71
|
+
repo: string;
|
|
72
|
+
path: string;
|
|
73
|
+
line: number;
|
|
74
|
+
ruleId?: string;
|
|
75
|
+
}
|
|
76
|
+
interface Mechanical {
|
|
77
|
+
/** JavaScript regex source. Compiled with `flags` (default "gu"). */
|
|
78
|
+
regex?: string;
|
|
79
|
+
flags?: string;
|
|
80
|
+
/** Case-insensitive whole-phrase list. Word-boundary checked. */
|
|
81
|
+
phrases?: string[];
|
|
82
|
+
/** Minimum matches before the rule fires (default 1). */
|
|
83
|
+
minMatches?: number;
|
|
84
|
+
/** The rule fires only when this regex matches nowhere in the unit. */
|
|
85
|
+
absent?: string;
|
|
86
|
+
}
|
|
87
|
+
interface CriterionSide {
|
|
88
|
+
what: string;
|
|
89
|
+
examples: string[];
|
|
90
|
+
}
|
|
91
|
+
interface Question {
|
|
92
|
+
instructions: string;
|
|
93
|
+
criteria?: {
|
|
94
|
+
true: CriterionSide;
|
|
95
|
+
false: CriterionSide;
|
|
96
|
+
};
|
|
97
|
+
/** Context keys to include in the state for this question. */
|
|
98
|
+
context?: ContextKey[];
|
|
99
|
+
}
|
|
100
|
+
interface Thresholds {
|
|
101
|
+
review: number;
|
|
102
|
+
act: number;
|
|
103
|
+
}
|
|
104
|
+
interface Fix {
|
|
105
|
+
hint: string;
|
|
106
|
+
/** Named function in src/reduce/fixes.ts; present means `--fix` can apply it. */
|
|
107
|
+
function?: string;
|
|
108
|
+
}
|
|
109
|
+
interface Preconditions {
|
|
110
|
+
notInCode?: boolean;
|
|
111
|
+
docType?: DocType[];
|
|
112
|
+
role?: Role[];
|
|
113
|
+
/** Skip Markdown units when the project curls quotes at build time. */
|
|
114
|
+
smartQuotesAtBuild?: false;
|
|
115
|
+
}
|
|
116
|
+
interface Rule {
|
|
117
|
+
id: string;
|
|
118
|
+
title: string;
|
|
119
|
+
categoryId: string;
|
|
120
|
+
domain: Domain;
|
|
121
|
+
source: RuleSource;
|
|
122
|
+
/** Resolved: include derived from `unit` unless the rule names it. */
|
|
123
|
+
scope: {
|
|
124
|
+
include: string[];
|
|
125
|
+
exclude: string[];
|
|
126
|
+
};
|
|
127
|
+
unit: UnitKind[];
|
|
128
|
+
/** Derived: mechanical only, question only, or both. */
|
|
129
|
+
tier: Tier;
|
|
130
|
+
mechanical?: Mechanical;
|
|
131
|
+
question?: Question;
|
|
132
|
+
thresholds: Thresholds;
|
|
133
|
+
severity: Severity;
|
|
134
|
+
fix: Fix;
|
|
135
|
+
preconditions?: Preconditions;
|
|
136
|
+
status: RuleStatus;
|
|
137
|
+
handWritten: string[];
|
|
138
|
+
/** Absolute path of the YAML file the rule was loaded from, or `code:<module>`. */
|
|
139
|
+
file: string;
|
|
140
|
+
/**
|
|
141
|
+
* A code rule's check, in place of `mechanical`. Counts, compares and
|
|
142
|
+
* measures; throws UnresolvedError to abstain. Data rules never set it.
|
|
143
|
+
*/
|
|
144
|
+
check?: (unit: Unit) => MechanicalHit;
|
|
145
|
+
}
|
|
146
|
+
interface TuningEntry {
|
|
147
|
+
act?: number;
|
|
148
|
+
status?: RuleStatus;
|
|
149
|
+
precisionLower?: number;
|
|
150
|
+
n?: number;
|
|
151
|
+
ts?: string;
|
|
152
|
+
}
|
|
153
|
+
type Tuning = Record<string, TuningEntry>;
|
|
154
|
+
interface ResolvedTypography {
|
|
155
|
+
fontSizePx?: number;
|
|
156
|
+
lineHeight?: number;
|
|
157
|
+
lineHeightPx?: number;
|
|
158
|
+
letterSpacingEm?: number;
|
|
159
|
+
fontWeight?: number;
|
|
160
|
+
uppercase?: boolean;
|
|
161
|
+
italic?: boolean;
|
|
162
|
+
family?: "mono" | "sans" | "serif";
|
|
163
|
+
colourClasses: string[];
|
|
164
|
+
unresolved: string[];
|
|
165
|
+
}
|
|
166
|
+
interface NeighbourSummary {
|
|
167
|
+
text: string;
|
|
168
|
+
element?: string;
|
|
169
|
+
typography?: ResolvedTypography;
|
|
170
|
+
}
|
|
171
|
+
interface WritingContext {
|
|
172
|
+
facts?: string;
|
|
173
|
+
profile?: string;
|
|
174
|
+
instructions?: string;
|
|
175
|
+
}
|
|
176
|
+
interface UnitContext {
|
|
177
|
+
section?: string;
|
|
178
|
+
writingFacts?: string;
|
|
179
|
+
writingProfile?: string;
|
|
180
|
+
writingInstructions?: string;
|
|
181
|
+
headingAbove?: string;
|
|
182
|
+
docType: DocType;
|
|
183
|
+
element?: string;
|
|
184
|
+
attr?: string;
|
|
185
|
+
component?: string;
|
|
186
|
+
role: Role;
|
|
187
|
+
/** The className has parts this extractor could not read statically. */
|
|
188
|
+
dynamic?: boolean;
|
|
189
|
+
/** The className is a template literal with `${...}` inside a class. */
|
|
190
|
+
interpolated?: boolean;
|
|
191
|
+
parseError?: string;
|
|
192
|
+
mdxFallback?: boolean;
|
|
193
|
+
}
|
|
194
|
+
interface Unit {
|
|
195
|
+
facts?: SourceFacts;
|
|
196
|
+
/** Stable hash of file, kind and source offset. */
|
|
197
|
+
id: string;
|
|
198
|
+
kind: UnitKind;
|
|
199
|
+
/** Normalised rendered text, whitespace collapsed. */
|
|
200
|
+
text: string;
|
|
201
|
+
/** Relative to the scanned root, forward slashes. */
|
|
202
|
+
file: string;
|
|
203
|
+
line: number;
|
|
204
|
+
column: number;
|
|
205
|
+
endLine: number;
|
|
206
|
+
endColumn: number;
|
|
207
|
+
sourceStart: number;
|
|
208
|
+
sourceEnd: number;
|
|
209
|
+
inCode: boolean;
|
|
210
|
+
/** Ranges inside `text` that are code and must be skipped by regexes. */
|
|
211
|
+
codeSpans: [number, number][];
|
|
212
|
+
/**
|
|
213
|
+
* Source ranges (UTF-16 offsets into the file) holding prose a
|
|
214
|
+
* deterministic fix may rewrite: JSX text pieces, the inside of string
|
|
215
|
+
* literals, Markdown text nodes. Never quotes, braces, inline code or
|
|
216
|
+
* expressions. Absent means the unit cannot be fixed in place.
|
|
217
|
+
*/
|
|
218
|
+
fixRanges?: [number, number][];
|
|
219
|
+
context: UnitContext;
|
|
220
|
+
typography?: ResolvedTypography;
|
|
221
|
+
neighbours?: {
|
|
222
|
+
prev?: NeighbourSummary;
|
|
223
|
+
next?: NeighbourSummary;
|
|
224
|
+
};
|
|
225
|
+
/** Class list for class-list and element units. */
|
|
226
|
+
classes?: string[];
|
|
227
|
+
}
|
|
228
|
+
interface MechanicalHit {
|
|
229
|
+
fired: boolean;
|
|
230
|
+
evidence: string;
|
|
231
|
+
/** Offset into `unit.text` of the first match; a source unit's finding line. */
|
|
232
|
+
offset?: number;
|
|
233
|
+
}
|
|
234
|
+
interface Finding {
|
|
235
|
+
ruleId: string;
|
|
236
|
+
categoryId: string;
|
|
237
|
+
domain: Domain;
|
|
238
|
+
severity: Severity;
|
|
239
|
+
band: Band;
|
|
240
|
+
probability: number;
|
|
241
|
+
tier: Tier;
|
|
242
|
+
unitId: string;
|
|
243
|
+
file: string;
|
|
244
|
+
line: number;
|
|
245
|
+
column: number;
|
|
246
|
+
endLine: number;
|
|
247
|
+
endColumn: number;
|
|
248
|
+
message: string;
|
|
249
|
+
evidence: string;
|
|
250
|
+
fixHint: string;
|
|
251
|
+
suppressed: boolean;
|
|
252
|
+
also?: string[];
|
|
253
|
+
}
|
|
254
|
+
interface Unknown {
|
|
255
|
+
ruleId: string;
|
|
256
|
+
unitId: string;
|
|
257
|
+
file: string;
|
|
258
|
+
line: number;
|
|
259
|
+
reason: string;
|
|
260
|
+
}
|
|
261
|
+
interface Scorecard {
|
|
262
|
+
byCategory: Record<string, {
|
|
263
|
+
domain: Domain;
|
|
264
|
+
units: number;
|
|
265
|
+
act: number;
|
|
266
|
+
review: number;
|
|
267
|
+
suppressed: number;
|
|
268
|
+
unknown: number;
|
|
269
|
+
}>;
|
|
270
|
+
byDomain: Record<string, {
|
|
271
|
+
units: number;
|
|
272
|
+
act: number;
|
|
273
|
+
review: number;
|
|
274
|
+
suppressed: number;
|
|
275
|
+
unknown: number;
|
|
276
|
+
}>;
|
|
277
|
+
byRule: Record<string, {
|
|
278
|
+
act: number;
|
|
279
|
+
review: number;
|
|
280
|
+
silent: number;
|
|
281
|
+
unknown: number;
|
|
282
|
+
}>;
|
|
283
|
+
}
|
|
284
|
+
interface Progress {
|
|
285
|
+
phase: "evaluating" | "complete";
|
|
286
|
+
completed: number;
|
|
287
|
+
planned: number;
|
|
288
|
+
cachedAnswers: number;
|
|
289
|
+
failed: number;
|
|
290
|
+
attempts: number;
|
|
291
|
+
elapsedMs: number;
|
|
292
|
+
}
|
|
293
|
+
interface Usage {
|
|
294
|
+
/** HTTP attempts when reported by the evaluator; absent for legacy evaluators. */
|
|
295
|
+
attempts?: number;
|
|
296
|
+
sharedAnswers?: number;
|
|
297
|
+
requests: number;
|
|
298
|
+
cached: number;
|
|
299
|
+
inputTokens: number;
|
|
300
|
+
costUsd: number;
|
|
301
|
+
errors: number;
|
|
302
|
+
}
|
|
303
|
+
type RunStatus = "complete" | "incomplete" | "dry-run";
|
|
304
|
+
interface RunSummary {
|
|
305
|
+
act: number;
|
|
306
|
+
review: number;
|
|
307
|
+
unknown: number;
|
|
308
|
+
failing: number;
|
|
309
|
+
failOn: Severity;
|
|
310
|
+
ruleFindings: number;
|
|
311
|
+
}
|
|
312
|
+
interface Coverage {
|
|
313
|
+
byRule: Record<string, {
|
|
314
|
+
eligible: number;
|
|
315
|
+
skipped: number;
|
|
316
|
+
negative: number;
|
|
317
|
+
pending: number;
|
|
318
|
+
unknown: number;
|
|
319
|
+
answered: number;
|
|
320
|
+
}>;
|
|
321
|
+
byCategory: Record<string, {
|
|
322
|
+
eligibleUnits: number;
|
|
323
|
+
eligiblePairs: number;
|
|
324
|
+
}>;
|
|
325
|
+
}
|
|
326
|
+
interface ScanScope {
|
|
327
|
+
files: number;
|
|
328
|
+
units: number;
|
|
329
|
+
byDocType: Record<string, number>;
|
|
330
|
+
excluded: number;
|
|
331
|
+
diagnostics: string[];
|
|
332
|
+
}
|
|
333
|
+
interface LintResult {
|
|
334
|
+
summary?: RunSummary;
|
|
335
|
+
ruleFindings?: Finding[];
|
|
336
|
+
ruleScorecard?: Scorecard;
|
|
337
|
+
coverage?: Coverage;
|
|
338
|
+
scope?: ScanScope;
|
|
339
|
+
reportPath?: string;
|
|
340
|
+
rerun?: string;
|
|
341
|
+
status: RunStatus;
|
|
342
|
+
findings: Finding[];
|
|
343
|
+
unknowns: Unknown[];
|
|
344
|
+
scorecard: Scorecard;
|
|
345
|
+
usage: Usage;
|
|
346
|
+
units: number;
|
|
347
|
+
rules: string[];
|
|
348
|
+
estimated?: {
|
|
349
|
+
requests: number;
|
|
350
|
+
inputTokens: number;
|
|
351
|
+
costUsd: number;
|
|
352
|
+
};
|
|
353
|
+
exitCode: number;
|
|
354
|
+
}
|
|
355
|
+
type EntryValue = string | number | boolean | null | EntryValue[] | {
|
|
356
|
+
[key: string]: EntryValue;
|
|
357
|
+
};
|
|
358
|
+
interface SystemOneNoul {
|
|
359
|
+
type: "noul";
|
|
360
|
+
instructions: EntryValue;
|
|
361
|
+
criteria?: {
|
|
362
|
+
true?: EntryValue;
|
|
363
|
+
false?: EntryValue;
|
|
364
|
+
} | null;
|
|
365
|
+
}
|
|
366
|
+
interface SystemOneRequest {
|
|
367
|
+
model: string;
|
|
368
|
+
state: EntryValue;
|
|
369
|
+
questions: Record<string, SystemOneNoul>;
|
|
370
|
+
}
|
|
371
|
+
interface SystemOneResponse {
|
|
372
|
+
attempts?: number;
|
|
373
|
+
model: string;
|
|
374
|
+
answers: Record<string, {
|
|
375
|
+
type?: string;
|
|
376
|
+
noul?: number;
|
|
377
|
+
}>;
|
|
378
|
+
usage: {
|
|
379
|
+
input_tokens: number;
|
|
380
|
+
output_tokens: number;
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
type Evaluate = (request: SystemOneRequest, onAttempt?: () => void) => Promise<SystemOneResponse>;
|
|
384
|
+
interface RecorderHandle {
|
|
385
|
+
append: (record: Record<string, unknown>) => Record<string, unknown>;
|
|
386
|
+
summary: (obj: Record<string, unknown>) => Record<string, unknown>;
|
|
387
|
+
file: string;
|
|
388
|
+
}
|
|
389
|
+
interface CorpusItem {
|
|
390
|
+
id: string;
|
|
391
|
+
kind: UnitKind;
|
|
392
|
+
text: string;
|
|
393
|
+
context?: Partial<UnitContext>;
|
|
394
|
+
neighbours?: Unit["neighbours"];
|
|
395
|
+
classes?: string[];
|
|
396
|
+
categoryId: string;
|
|
397
|
+
labels: Record<string, boolean>;
|
|
398
|
+
labelSource: "manifest" | "manifest-weak" | "hand" | "sweep" | "ai";
|
|
399
|
+
labelModel?: string;
|
|
400
|
+
labelPromptHash?: string;
|
|
401
|
+
source: {
|
|
402
|
+
repo: string;
|
|
403
|
+
path: string;
|
|
404
|
+
id?: string;
|
|
405
|
+
option?: string;
|
|
406
|
+
};
|
|
407
|
+
split: "dev" | "holdout";
|
|
408
|
+
}
|
|
409
|
+
interface ArchitecturePolicy {
|
|
410
|
+
boundaries?: {
|
|
411
|
+
from: string;
|
|
412
|
+
disallow: string;
|
|
413
|
+
reason: string;
|
|
414
|
+
}[];
|
|
415
|
+
deprecatedImports?: Record<string, string>;
|
|
416
|
+
generated?: string[];
|
|
417
|
+
}
|
|
418
|
+
interface Config {
|
|
419
|
+
architecture?: ArchitecturePolicy;
|
|
420
|
+
root: string;
|
|
421
|
+
docTypes: {
|
|
422
|
+
glob: string;
|
|
423
|
+
type: DocType;
|
|
424
|
+
}[];
|
|
425
|
+
components: {
|
|
426
|
+
unwrap: string[];
|
|
427
|
+
skip: string[];
|
|
428
|
+
};
|
|
429
|
+
tailwind: {
|
|
430
|
+
theme: Record<string, string>;
|
|
431
|
+
};
|
|
432
|
+
smartQuotesAtBuild: boolean;
|
|
433
|
+
exclude: string[];
|
|
434
|
+
}
|
|
435
|
+
//#endregion
|
|
436
|
+
//#region src/lib/config.d.ts
|
|
437
|
+
declare const loadConfig: (root: string, defaults?: Config["docTypes"]) => Config;
|
|
438
|
+
//#endregion
|
|
439
|
+
//#region src/lint.d.ts
|
|
440
|
+
interface LintOptions {
|
|
441
|
+
docTypes?: {
|
|
442
|
+
glob: string;
|
|
443
|
+
type: DocType;
|
|
444
|
+
}[];
|
|
445
|
+
advisoryRules?: string[];
|
|
446
|
+
writingContext?: WritingContext;
|
|
447
|
+
root: string;
|
|
448
|
+
targets: string[];
|
|
449
|
+
rulesDir?: string;
|
|
450
|
+
only?: string[];
|
|
451
|
+
exclude?: string[];
|
|
452
|
+
dryRun?: boolean;
|
|
453
|
+
printRequests?: boolean;
|
|
454
|
+
mechanicalOnly?: boolean;
|
|
455
|
+
noCache?: boolean;
|
|
456
|
+
limitUnits?: number;
|
|
457
|
+
failOn?: Severity;
|
|
458
|
+
fix?: boolean;
|
|
459
|
+
resultsDir?: string;
|
|
460
|
+
model?: string;
|
|
461
|
+
apiKey?: string;
|
|
462
|
+
/** Extra units supplied by the caller (rendered mode). */
|
|
463
|
+
extraUnits?: Unit[];
|
|
464
|
+
}
|
|
465
|
+
interface LintContext {
|
|
466
|
+
evaluate?: Evaluate;
|
|
467
|
+
stdout?: (text: string) => void;
|
|
468
|
+
stderr?: (text: string) => void;
|
|
469
|
+
onProgress?: (progress: Progress) => void;
|
|
470
|
+
onEvidence?: (units: Unit[], answers: Map<string, Record<string, number>>, negatives: Map<string, Set<string>>) => void;
|
|
471
|
+
}
|
|
472
|
+
declare const runLint: (options: LintOptions, ctx?: LintContext) => Promise<LintResult & {
|
|
473
|
+
rulesLoaded: Rule[];
|
|
474
|
+
units: number;
|
|
475
|
+
manifest: Record<string, unknown>;
|
|
476
|
+
}>;
|
|
477
|
+
//#endregion
|
|
478
|
+
//#region src/rules/load.d.ts
|
|
479
|
+
declare const resolveRulesDir: (explicit?: string) => string;
|
|
480
|
+
interface LoadOptions {
|
|
481
|
+
/** Include rules with status draft (default false). */
|
|
482
|
+
allowDraft?: boolean;
|
|
483
|
+
/** Restrict to these rule ids. */
|
|
484
|
+
only?: string[];
|
|
485
|
+
}
|
|
486
|
+
declare const loadRules: (rulesDir: string, options?: LoadOptions) => Rule[];
|
|
487
|
+
//#endregion
|
|
488
|
+
//#region src/rules/validate.d.ts
|
|
489
|
+
declare const validateRule: (raw: unknown, file: string, expectedId: string) => Rule;
|
|
490
|
+
//#endregion
|
|
491
|
+
//#region src/rules/taxonomy.d.ts
|
|
492
|
+
interface Category {
|
|
493
|
+
id: string;
|
|
494
|
+
domain: Domain;
|
|
495
|
+
label: string;
|
|
496
|
+
}
|
|
497
|
+
declare const CATEGORIES: readonly Category[];
|
|
498
|
+
declare const CATEGORY_BY_ID: ReadonlyMap<string, Category>;
|
|
499
|
+
//#endregion
|
|
500
|
+
//#region src/extract/index.d.ts
|
|
501
|
+
declare const extractFile: (config: Config, relativeFile: string) => Unit[];
|
|
502
|
+
//#endregion
|
|
503
|
+
//#region src/extract/tsx.d.ts
|
|
504
|
+
interface TsxExtractOptions {
|
|
505
|
+
config: Config;
|
|
506
|
+
docType: DocType;
|
|
507
|
+
}
|
|
508
|
+
declare const extractTsx: (file: string, source: string, options: TsxExtractOptions) => Unit[];
|
|
509
|
+
//#endregion
|
|
510
|
+
//#region src/extract/capture.d.ts
|
|
511
|
+
interface BoundingBox {
|
|
512
|
+
bottom: number;
|
|
513
|
+
height: number;
|
|
514
|
+
left: number;
|
|
515
|
+
right: number;
|
|
516
|
+
top: number;
|
|
517
|
+
width: number;
|
|
518
|
+
x: number;
|
|
519
|
+
y: number;
|
|
520
|
+
}
|
|
521
|
+
interface ElementSnapshot {
|
|
522
|
+
attributes: Record<string, string>;
|
|
523
|
+
boundingBox: BoundingBox;
|
|
524
|
+
children: string[];
|
|
525
|
+
classList: string[];
|
|
526
|
+
id: string;
|
|
527
|
+
parentId: string | null;
|
|
528
|
+
selector: string;
|
|
529
|
+
styles: Record<string, string>;
|
|
530
|
+
tagName: string;
|
|
531
|
+
text?: string;
|
|
532
|
+
}
|
|
533
|
+
interface CaptureResult {
|
|
534
|
+
elements: Record<string, ElementSnapshot>;
|
|
535
|
+
metadata: {
|
|
536
|
+
url: string;
|
|
537
|
+
title?: string;
|
|
538
|
+
capturedAt?: string;
|
|
539
|
+
};
|
|
540
|
+
order: string[];
|
|
541
|
+
rootElementId: string;
|
|
542
|
+
rootOuterHtml: string;
|
|
543
|
+
settings?: unknown;
|
|
544
|
+
version: 1;
|
|
545
|
+
}
|
|
546
|
+
//#endregion
|
|
547
|
+
//#region src/extract/rendered.d.ts
|
|
548
|
+
declare const extractCapture: (raw: CaptureResult, label: string) => Unit[];
|
|
549
|
+
declare const runStyleCapture: (url: string, selector: string) => Promise<CaptureResult>;
|
|
550
|
+
//#endregion
|
|
551
|
+
//#region src/extract/style-capture-text.d.ts
|
|
552
|
+
declare const parseCaptureInput: (raw: string) => CaptureResult;
|
|
553
|
+
//#endregion
|
|
554
|
+
//#region src/map/jev.d.ts
|
|
555
|
+
type Transport = "typesafe" | "gateway";
|
|
556
|
+
declare class ProviderError extends Error {
|
|
557
|
+
readonly category: "provider_error" | "invalid_response" | "timeout" | "auth";
|
|
558
|
+
readonly status?: number | undefined;
|
|
559
|
+
constructor(category: "provider_error" | "invalid_response" | "timeout" | "auth", status?: number | undefined);
|
|
560
|
+
}
|
|
561
|
+
interface FetchEvaluateOptions {
|
|
562
|
+
apiKey: string;
|
|
563
|
+
transport?: Transport;
|
|
564
|
+
baseUrl?: string;
|
|
565
|
+
fetch?: typeof globalThis.fetch;
|
|
566
|
+
timeoutMs?: number;
|
|
567
|
+
retries?: number;
|
|
568
|
+
/** Sleep hook so tests can run without waiting. */
|
|
569
|
+
sleep?: (ms: number) => Promise<void>;
|
|
570
|
+
}
|
|
571
|
+
declare const makeFetchEvaluate: (options: FetchEvaluateOptions) => Evaluate;
|
|
572
|
+
//#endregion
|
|
573
|
+
//#region src/report/json.d.ts
|
|
574
|
+
declare const renderJson: (result: LintResult, manifest: Record<string, unknown>) => string;
|
|
575
|
+
//#endregion
|
|
576
|
+
//#region src/report/sarif.d.ts
|
|
577
|
+
declare const renderSarif: (result: Pick<LintResult, "findings" | "ruleFindings">, rules: Rule[], version: string) => string;
|
|
578
|
+
//#endregion
|
|
579
|
+
//#region src/report/tty.d.ts
|
|
580
|
+
declare const renderTty: (result: LintResult, options?: {
|
|
581
|
+
verbose?: boolean;
|
|
582
|
+
}) => string;
|
|
583
|
+
//#endregion
|
|
584
|
+
//#region src/lib/stats.d.ts
|
|
585
|
+
interface BinaryMetrics {
|
|
586
|
+
tp: number;
|
|
587
|
+
fp: number;
|
|
588
|
+
fn: number;
|
|
589
|
+
tn: number;
|
|
590
|
+
precision: number;
|
|
591
|
+
recall: number;
|
|
592
|
+
f1: number;
|
|
593
|
+
precisionCI: [number, number];
|
|
594
|
+
recallCI: [number, number];
|
|
595
|
+
}
|
|
596
|
+
declare const calibrationTable: (pairs: {
|
|
597
|
+
label: boolean;
|
|
598
|
+
probability: number;
|
|
599
|
+
}[], buckets?: number) => {
|
|
600
|
+
lo: number;
|
|
601
|
+
hi: number;
|
|
602
|
+
n: number;
|
|
603
|
+
positives: number;
|
|
604
|
+
meanP: number;
|
|
605
|
+
}[];
|
|
606
|
+
//#endregion
|
|
607
|
+
//#region src/eval/coverage.d.ts
|
|
608
|
+
declare const corpusCoverage: (items: CorpusItem[], rules: Rule[]) => {
|
|
609
|
+
items: number;
|
|
610
|
+
labelSources: {
|
|
611
|
+
[k: string]: number;
|
|
612
|
+
};
|
|
613
|
+
overlappingSources: [string, string][];
|
|
614
|
+
overlappingTexts: number;
|
|
615
|
+
rules: {
|
|
616
|
+
negative: number;
|
|
617
|
+
positive: number;
|
|
618
|
+
dev: {
|
|
619
|
+
negative: number;
|
|
620
|
+
positive: number;
|
|
621
|
+
};
|
|
622
|
+
documentTypes: ("agent-instructions" | "explanation" | "howto" | "lesson" | "marketing" | "personal" | "plan" | "pr" | "readme" | "reference" | "skill" | "slides" | "tutorial" | "ui" | "unknown")[];
|
|
623
|
+
holdout: {
|
|
624
|
+
negative: number;
|
|
625
|
+
positive: number;
|
|
626
|
+
};
|
|
627
|
+
repositories: string[];
|
|
628
|
+
ruleId: string;
|
|
629
|
+
}[];
|
|
630
|
+
};
|
|
631
|
+
//#endregion
|
|
632
|
+
//#region src/eval/metrics.d.ts
|
|
633
|
+
interface EvalOptions {
|
|
634
|
+
corpusDir?: string;
|
|
635
|
+
rulesDir?: string;
|
|
636
|
+
only?: string[];
|
|
637
|
+
split?: "dev" | "holdout" | "all";
|
|
638
|
+
includeWeak?: boolean;
|
|
639
|
+
dryRun?: boolean;
|
|
640
|
+
noCache?: boolean;
|
|
641
|
+
resultsDir?: string;
|
|
642
|
+
model?: string;
|
|
643
|
+
apiKey?: string;
|
|
644
|
+
}
|
|
645
|
+
interface EvalContext {
|
|
646
|
+
evaluate?: Evaluate;
|
|
647
|
+
}
|
|
648
|
+
interface RuleEval {
|
|
649
|
+
ruleId: string;
|
|
650
|
+
n: number;
|
|
651
|
+
/** Labelled items the rule could not judge (unresolved value, failed request). */
|
|
652
|
+
unknown: number;
|
|
653
|
+
skipped?: number;
|
|
654
|
+
metrics: BinaryMetrics;
|
|
655
|
+
reviewRate: number;
|
|
656
|
+
calibration: ReturnType<typeof calibrationTable>;
|
|
657
|
+
/** Per item: label, probability. */
|
|
658
|
+
pairs: {
|
|
659
|
+
id: string;
|
|
660
|
+
label: boolean;
|
|
661
|
+
probability: number;
|
|
662
|
+
}[];
|
|
663
|
+
}
|
|
664
|
+
interface EvalResult {
|
|
665
|
+
referenceCoverage?: ReturnType<typeof corpusCoverage>;
|
|
666
|
+
labelSources?: Record<string, number>;
|
|
667
|
+
report: string;
|
|
668
|
+
exitCode: number;
|
|
669
|
+
rules: RuleEval[];
|
|
670
|
+
usage: {
|
|
671
|
+
requests: number;
|
|
672
|
+
cached: number;
|
|
673
|
+
inputTokens: number;
|
|
674
|
+
costUsd: number;
|
|
675
|
+
errors: number;
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
declare const runEval: (options: EvalOptions, ctx?: EvalContext) => Promise<EvalResult>;
|
|
679
|
+
//#endregion
|
|
680
|
+
//#region src/eval/corpus.d.ts
|
|
681
|
+
declare const splitFor: (id: string) => "dev" | "holdout";
|
|
682
|
+
//#endregion
|
|
683
|
+
//#region src/eval/promotion.d.ts
|
|
684
|
+
interface PromotionEvidence {
|
|
685
|
+
eligible: boolean;
|
|
686
|
+
n: number;
|
|
687
|
+
precisionLower: number;
|
|
688
|
+
reason: string;
|
|
689
|
+
}
|
|
690
|
+
//#endregion
|
|
691
|
+
//#region src/eval/tune.d.ts
|
|
692
|
+
interface TuneOptions {
|
|
693
|
+
corpusDir?: string;
|
|
694
|
+
rulesDir?: string;
|
|
695
|
+
only?: string[];
|
|
696
|
+
floor?: number;
|
|
697
|
+
write?: boolean;
|
|
698
|
+
resultsDir?: string;
|
|
699
|
+
model?: string;
|
|
700
|
+
apiKey?: string;
|
|
701
|
+
minItems?: number;
|
|
702
|
+
}
|
|
703
|
+
interface TuneContext {
|
|
704
|
+
evaluate?: Evaluate;
|
|
705
|
+
}
|
|
706
|
+
interface TuneDecision {
|
|
707
|
+
ruleId: string;
|
|
708
|
+
validation?: PromotionEvidence;
|
|
709
|
+
n: number;
|
|
710
|
+
current: number;
|
|
711
|
+
chosen: number | null;
|
|
712
|
+
precisionLower: number;
|
|
713
|
+
recall: number;
|
|
714
|
+
action: "keep" | "raise" | "lower" | "demote" | "insufficient";
|
|
715
|
+
}
|
|
716
|
+
declare const runTune: (options: TuneOptions, ctx?: TuneContext) => Promise<{
|
|
717
|
+
report: string;
|
|
718
|
+
exitCode: number;
|
|
719
|
+
decisions: TuneDecision[];
|
|
720
|
+
}>;
|
|
721
|
+
interface TuneAbOptions {
|
|
722
|
+
ruleId: string;
|
|
723
|
+
variantFile: string;
|
|
724
|
+
corpusDir?: string;
|
|
725
|
+
rulesDir?: string;
|
|
726
|
+
resultsDir?: string;
|
|
727
|
+
model?: string;
|
|
728
|
+
apiKey?: string;
|
|
729
|
+
}
|
|
730
|
+
declare const runTuneAb: (options: TuneAbOptions, ctx?: TuneContext) => Promise<{
|
|
731
|
+
report: string;
|
|
732
|
+
exitCode: number;
|
|
733
|
+
}>;
|
|
734
|
+
//#endregion
|
|
735
|
+
export { type ArchitecturePolicy, type Band, CATEGORIES, CATEGORY_BY_ID, type CONTEXT_KEYS, type Config, type ContextKey, type CorpusItem, type Coverage, type CriterionSide, type DOC_TYPES, type DOMAINS, type DocType, type Domain, type EntryValue, type Evaluate, type Finding, type Fix, type LintContext, type LintOptions, type LintResult, type Mechanical, type MechanicalHit, type NeighbourSummary, type Preconditions, type Progress, ProviderError, type Question, type ROLES, type RULE_STATUSES, type RecorderHandle, type ResolvedTypography, type Role, type Rule, type RuleSource, type RuleStatus, type RunStatus, type RunSummary, type SEVERITIES, type SEVERITY_RANK, type STRUCTURAL_KINDS, type ScanScope, type Scorecard, type Severity, type SystemOneNoul, type SystemOneRequest, type SystemOneResponse, type TIERS, type Thresholds, type Tier, type Tuning, type TuningEntry, type UNIT_KINDS, type Unit, type UnitContext, type UnitKind, type Unknown, type Usage, type WritingContext, extractCapture, extractFile, extractTsx, loadConfig, loadRules, makeFetchEvaluate, parseCaptureInput, renderJson, renderSarif, renderTty, resolveRulesDir, runEval, runLint, runStyleCapture, runTune, runTuneAb, splitFor, validateRule };
|
|
736
|
+
//# sourceMappingURL=index.d.ts.map
|