/**
* Placement Validator
*
* Structural checks on WHERE an Eddie component sits, as opposed to what it
* is. Every other markup validator judges an element on its own attributes
* (slot names, link text, knockout); this one judges an element by its
* parent and siblings. It exists because guidance held only as prose does
* not stop a generator: eddie-brain already said "not for single paragraphs"
* and "the description goes in the header slot", a composer that copied both
* lines into its catalog still emitted four bare `ed-text-passage`s at the
* page root (#1890, Brad-Frost-Web/bf-brain#1154).
*
* Scope:
* - `.html` files (consumer projects, boilerplates, generated pages)
* - Lit `html`...`` template regions inside `.ts` / `.tsx` / `.js` / `.mjs` / `.jsx`
* - the product analyzer's tag stream (`findFloatingProse` on a tree it
* builds from `scanHtml`), so `eddie_analyze_product` reports the same
* finding on a consumer's built pages.
*
* Checks:
* 1. FLOATING PROSE (error) — an `ed-text-passage`, `ed-button`,
* `ed-button-group`, or bare `
` that is a direct child of a
* page-level rhythm owner (`ed-page`, `ed-main`, `ed-stack`,
* `ed-layout-section`, `ed-layout-container`, `ed-band`) with no heading
* beside it and no enclosing content container (`ed-section`, `ed-card`,
* `ed-page-header`, a recipe, a landmark…). A sentence with no container
* has no place on a page: the neighbouring section's header slot (as its
* description), `ed-page-header`'s description, or the card it belongs
* to is where it goes. The uniform section/region gap of the owner turns
* each stray line into its own 64px-padded region (the measured symptom).
*
* Conservatism (the repo's validator philosophy, #1015/#1530): false
* positives are worse than false negatives. Every exemption below is a
* legitimate page shape, not a loophole:
* - a heading sibling (`ed-heading`, `
`–``, `ed-page-header`, or an
* `ed-text-passage` carrying its own heading) gives every sibling context.
* That is the issue's own definition, and it is also the cheapest route
* around the rule — one heading at the top of a root stack exempts every
* stray line under it. Whether those lines are the same granularity as
* their siblings is #1891's question, not this check's;
* - an `ed-text-passage` that carries its own heading is editorial prose
* (an article body), not a stray line;
* - any ancestor that is not a page-level owner or a bare `` is a
* content container that owns its children — the chain stops there;
* - a `slot=` attribute means the element addresses a slot contract, which
* the slot-contract validator judges, not this one;
* - a `${…}` expression among the siblings (Lit) means the siblings are
* unknowable statically — skip rather than guess.
*
* 2. MIXED-GRANULARITY STACK (warning, #1891) — an `ed-stack` with
* `gap="section"` or `gap="region"` whose direct children are not all
* regions. The gap is uniform, so a stack's children must be the same
* granularity: bf-brain's root `
` put a 20px
* one-line passage and a 52px button group between sections and each got
* 64px above and below — "a monstrous amount of spacing between these
* little things". A one-line note belongs inside the neighbouring section
* (its header description or body), not between sections; the paved path
* for an app page is `ed-main` owning the sequence of `ed-section`s, with
* `ed-stack` reserved for same-granularity siblings inside a region.
* Conservative: only the tags that are unambiguously line-scale are
* counted as small (a passage, a button, a link, a badge…); anything the
* rule cannot classify — a ``, a recipe, a custom element — is taken
* to be a region. This is a STACK-level diagnosis ("this stack is the
* wrong construct"), so it fires even when check 1 has already reported
* each stray line: the incident's root stack gets four floating-prose
* errors AND one warning saying to let ed-main own the sections.
*
* Every rule here is measured against the whole repo before it lands (the
* sweep is in the PR that adds it); a rule that fires on Eddie's own pages,
* recipes, stories or boilerplates is either wrong or has found a bug to fix
* in the same PR.
*/
import type { HealthIssue } from '../types.js';
import type { MarkupNode } from './markup.js';
export interface MixedGranularityFinding {
/** The stack's gap value (`section` | `region`). */
gap: string;
/** Tags of the children that are not region-scale, in document order. */
offenders: string[];
/** Total direct children considered. */
childCount: number;
/** 0-based line of the stack's open tag within the region. */
line: number;
/** 0-based line of the first offending child. */
firstOffenderLine: number;
message: string;
suggestion: string;
}
export interface FloatingProseFinding {
tag: string;
parentTag: string;
attrs: string;
/** 0-based line within the region (or the token's own line when built from a stream). */
line: number;
message: string;
suggestion: string;
}
/**
* Walk a parsed tree and report every floating-prose occurrence. Pure — the
* validator and the product analyzer both call this.
*/
export declare function findFloatingProse(roots: MarkupNode[]): FloatingProseFinding[];
/**
* Walk a parsed tree and report every section/region-gapped `ed-stack` whose
* direct children mix a line-scale element with regions (#1891). One finding
* per stack, independent of `findFloatingProse`: that check says a line has
* no home, this one says the stack is the wrong construct.
*/
export declare function findMixedGranularity(roots: MarkupNode[]): MixedGranularityFinding[];
export declare class PlacementValidator {
validateFile(filePath: string): Promise;
private scanRegion;
}
//# sourceMappingURL=placement-validator.d.ts.map