@templatical/quality 0.8.0 → 0.8.2

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/dist/index.d.ts CHANGED
@@ -1,11 +1,16 @@
1
- import { Block } from '../../types/src/index.ts';
2
- import { SectionBlock } from '../../types/src/index.ts';
3
- import { TemplateContent } from '../../../types/src/index.ts';
4
- import { TemplateContent as TemplateContent_2 } from '../../types/src/index.ts';
5
- import { TemplateSettings } from '../../types/src/index.ts';
1
+ import type { Block } from '@templatical/types';
2
+ import type { SectionBlock } from '@templatical/types';
3
+ import type { TemplateContent } from '@templatical/types';
4
+ import type { TemplateSettings } from '@templatical/types';
6
5
 
7
6
  export declare const ACCESSIBILITY_RULES: Rule[];
8
7
 
8
+ /** Options consumed only by the accessibility linter. */
9
+ export declare interface AccessibilityLintOptions {
10
+ rules?: RuleOverrides;
11
+ thresholds?: Partial<LintThresholds>;
12
+ }
13
+
9
14
  export declare interface AnchorInfo {
10
15
  href: string;
11
16
  text: string;
@@ -58,6 +63,7 @@ declare const en_2: {
58
63
  "a11y.link-vague-text": string;
59
64
  "a11y.link-href-empty": string;
60
65
  "a11y.link-target-blank-no-rel": string;
66
+ "a11y.link-nested-anchor": string;
61
67
  "a11y.text-all-caps": string;
62
68
  "a11y.text-low-contrast": string;
63
69
  "a11y.text-too-small": string;
@@ -99,6 +105,15 @@ declare const en_4: {
99
105
  * Extract every anchor from a TipTap-style HTML fragment. Used by
100
106
  * link-* rules. Doesn't try to be a full DOM — only the data the rules
101
107
  * need.
108
+ *
109
+ * Nested `<a>` is invalid HTML; htmlparser2 follows the HTML5 spec and
110
+ * emits an implicit `</a>` when a second `<a>` opens, so anchors are
111
+ * effectively flat siblings. We mirror that with a single in-flight
112
+ * anchor (no stack); a defensive finalize-on-reopen handles the
113
+ * theoretical case where the parser ever stops emitting the implicit
114
+ * close. Detecting nested-anchor markup as its own concern lives in
115
+ * the `a11y.link-nested-anchor` rule, which inspects the raw input
116
+ * before this normalization.
102
117
  */
103
118
  export declare function extractAnchors(html: string): AnchorInfo[];
104
119
 
@@ -148,6 +163,30 @@ export declare function getMessages(locale: string): MessageMap;
148
163
 
149
164
  export declare function getStructureMessages(locale: string): StructureMessageMap;
150
165
 
166
+ /**
167
+ * Whether the raw HTML contains an `<a>` opened inside another open
168
+ * `<a>` — invalid markup that htmlparser2 silently normalizes by
169
+ * emitting an implicit `</a>` before the inner open. `extractAnchors`
170
+ * runs against the normalized parse and therefore can't distinguish
171
+ * nested-from-sibling input; this helper inspects the raw text so the
172
+ * `a11y.link-nested-anchor` rule can flag the structural problem.
173
+ *
174
+ * Tokenization here ignores anchor-like tokens inside HTML comments,
175
+ * which is enough for TipTap email-template HTML. CDATA, `<script>`,
176
+ * and attribute-value occurrences aren't expected in this surface.
177
+ */
178
+ export declare function hasNestedAnchors(html: string): boolean;
179
+
180
+ /**
181
+ * `true` when no linter would run for the given options — either the
182
+ * global `disabled` flag is set, or every per-tool key is `false`.
183
+ *
184
+ * The editor uses this to skip lazy-loading `@templatical/quality`, hide
185
+ * the Issues sidebar tab, and suppress inline canvas badges. Headless
186
+ * callers can use it to short-circuit before any linter call.
187
+ */
188
+ export declare function isLintFullyDisabled(options: LintOptions | undefined): boolean;
189
+
151
190
  export declare function isOpaqueHex(input: string | undefined | null): boolean;
152
191
 
153
192
  export declare const LINK_RULES: Rule[];
@@ -156,6 +195,21 @@ export declare type LinkMessageMap = typeof en_4;
156
195
 
157
196
  export declare type LinkRuleMessageId = keyof LinkMessageMap;
158
197
 
198
+ /** Options consumed only by the links linter. */
199
+ export declare interface LinksLintOptions {
200
+ rules?: RuleOverrides;
201
+ /**
202
+ * Host patterns that should flag as "staging / non-production".
203
+ * Each entry is a glob-style pattern matched against the URL host.
204
+ * `*` matches any run of characters (including `.`), so `*.staging.*`
205
+ * matches `app.staging.example.com`.
206
+ *
207
+ * Default: ['localhost', '127.0.0.1', '0.0.0.0', '*.local',
208
+ * '*.staging.*', '*.dev.*']
209
+ */
210
+ nonProductionHosts?: string[];
211
+ }
212
+
159
213
  export declare function lintAccessibility(content: TemplateContent, options?: LintOptions): LintIssue[];
160
214
 
161
215
  export declare interface LintIssue {
@@ -169,19 +223,6 @@ export declare interface LintIssue {
169
223
 
170
224
  export declare function lintLinks(content: TemplateContent, options?: LintOptions): LintIssue[];
171
225
 
172
- export declare interface LintLinksOptions {
173
- /**
174
- * Host patterns that should flag as "staging / non-production".
175
- * Each entry is a glob-style pattern matched against the URL host.
176
- * `*` matches any run of characters (including `.`), so `*.staging.*`
177
- * matches `app.staging.example.com`.
178
- *
179
- * Default: ['localhost', '127.0.0.1', '0.0.0.0', '*.local',
180
- * '*.staging.*', '*.dev.*']
181
- */
182
- nonProductionHosts?: string[];
183
- }
184
-
185
226
  export declare interface LintOptions {
186
227
  /**
187
228
  * Fully disable linting. When true, the editor skips lazy-loading the
@@ -190,11 +231,21 @@ export declare interface LintOptions {
190
231
  disabled?: boolean;
191
232
  /** Locale for vague-text dictionaries and message text. Falls back to `en`. */
192
233
  locale?: string;
193
- /** Per-rule severity override. Set to `'off'` to disable a specific rule. */
194
- rules?: Record<string, Severity>;
195
- thresholds?: Partial<LintThresholds>;
196
- /** Per-linter knobs. Only `lintLinks` reads `links` today. */
197
- links?: LintLinksOptions;
234
+ /**
235
+ * Accessibility linter config. Set to `false` to disable the whole
236
+ * `lintAccessibility` linter without enumerating its rules.
237
+ */
238
+ accessibility?: false | AccessibilityLintOptions;
239
+ /**
240
+ * Structure linter config. Set to `false` to disable the whole
241
+ * `lintStructure` linter without enumerating its rules.
242
+ */
243
+ structure?: false | StructureLintOptions;
244
+ /**
245
+ * Links linter config. Set to `false` to disable the whole `lintLinks`
246
+ * linter without enumerating its rules.
247
+ */
248
+ links?: false | LinksLintOptions;
198
249
  }
199
250
 
200
251
  export declare interface LintPatch {
@@ -227,7 +278,7 @@ export declare interface ResolvedLinksOptions {
227
278
 
228
279
  export declare interface ResolvedOptions {
229
280
  locale: string;
230
- rules: Record<string, Severity>;
281
+ rules: RuleOverrides;
231
282
  thresholds: LintThresholds;
232
283
  links: ResolvedLinksOptions;
233
284
  /** Returns the effective severity for a rule (override or default). */
@@ -245,7 +296,7 @@ export declare interface Rule {
245
296
  /** Block-level rule. Returns a hit or null. */
246
297
  block?: (block: Block, ctx: WalkContext, opts: ResolvedOptions) => RuleHit | null;
247
298
  /** Template-level rule. Runs once after the walk. */
248
- template?: (content: TemplateContent_2, opts: ResolvedOptions) => RuleHit[];
299
+ template?: (content: TemplateContent, opts: ResolvedOptions) => RuleHit[];
249
300
  }
250
301
 
251
302
  /**
@@ -269,10 +320,22 @@ export declare interface RuleMeta {
269
320
  severity: Exclude<Severity, "off">;
270
321
  }
271
322
 
323
+ /**
324
+ * Per-rule severity override. Set a rule to `'off'` to disable it.
325
+ * Keys are the full prefixed rule IDs (`a11y.*`, `structure.*`, `link.*`)
326
+ * so a value copied from `LintIssue.ruleId` pastes straight in.
327
+ */
328
+ export declare type RuleOverrides = Record<string, Severity>;
329
+
272
330
  export declare type Severity = "error" | "warning" | "info" | "off";
273
331
 
274
332
  export declare const STRUCTURE_RULES: Rule[];
275
333
 
334
+ /** Options consumed only by the structure linter. */
335
+ export declare interface StructureLintOptions {
336
+ rules?: RuleOverrides;
337
+ }
338
+
276
339
  export declare type StructureMessageMap = typeof en_3;
277
340
 
278
341
  export declare type StructureRuleMessageId = keyof StructureMessageMap;
@@ -306,7 +369,7 @@ export declare type Visitor = (block: Block, ctx: WalkContext) => void;
306
369
  * descend into a section that lives inside a column. Custom blocks are
307
370
  * visited but not descended into.
308
371
  */
309
- export declare function walkBlocks(content: TemplateContent_2, visit: Visitor): void;
372
+ export declare function walkBlocks(content: TemplateContent, visit: Visitor): void;
310
373
 
311
374
  export declare interface WalkContext {
312
375
  parent: Block | null;
@@ -334,6 +397,6 @@ export declare interface WalkContext {
334
397
  *
335
398
  * Each rule iterates this list once and decides per occurrence.
336
399
  */
337
- export declare function walkUrls(content: TemplateContent_2): UrlOccurrence[];
400
+ export declare function walkUrls(content: TemplateContent): UrlOccurrence[];
338
401
 
339
402
  export { }