import { type RelativeJavascriptNode } from './javascript-parser.js'; import { type SyntaxNode } from './ts-parser.js'; export type EjsSyntaxNode = SyntaxNode & { linePrefix: string; }; export declare const EJS_MARKER_PREFIX = "@ejs-tag:"; export declare const getTagTypeFromLine: (line: string) => EjsTagType | null; declare const _TAG_TYPES_WITH_MULTILINE: readonly ["escaped-output", "raw-output", "slurp", "code", "code-slurpable", "slurp-needs-indent"]; declare const _TAG_TYPES: readonly ["directive-comment", "comment-empty-line", "slurp-not-standalone"]; type EjsBaseTagType = (typeof _TAG_TYPES_WITH_MULTILINE)[number]; type EjsTagType = EjsBaseTagType | (typeof _TAG_TYPES)[number] | `${EjsBaseTagType}-multiline`; declare const EJS_OPENING_DELIMS: readonly ["<%=", "<%-", "<%_", "<%#", "<%"]; declare const EJS_CLOSING_DELIMS: readonly ["-%>", "_%>", "%>"]; type EjsOpeningDelimiter = (typeof EJS_OPENING_DELIMS)[number]; type EjsClosingDelimiter = (typeof EJS_CLOSING_DELIMS)[number]; /** * Whether tree-sitter absorbed the `_` of a `_%>` close delimiter into this tag's code node. * * tree-sitter-embedded-template ends an output tag's code node one character too late when the * tag closes with `_%>`, leaving `%>` as the delimiter and a stray `_` at the end of the code * (tree-sitter/tree-sitter-embedded-template#46). Left uncorrected the `_` reaches the * JavaScript parser and makes the whole file fail to lint. */ export declare const hasAbsorbedSlurpClose: (node: SyntaxNode) => boolean; /** * Code text of a directive tag, with an absorbed `_` close-delimiter marker removed. * * Every consumer of a tag's code must go through this: the virtual JavaScript and the tag * blocks are built from the same nodes, so correcting only one of them leaves the other * carrying the stray `_`. */ export declare const getDirectiveCodeText: (node: SyntaxNode) => string; /** A single extracted EJS tag together with its position in the original file. */ export type TagBlock = { ejsNode: EjsSyntaxNode; /** * Virtual JS code for this block (original content only — no synthetic braces). * * Structure: * ``` * Line 1: //@ejs-tag: ← type marker comment * Line 2: [virtualBodyInlineSuffix] * ← block.originalLine * Line 2+n: ← block.originalLine + n * Line 2+m: [virtualBodyExtraLine] ← optional extra line (e.g. `void 0;`) * ``` * * Brace balancing is done at the **global** level in `preprocess` (not per-block), * so that cross-tag constructs like `forEach(x => { ... })` work correctly. */ virtualCode: string; /** 1-based line in the original EJS file where the opening delimiter starts. */ tagLine: number; /** 0-based column in the original EJS file where the opening delimiter starts. */ tagColumn: number; /** 1-based line in the original EJS file where the JS code content starts. */ originalLine: number; /** 0-based column in the original EJS file where the JS code content starts. */ originalColumn: number; /** Character offset of the tag start (`<`) in the original source. */ tagOffset: number; /** Total length of the original tag (opening delimiter + content + closing delimiter). */ tagLength: number; /** * Determined tag type (same value as the `//@ejs-tag:` marker). * * Base types: `escaped-output` | `raw-output` | `slurp` | `code` | `code-slurpable` * * Suffixes added for violations: * - `-multiline` → content contains `\n` (triggers `prefer-single-line-tags` rule) * - `-needs-indent` → standalone `<%_ _%>` tag whose indentation does not match * the brace-depth expected indent (triggers `indent` rule) * - `-not-standalone` → slurp tag that is inline (triggers `slurp-newline` rule) */ tagType: EjsTagType; /** Raw JS content captured between the delimiters. */ codeContent: string; /** * JS content used in the virtual file sent to ESLint rules. * * We remove a trailing empty line (or a single trailing blank character) to avoid * conflicts with `@stylistic/no-trailing-spaces` against the delimiter * boundary, while keeping `codeContent` untouched for source-accurate fixes. */ lintCodeContent: string; javascriptPartialNode?: RelativeJavascriptNode; /** Full opening delimiter string (e.g. `<%`, `<%_`, `<%=`, `<%-`). */ openDelim: EjsOpeningDelimiter; /** Full closing delimiter string (e.g. `%>`, `_%>`, `-%>`). */ closeDelim: EjsClosingDelimiter; /** * Actual whitespace characters on the current line before the tag. * Empty string when the tag is not standalone (has non-whitespace before it * on the same line). */ lineIndent: string; /** * Expected brace-depth indentation for this tag. * Only meaningful for standalone `<%_ _%>` tags; empty string otherwise. */ expectedIndent: string; /** * Text appended to `codeContent` in the virtual body (same line, after the code). * For current output-tag handling this is `';'`, turning an expression into * a valid statement in virtual JS. * Empty string for other tags. */ virtualBodyInlineSuffix: string; /** * Optional extra line injected into the virtual body AFTER `codeContent` and * BEFORE `syntheticSuffix`. Used for code/slurp tags whose trimmed content * ends with `{`: appends `void 0;` to suppress ESLint `no-empty` errors * on the opened block. Empty string when not needed. */ virtualBodyExtraLine: string; /** Whether the tag is standalone (only whitespace before it on the same line). */ isStandalone: boolean; /** Whether this block is a virtualized ESLint directive comment from an EJS comment tag. */ isDirectiveComment: boolean; }; /** * Parse an EJS template and extract syntax nodes for tag block extraction. * * Uses tree-sitter-embedded-template for accurate EJS parsing. If parsing fails, * throws a detailed error with line/column position and the offending token. * * Each returned node is augmented with a `linePrefix` property containing the * whitespace/indentation before the node on its line. This is used during * tag block extraction to preserve original indentation. * * @throws Error if the EJS template has syntax errors */ export declare const getEjsNodes: (text: string) => EjsSyntaxNode[]; /** * Extract each non-comment EJS tag from `text` as a {@link TagBlock}, * plus supported ESLint directive comments written as EJS comments. * using tree-sitter-embedded-template for accurate parsing. * * Each per-tag virtual block has the structure: * ``` * //@ejs-tag: * [synthetic prefix — brace-balancing] * [virtualBodyInlineSuffix] * [virtualBodyExtraLine — e.g. void 0;] * [synthetic suffix — brace-balancing] * ``` * * Tag types (base): * - `escaped-output` – `<%= … %>` * - `raw-output` – `<%- … %>` * - `slurp` – `<%_ … _%>` / `<% … _%>` / `<%_ … %>` * - `code` – `<% … %>` that cannot be promoted to slurping * - `code-slurpable` – `<% … %>` that can be safely promoted to `<%_ … _%>` * * Violation suffixes (appended to the base type): * - `-multiline` – content contains newlines (fixable by `prefer-single-line-tags`) * - `-needs-indent` – wrong brace-depth indentation (fixable by `indent`) * - `-not-standalone` – slurp tag is inline (fixable by `slurp-newline`) */ export declare function extractTagBlocks(nodes: EjsSyntaxNode[]): TagBlock[]; export {}; //# sourceMappingURL=ejs-parser.d.ts.map