import type { Rule, Scope } from 'eslint'; /** * A part of the package is placed from outside, never restyled (UIG-9; Katerina's * ruling B8 of 13 September, "only position and spacing pass into our * components"). * * Every part takes `className`, and some take a second class prop for an inner * box (`contentClassName`, `bodyClassName`…). Through either, an app could push * a colour, a text size or a border into a part and quietly undo it: the token * lint only asks whether a class is a real token, never whether the part should * take it. This rule reads every class passed into a part and lets through only * placement — where the part sits and how much room it takes. * * **Which elements are parts: by where they come from, never by name.** No list * of names is kept, so a part added to the package later is covered the day it * is added. * * - In an app: anything imported from `@estiva-app/ui`, and anything imported * from the app's own files that is one of those — a re-export (Peek's * `components/ui/Button.tsx`), a wrapper that hands its props on to a part * (`{...rest}`), or a component that hands its own `className` on to a part * (Peek's `ConversationCard` into `Card`). Relative imports and the apps' `@/` * alias are followed; `@/` is the `src` folder beside the nearest * `package.json`. * - Inside the package (Katerina, 17 September): a name `src/index.ts` exports, * imported from a sibling file or declared in the same file. * * **What it reads:** a string, a template, `cn()`/`clsx()` and their arguments, * both sides of a condition, a `const` in the same file and the values of a * class map read from one. A class the code works out while it runs passes: the * rule cannot read it. * * `EmptyState` takes no padding either (Katerina's ruling 6 of 14 September): * its room comes from the box its rows live in. * * `Form` takes no layout for its fields (Katerina, 28 September): it stacks * them 24px apart itself, so every form reads the same. A form that is not a * list of fields says `layout="free"`, and then lays itself out. */ /** Where a part sits and how much room it takes. Read on the utility, after its variants. */ export declare const PLACEMENT: { what: string; pattern: RegExp; }[]; /** * The same, as `style` keys (Katerina's ruling B6, 25 September): `style` on a * part is read like its `className`, so a radius, a weight or an opacity cannot * go in by the other door. CSS's own names for space, size, flex and grid, and * position; `transform` and `translate` move a part without changing its look. * A custom property (`--name`) passes: the part decides what it means. */ export declare const PLACEMENT_STYLE: RegExp; /** A class list's variants and its utility: `sm:[&>*]:shrink-0` → `['sm', '[&>*]']`, `shrink-0`. */ export declare function splitClass(token: string): { variants: string[]; utility: string; }; /** Whether a class only places the part. */ export declare function isPlacement(token: string): boolean; /** * The props a part has for how it looks, named in the message. Held to the * package's source by `no-restyled-part.test.ts`: every prop here exists, and * every look prop an exported part has is here. A part missing from this table * has none, and the message says to ask for one. */ export declare const PART_LOOK_PROPS: Record; interface Node { type: string; range: [number, number]; loc?: NonNullable; parent?: Node; [key: string]: unknown; } /** Walk every node under `root`, skipping the parser's bookkeeping keys. */ declare function walk(root: Node, visit: (node: Node) => void): void; /** * What a name is to this rule: the part it draws, and which of the caller's * class props reach which of the part's (`all` for a part, a re-export or a * wrapper; a map for a component that hands on its own `className`). `via` is * the app's own component in between, for the message. */ export interface PartBinding { part: string; props: 'all' | Record; via?: string; } interface Parser { parseForESLint?: (code: string, options: unknown) => { ast: Node; }; parse?: (code: string, options: unknown) => Node; } declare function parseFile(parser: Parser, filePath: string): Node | null; declare function resolveModule(fromFile: string, specifier: string): string | null; /** A function component declared in a module: its name, and the function. */ declare function functionComponents(program: Node): Map; /** * What a file's names stand for, found the way this rule finds them: for a rule * that asks whether a tag is one particular part, through an app's wrapper too * (UIG-23 asks for `EmptyState` and `ScrollArea`). */ export declare function partsOfFile(file: string, program: Node, parser: Parser): Map; export { bindingOfTag, functionComponents, parseFile, resolveModule, walk, type Node, type Parser }; declare function bindingOfTag(tag: Node | null | undefined, locals: Map): PartBinding | undefined; /** * Every class the code spells out for a value, as far as it can be read in this * file. `asMap` reads an object as a class map (its values) rather than as a * `clsx` object (its keys). */ export declare function classesOf(value: Node | null | undefined, scopeOf: (node: Node) => Scope.Scope | null, asMap?: boolean, seen?: Set): string[]; export declare const noRestyledPart: Rule.RuleModule; //# sourceMappingURL=no-restyled-part.d.ts.map