"use strict";
const require_runtime = require("../_virtual/_rolldown/runtime.js");
const require_index = require("../utils/index.js");
//#region lib/rules/max-len.js
/**
* @author Yosuke Ota
* @fileoverview Rule to check for max length on a line of Vue file.
*/
var require_max_len = /* @__PURE__ */ require_runtime.__commonJSMin(((exports, module) => {
	const utils = require_index.default;
	const OPTIONS_SCHEMA = {
		type: "object",
		properties: {
			code: {
				type: "integer",
				minimum: 0
			},
			template: {
				type: "integer",
				minimum: 0
			},
			comments: {
				type: "integer",
				minimum: 0
			},
			tabWidth: {
				type: "integer",
				minimum: 0
			},
			ignorePattern: { type: "string" },
			ignoreComments: { type: "boolean" },
			ignoreTrailingComments: { type: "boolean" },
			ignoreUrls: { type: "boolean" },
			ignoreStrings: { type: "boolean" },
			ignoreTemplateLiterals: { type: "boolean" },
			ignoreRegExpLiterals: { type: "boolean" },
			ignoreHTMLAttributeValues: { type: "boolean" },
			ignoreHTMLTextContents: { type: "boolean" }
		},
		additionalProperties: false
	};
	const OPTIONS_OR_INTEGER_SCHEMA = { oneOf: [OPTIONS_SCHEMA, {
		type: "integer",
		minimum: 0
	}] };
	/**
	* Computes the length of a line that may contain tabs. The width of each
	* tab will be the number of spaces to the next tab stop.
	* @param {string} line The line.
	* @param {number} tabWidth The width of each tab stop in spaces.
	* @returns {number} The computed line length.
	* @private
	*/
	function computeLineLength(line, tabWidth) {
		let extraCharacterCount = 0;
		const re = /\t/gu;
		let ret;
		while (ret = re.exec(line)) {
			const totalOffset = ret.index + extraCharacterCount;
			const spaceCount = tabWidth - (tabWidth ? totalOffset % tabWidth : 0);
			extraCharacterCount += spaceCount - 1;
		}
		return [...line].length + extraCharacterCount;
	}
	/**
	* Tells if a given comment is trailing: it starts on the current line and
	* extends to or past the end of the current line.
	* @param {string} line The source line we want to check for a trailing comment on
	* @param {number} lineNumber The one-indexed line number for line
	* @param {Token | null} comment The comment to inspect
	* @returns {comment is Token} If the comment is trailing on the given line
	*/
	function isTrailingComment(line, lineNumber, comment) {
		return Boolean(comment && comment.loc.start.line === lineNumber && lineNumber <= comment.loc.end.line && (comment.loc.end.line > lineNumber || comment.loc.end.column === line.length));
	}
	/**
	* Tells if a comment encompasses the entire line.
	* @param {string} line The source line with a trailing comment
	* @param {number} lineNumber The one-indexed line number this is on
	* @param {Token | null} comment The comment to remove
	* @returns {boolean} If the comment covers the entire line
	*/
	function isFullLineComment(line, lineNumber, comment) {
		if (!comment) return false;
		const start = comment.loc.start;
		const end = comment.loc.end;
		const isFirstTokenOnLine = !line.slice(0, comment.loc.start.column).trim();
		return comment && (start.line < lineNumber || start.line === lineNumber && isFirstTokenOnLine) && (end.line > lineNumber || end.line === lineNumber && end.column === line.length);
	}
	/**
	* Gets the line after the comment and any remaining trailing whitespace is
	* stripped.
	* @param {string} line The source line with a trailing comment
	* @param {Token} comment The comment to remove
	* @returns {string} Line without comment and trailing whitepace
	*/
	function stripTrailingComment(line, comment) {
		return line.slice(0, comment.loc.start.column).replace(/\s+$/u, "");
	}
	/**
	* Group AST nodes by line number, both start and end.
	*
	* @param {Token[]} nodes the AST nodes in question
	* @returns { { [key: number]: Token[] } } the grouped nodes
	* @private
	*/
	function groupByLineNumber(nodes) {
		/** @type { { [key: number]: Token[] } } */
		const grouped = {};
		for (const node of nodes) for (let i = node.loc.start.line; i <= node.loc.end.line; ++i) {
			if (!Array.isArray(grouped[i])) grouped[i] = [];
			grouped[i].push(node);
		}
		return grouped;
	}
	module.exports = {
		meta: {
			type: "layout",
			docs: {
				description: "enforce a maximum line length in `.vue` files",
				categories: void 0,
				url: "https://eslint.vuejs.org/rules/max-len.html",
				extensionSource: {
					url: "https://eslint.org/docs/rules/max-len",
					name: "ESLint core"
				}
			},
			schema: [
				OPTIONS_OR_INTEGER_SCHEMA,
				OPTIONS_OR_INTEGER_SCHEMA,
				OPTIONS_SCHEMA
			],
			messages: {
				max: "This line has a length of {{lineLength}}. Maximum allowed is {{maxLength}}.",
				maxComment: "This line has a comment length of {{lineLength}}. Maximum allowed is {{maxCommentLength}}."
			}
		},
		/**
		* @param {RuleContext} context - The rule context.
		* @returns {RuleListener} AST event handlers.
		*/
		create(context) {
			const URL_REGEXP = /[^:/?#]:\/\/[^?#]/u;
			const sourceCode = context.sourceCode;
			/** @type {Token[]} */
			const tokens = [];
			/** @type {(HTMLComment | HTMLBogusComment | Comment)[]} */
			const comments = [];
			/** @type {VLiteral[]} */
			const htmlAttributeValues = [];
			const options = Object.assign({}, context.options.at(-1));
			if (typeof context.options[0] === "number") options.code = context.options[0];
			if (typeof context.options[1] === "number") options.tabWidth = context.options[1];
			/** @type {number} */
			const scriptMaxLength = typeof options.code === "number" ? options.code : 80;
			/** @type {number} */
			const tabWidth = typeof options.tabWidth === "number" ? options.tabWidth : 2;
			/** @type {number} */
			const templateMaxLength = typeof options.template === "number" ? options.template : scriptMaxLength;
			const shouldIgnoreComments = !!options.ignoreComments;
			const shouldIgnoreStrings = !!options.ignoreStrings;
			const shouldIgnoreTemplateLiterals = !!options.ignoreTemplateLiterals;
			const shouldIgnoreRegExpLiterals = !!options.ignoreRegExpLiterals;
			const shouldIgnoreTrailingComments = !!options.ignoreTrailingComments || !!options.ignoreComments;
			const shouldIgnoreUrls = !!options.ignoreUrls;
			const shouldIgnoreHTMLAttributeValues = !!options.ignoreHTMLAttributeValues;
			const shouldIgnoreHTMLTextContents = !!options.ignoreHTMLTextContents;
			/** @type {number} */
			const maxCommentLength = options.comments;
			/** @type {RegExp} */
			let ignorePattern = options.ignorePattern || null;
			if (ignorePattern) ignorePattern = new RegExp(ignorePattern, "u");
			/**
			* Retrieves an array containing all strings (" or ') in the source code.
			*
			* @returns {Token[]} An array of string nodes.
			*/
			function getAllStrings() {
				return tokens.filter((token) => token.type === "String" || token.type === "JSXText" && sourceCode.getNodeByRangeIndex(token.range[0] - 1).type === "JSXAttribute");
			}
			/**
			* Retrieves an array containing all template literals in the source code.
			*
			* @returns {Token[]} An array of template literal nodes.
			*/
			function getAllTemplateLiterals() {
				return tokens.filter((token) => token.type === "Template");
			}
			/**
			* Retrieves an array containing all RegExp literals in the source code.
			*
			* @returns {Token[]} An array of RegExp literal nodes.
			*/
			function getAllRegExpLiterals() {
				return tokens.filter((token) => token.type === "RegularExpression");
			}
			/**
			* Retrieves an array containing all HTML texts in the source code.
			*
			* @returns {Token[]} An array of HTML text nodes.
			*/
			function getAllHTMLTextContents() {
				return tokens.filter((token) => token.type === "HTMLText");
			}
			/**
			* Check the program for max length
			* @param {Program} node Node to examine
			* @returns {void}
			* @private
			*/
			function checkProgramForMaxLength(node) {
				const programNode = node;
				const templateBody = node.templateBody;
				const scriptTokens = sourceCode.ast.tokens;
				const scriptComments = sourceCode.getAllComments();
				if (sourceCode.parserServices.getTemplateBodyTokenStore && templateBody) {
					const templateTokens = sourceCode.parserServices.getTemplateBodyTokenStore().getTokens(templateBody, { includeComments: true });
					if (templateBody.range[0] < programNode.range[0]) tokens.push(...templateTokens, ...scriptTokens);
					else tokens.push(...scriptTokens, ...templateTokens);
				} else tokens.push(...scriptTokens);
				if (shouldIgnoreComments || maxCommentLength || shouldIgnoreTrailingComments) if (templateBody) if (templateBody.range[0] < programNode.range[0]) comments.push(...templateBody.comments, ...scriptComments);
				else comments.push(...scriptComments, ...templateBody.comments);
				else comments.push(...scriptComments);
				/** @type {Range | undefined} */
				let scriptLinesRange;
				if (scriptTokens.length > 0) scriptLinesRange = scriptComments.length > 0 ? [Math.min(scriptTokens[0].loc.start.line, scriptComments[0].loc.start.line), Math.max(
					/** @type {Token} */
					scriptTokens.at(-1).loc.end.line,
					/** @type {Comment} */
					scriptComments.at(-1).loc.end.line
				)] : [scriptTokens[0].loc.start.line, scriptTokens.at(-1).loc.end.line];
				else if (scriptComments.length > 0) scriptLinesRange = [scriptComments[0].loc.start.line, scriptComments.at(-1).loc.end.line];
				const templateLinesRange = templateBody && [templateBody.loc.start.line, templateBody.loc.end.line];
				const lines = sourceCode.lines;
				const stringsByLine = groupByLineNumber(getAllStrings());
				const templateLiteralsByLine = groupByLineNumber(getAllTemplateLiterals());
				const regExpLiteralsByLine = groupByLineNumber(getAllRegExpLiterals());
				const htmlAttributeValuesByLine = groupByLineNumber(htmlAttributeValues);
				const htmlTextContentsByLine = groupByLineNumber(getAllHTMLTextContents());
				const commentsByLine = groupByLineNumber(comments);
				for (const [i, line] of lines.entries()) {
					const lineNumber = i + 1;
					const inScript = scriptLinesRange && scriptLinesRange[0] <= lineNumber && lineNumber <= scriptLinesRange[1];
					const inTemplate = templateLinesRange && templateLinesRange[0] <= lineNumber && lineNumber <= templateLinesRange[1];
					if (!inScript && !inTemplate) continue;
					if (shouldIgnoreStrings && stringsByLine[lineNumber] || shouldIgnoreTemplateLiterals && templateLiteralsByLine[lineNumber] || shouldIgnoreRegExpLiterals && regExpLiteralsByLine[lineNumber] || shouldIgnoreHTMLAttributeValues && htmlAttributeValuesByLine[lineNumber] || shouldIgnoreHTMLTextContents && htmlTextContentsByLine[lineNumber]) continue;
					let isCommentLine = false;
					let textToMeasure;
					if (commentsByLine[lineNumber]) {
						const commentList = [...commentsByLine[lineNumber]];
						let comment = commentList.pop() || null;
						if (isFullLineComment(line, lineNumber, comment)) {
							isCommentLine = true;
							textToMeasure = line;
						} else if (shouldIgnoreTrailingComments && isTrailingComment(line, lineNumber, comment)) {
							textToMeasure = stripTrailingComment(line, comment);
							comment = commentList.pop() || null;
							while (isTrailingComment(textToMeasure, lineNumber, comment)) textToMeasure = stripTrailingComment(textToMeasure, comment);
						} else textToMeasure = line;
					} else textToMeasure = line;
					if (ignorePattern && ignorePattern.test(textToMeasure) || shouldIgnoreUrls && URL_REGEXP.test(textToMeasure) || isCommentLine && shouldIgnoreComments) continue;
					const maxLength = Math.max(inScript ? scriptMaxLength : 0, inTemplate ? templateMaxLength : 0);
					const lineLength = computeLineLength(textToMeasure, tabWidth);
					if (isCommentLine && maxCommentLength) {
						if (lineLength > maxCommentLength) context.report({
							node,
							loc: {
								start: {
									line: lineNumber,
									column: maxCommentLength
								},
								end: {
									line: lineNumber,
									column: lineLength
								}
							},
							messageId: "maxComment",
							data: {
								lineLength,
								maxCommentLength
							}
						});
					} else if (lineLength > maxLength) context.report({
						node,
						loc: {
							start: {
								line: lineNumber,
								column: maxLength
							},
							end: {
								line: lineNumber,
								column: lineLength
							}
						},
						messageId: "max",
						data: {
							lineLength,
							maxLength
						}
					});
				}
			}
			return utils.compositingVisitors(utils.defineTemplateBodyVisitor(context, { 
			/** @param {VLiteral} node */
"VAttribute[directive=false] > VLiteral"(node) {
				htmlAttributeValues.push(node);
			} }), { "Program:exit"(node) {
				checkProgramForMaxLength(node);
			} });
		}
	};
}));
//#endregion
Object.defineProperty(exports, "default", {
	enumerable: true,
	get: function() {
		return require_max_len();
	}
});
