import type { Linter } from 'eslint'; import { type TagBlock } from './ejs-parser.js'; /** * Sentinel text written by the `experimental-prefer-slurp-multiline` fix. * Using a non-empty distinct value lets `translateFix` tell this sentinel * apart from the generic `''` sentinel used by all other plugin rules. */ export declare const SENTINEL_PREFER_SLURP_MULTILINE = "PREFER_SLURP_MULTILINE"; /** * Sentinel text written by `prefer-single-line-tags`. */ export declare const SENTINEL_PREFER_SINGLE_LINE_TAGS_BRACES = "PREFER_SINGLE_LINE_TAGS_BRACES"; /** * Sentinel text written by the `slurp-newline` fix. */ export declare const SENTINEL_SLURP_NEWLINE = "SLURP_NEWLINE"; /** * Sentinel text written by the `indent` fix. */ export declare const SENTINEL_INDENT = "INDENT"; /** * Sentinel text written by the `indent` fix when `normalizeContent` is enabled. */ export declare const SENTINEL_INDENT_NORMALIZE = "INDENT_NORMALIZE"; /** * Sentinel text written by the `format` fix. */ export declare const SENTINEL_FORMAT = "FORMAT"; /** * Sentinel text written by the `format` fix when `multilineCloseOnNewLine` * is enabled. */ export declare const SENTINEL_FORMAT_MULTILINE_CLOSE = "FORMAT_MULTILINE_CLOSE"; /** * Sentinel text written by the `no-comment-empty-line` fix. */ export declare const SENTINEL_COMMENT_EMPTY_LINE = "COMMENT_EMPTY_LINE"; /** * Sentinel text written by the `output-semi` fix when `always` is enabled. * Inserts `;` at the end of the output tag content (before `%>`). */ export declare const SENTINEL_OUTPUT_SEMI_ADD = "OUTPUT_SEMI_ADD"; /** * Sentinel text written by the `output-semi` fix when `never` is enabled. * Removes the trailing `;` from the output tag content. */ export declare const SENTINEL_OUTPUT_SEMI_REMOVE = "OUTPUT_SEMI_REMOVE"; /** * Sentinel text written by the `prefer-output` fix. */ export declare const SENTINEL_PREFER_OUTPUT = "PREFER_OUTPUT"; export declare const SENTINEL_PREFER_OUTPUT_ELSE = "PREFER_OUTPUT_ELSE"; export declare const SENTINEL_NO_MULTILINE_OUTPUT = "NO_MULTILINE_OUTPUT"; type NegatedOutputConditionalParts = { condition: string; consequent: string; alternate: string; hasTrailingSemi: boolean; }; /** An output ternary whose branches are literals and whose rendered text spans lines. */ export type MultilineOutputConditionalParts = { condition: string; consequent: string; alternate: string; }; /** * Extract the parts of an output tag of the form `<%- cond ? 'a\nb' : '' %>`. * * Returns null unless the tag is a single-line output tag holding one ternary whose branches * are both plain string literals and whose rendered output actually contains a newline — the * case where a conditional block reads better than an escaped one-liner. */ export declare function getMultilineOutputConditionalParts(block: TagBlock): MultilineOutputConditionalParts | null; export declare function getNegatedOutputConditionalParts(block: TagBlock): NegatedOutputConditionalParts | null; /** * Positive condition for a tag holding exactly `if () {`, or null. * * Only the opening tag is inspected here; whether the statement actually has an `else` * branch to swap with is decided by the caller from the surrounding blocks. */ export declare function getNegatedIfCondition(block: TagBlock): string | null; /** Whether a tag is exactly `} else {` — an `else if` continuation deliberately does not match. */ export declare function isElseOpeningBlock(block: TagBlock): boolean; /** * Whether a tag closes a branch and continues the chain with `else if` rather than a plain * `else` — e.g. `} else if (other) {`. * * Such a statement must not be swapped: its branches form a chain, and moving the first body * past the remaining `else if` links would neither preserve behaviour nor stay syntactically * valid. The core `no-negated-condition` rule likewise leaves these alone. */ export declare function isElseIfContinuationBlock(block: TagBlock): boolean; /** * Positive form of a negated `} else if (…) {` link's test, or null when it is not one. * * The link parses as an `ERROR` node — `}`, `else`, `if`, the condition, `{` — rather than an * `if_statement`, because the braces it opens and closes live in other tags. */ export declare function getNegatedElseIfCondition(block: TagBlock): string | null; /** Whether a tag is exactly `}`, closing a block without opening another. */ export declare function isBlockClosingBlock(block: TagBlock): boolean; /** * Locate the `} else {` and closing `}` tags belonging to an `if` tag, given the blocks that * follow it. * * The branches cannot be found positionally: a branch body normally holds further tags — * output tags, nested conditionals, loops — so the matching `else` is rarely the next block. * Nesting is tracked through each block's brace delta and only tags at depth zero are * considered, which is what makes the match the *own* branches of this `if`. * * Returns null when the statement has no `else` (a closing `}` is reached first), when the * `else` is an `else if` continuation, or when the template ends unbalanced. */ export declare function findNegatedConditionBranches(followingBlocks: TagBlock[]): { elseBlock: TagBlock; closeBlock: TagBlock; } | null; /** Whether a tag renders a value, regardless of whether its content spans lines. */ export declare const isOutputTagType: (tagType: string) => boolean; /** * Position mapping for a single EJS tag block within the concatenated virtual file. * * Two variants track the same block in different virtual file contexts: * - **segments**: Positions in the function-wrapped virtual file (`GLOBAL_VIRTUAL_OPEN + blocks + GLOBAL_VIRTUAL_CLOSE`) * Used for main ESLint linting and fix translation. * - **rawSegments**: Positions in raw concatenated virtual code (no function wrapper). * Used for fallback raw JS validation when main pass reports fatal errors with `return` statements. * * Line and offset numbers are absolute positions within their respective virtual files. * They are used during postprocess() to locate ESLint messages and map them back to * the corresponding TagBlock for translation to original EJS source positions. */ type VirtualBlockSegment = { block: TagBlock; /** 1-based start line of this block inside the combined virtual file. */ startLine: number; /** 1-based end line of this block inside the combined virtual file. */ endLine: number; /** 0-based start offset of this block inside the combined virtual file. */ startOffset: number; /** 0-based end offset (exclusive) of this block inside the combined virtual file. */ endOffset: number; }; type FileBlocks = { segments: VirtualBlockSegment[]; nonDirectiveSegments: VirtualBlockSegment[]; rawSegments: VirtualBlockSegment[]; }; export declare const getFileBlocks: (filename: string) => FileBlocks | undefined; /** * Cached formatting state for tags to detect if they already match format rules. */ type TagFormatState = { isFormattedDefault: boolean; isFormattedMultilineClose: boolean; }; /** * Unified metadata for a single virtual code block. * * Combines all per-tag metadata needed by ESLint rules: * - tagFormat: array of TagFormatState objects for format rule detection */ type VirtualCodeMetadata = { tagFormat: TagFormatState[]; /** Index i is true when i-th non-directive slurp-multiline block needs content normalization. */ needsNormalize: boolean[]; }; /** * Retrieve unified metadata for a virtual code block. * * Returns all metadata needed by rules: structural control flow, single-line-trim detection, * and cached formatting state. Returns undefined if metadata not found (file not preprocessed). */ export declare function getVirtualCodeMetadata(virtualCode: string): VirtualCodeMetadata | undefined; /** * ESLint processor for `.ejs` files. * * Each non-comment EJS tag is transformed into a virtual JavaScript block and * all blocks are concatenated, in source order, into a single incremental * virtual file for ESLint. * * Every per-tag block contains the original tag content (no synthetic * per-block braces). The first line of every per-tag block is a single-line * comment (`//@ejs-tag:`) that encodes the tag type so plugin rules can * detect EJS-specific patterns. Global brace balancing (synthetic `}` * characters) is appended before the IIFE close when the cumulative net brace * delta across all tags is positive, keeping isolated unbalanced fragments * parseable while still handling cross-tag constructs like `forEach(x => { … })` * correctly. * * Parsing is backed by tree-sitter-embedded-template for accurate position * information and robust syntax handling. */ export declare const processor: Linter.Processor; export {}; //# sourceMappingURL=processor.d.ts.map