UNPKG

eslint-plugin-vue-scoped-css

Version:
1,649 lines (1,648 loc) 191 kB
import { createRequire } from "node:module"; import * as postcss from "postcss"; import postcssSafeParser from "postcss-safe-parser"; import selectorParser from "postcss-selector-parser"; import { get, set, sortedLastIndex } from "es-toolkit/compat"; import * as vueParser from "vue-eslint-parser"; import { AST } from "vue-eslint-parser"; import eslintUtils from "@eslint-community/eslint-utils"; //#region lib/styles/ast.ts /** * The node */ var Node = class { /** * constructor. * @param {PostCSSNode | PostCSSSPNode} node PostCSS node. * @param {string} type The token type. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, type, loc, start, end, lang) { this.type = type; this.loc = loc; this.start = start; this.end = end; this.range = [start, end]; this.node = node; this.lang = lang; } }; /** * The has parent node */ var HasParentNode = class extends Node { constructor(node, type, loc, start, end, props) { super(node, type, loc, start, end, props.parent.lang); this.parent = props.parent; } }; /** * The CSS Parsing Error. */ var VCSSParsingError = class extends Node { /** * constructor. * @param {PostCSSDeclaration} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, loc, start, end, props) { super(node, "VCSSParsingError", loc, start, end, props.lang); this.message = props.message; } }; /** * The CSS root node. */ var VCSSStyleSheet = class extends Node { /** * constructor. * @param {PostCSSRoot} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, loc, start, end, props) { super(node, "VCSSStyleSheet", loc, start, end, props.lang); this.nodes = props.nodes ?? []; this.comments = props.comments ?? []; this.errors = props.errors ?? []; } /** * Copy * @param {object} props The optional change property. * @returns {VCSSStyleSheet} copy node */ copy(props) { return copyStdNode(this, props); } }; /** * The CSS Rule node. */ var VCSSStyleRule = class extends HasParentNode { /** * constructor. * @param {AtRule} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, loc, start, end, props) { super(node, "VCSSStyleRule", loc, start, end, props); this.selectorText = props.selectorText ?? node.selector; if (props.rawSelectorText != null) this.rawSelectorText = props.rawSelectorText; else { const raws = node.raws; this.rawSelectorText = raws.selector ? raws.selector.raw : node.selector; } this.selectors = props.selectors ?? []; this.nodes = props.nodes ?? []; } /** * Copy * @param {object} props The optional change property. * @returns {VCSSStyleRule} copy node */ copy(props) { return copyStdNode(this, props); } }; /** * The CSS Declaration Property node. */ var VCSSDeclarationProperty = class extends HasParentNode { /** * constructor. * @param {PostCSSDeclaration} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, loc, start, end, props) { super(node, "VCSSDeclarationProperty", loc, start, end, props); this.property = props.property ?? node.prop; this.value = getProp(props, node, "value"); this.important = props.important ?? Boolean(node.important); } /** * Copy * @param {object} props The optional change property. * @returns {VCSSDeclarationProperty} copy node */ copy(props) { return copyStdNode(this, props); } }; /** * The CSS At(@) Rule node. */ var VCSSAtRule = class extends HasParentNode { /** * constructor. * @param {PostCSSAtRule} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, loc, start, end, props) { super(node, "VCSSAtRule", loc, start, end, props); this.node = node; this.name = getProp(props, node, "name"); this.identifier = props.identifier; this.paramsText = props.paramsText ?? node.params; if (props.rawParamsText != null) this.rawParamsText = props.rawParamsText; else { const raws = node.raws; this.rawParamsText = raws.params?.raw ?? node.params; } this.selectors = props.selectors ?? void 0; this.nodes = props.nodes ?? []; } /** * Copy * @param {object} props The optional change property. * @returns {VCSSAtRule} copy node */ copy(props) { return copyStdNode(this, props); } }; /** * The CSS Unknown. */ var VCSSUnknown = class extends HasParentNode { /** * constructor. * @param {PostCSSNode} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, loc, start, end, props) { super(node, "VCSSUnknown", loc, start, end, props); this.nodes = props.nodes ?? []; this.unknownType = props.unknownType; } /** * Copy * @param {object} props The optional change property. * @returns {VCSSUnknown} copy node */ copy(props) { return copyStdNode(this, props); } }; /** * The CSS Selector node. */ var VCSSSelector = class extends HasParentNode { /** * constructor. * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, loc, start, end, props) { super(node, "VCSSSelector", loc, start, end, props); this.nodes = props.nodes ?? []; this.parent = props.parent; } /** * Copy * @param {object} props The optional change property. * @returns {VCSSSelector} copy node */ copy(props) { return copyStdNode(this, props); } get selector() { return this.nodes.map((n) => n.selector).join(""); } }; /** * The CSS Type Selector node. */ var VCSSTypeSelector = class extends HasParentNode { /** * constructor. * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, loc, start, end, props) { super(node, "VCSSTypeSelector", loc, start, end, props); this.value = getProp(props, node, "value"); this.selector = this.value; } /** * Copy * @param {object} props The optional change property. * @returns {VCSSTypeSelector} copy node */ copy(props) { return copyStdNode(this, props); } }; /** * The CSS ID Selector node. */ var VCSSIDSelector = class extends HasParentNode { /** * constructor. * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, loc, start, end, props) { super(node, "VCSSIDSelector", loc, start, end, props); this.value = getProp(props, node, "value"); this.selector = `#${this.value}`; } /** * Copy * @param {object} props The optional change property. * @returns {VCSSIDSelector} copy node */ copy(props) { return copyStdNode(this, props); } }; /** * The CSS Class Selector node. */ var VCSSClassSelector = class extends HasParentNode { /** * constructor. * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, loc, start, end, props) { super(node, "VCSSClassSelector", loc, start, end, props); this.value = getProp(props, node, "value"); this.selector = `.${this.value}`; } /** * Copy * @param {object} props The optional change property. * @returns {VCSSClassSelector} copy node */ copy(props) { return copyStdNode(this, props); } }; /** * The CSS Nesting Selector node. */ var VCSSNestingSelector = class extends HasParentNode { /** * constructor. * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, loc, start, end, props) { super(node, "VCSSNestingSelector", loc, start, end, props); this.value = getProp(props, node, "value"); this.selector = this.value; } /** * Copy * @param {object} props The optional change property. * @returns {VCSSNestingSelector} copy node */ copy(props) { return copyStdNode(this, props); } }; /** * The CSS Universal Selector node. */ var VCSSUniversalSelector = class extends HasParentNode { /** * constructor. * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, loc, start, end, props) { super(node, "VCSSUniversalSelector", loc, start, end, props); this.value = getProp(props, node, "value"); this.selector = this.value; } /** * Copy * @param {object} props The optional change property. * @returns {VCSSUniversalSelector} copy node */ copy(props) { return copyStdNode(this, props); } }; /** * The CSS Attribuute Selector node. */ var VCSSAttributeSelector = class extends HasParentNode { /** * constructor. * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, loc, start, end, props) { super(node, "VCSSAttributeSelector", loc, start, end, props); this.attribute = getProp(props, node, "attribute"); const operator = getProp(props, node, "operator"); this.operator = operator ?? null; const value = getProp(props, node, "value"); this.value = value ?? null; const quoteMark = getProp(props, node, "quoteMark"); this.quoteMark = quoteMark ?? null; const raws = node.raws; if (props.insensitiveFlag != null) this.insensitiveFlag = props.insensitiveFlag; else if (raws.insensitiveFlag != null) this.insensitiveFlag = raws.insensitiveFlag; else if (node.insensitive) this.insensitiveFlag = "i"; else this.insensitiveFlag = null; this.selector = this.refreshSelector(); } refreshSelector() { let selector = `[${this.attribute}`; if (this.operator != null) { selector += this.operator; if (this.value != null) selector += this.quoteMark ? this.quoteMark + this.value + this.quoteMark : this.value; } if (this.insensitiveFlag != null) selector += ` ${this.insensitiveFlag}`; selector += "]"; return selector; } /** * Copy * @param {object} props The optional change property. * @returns {VCSSAttributeSelector} copy node */ copy(props) { return copyStdNode(this, props); } }; /** * The CSS Pseudo node. */ var VCSSSelectorPseudo = class extends HasParentNode { /** * constructor. * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, loc, start, end, props) { super(node, "VCSSSelectorPseudo", loc, start, end, props); this.value = getProp(props, node, "value"); this.nodes = props.nodes ?? []; } /** * Copy * @param {object} props The optional change property. * @returns {VCSSSelectorPseudo} copy node */ copy(props) { return copyStdNode(this, props); } get selector() { if (!this.nodes.length) return this.value; const params = this.nodes.map((n) => n.selector).join(","); return `${this.value}(${params})`; } }; /** * The CSS Selector Combinator node. */ var VCSSSelectorCombinator = class extends HasParentNode { /** * constructor. * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, loc, start, end, props) { super(node, "VCSSSelectorCombinator", loc, start, end, props); this.value = getProp(props, node, "value"); this.selector = this.value; } /** * Copy * @param {object} props The optional change property. * @returns {VCSSSelectorCombinator} copy node */ copy(props) { return copyStdNode(this, props); } }; /** * The CSS Unknown Selector node. */ var VCSSUnknownSelector = class extends HasParentNode { /** * constructor. * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, loc, start, end, props) { super(node, "VCSSUnknownSelector", loc, start, end, props); this.value = getProp(props, node, "value") || ""; this.selector = this.value; } /** * Copy * @param {object} props The optional change property. * @returns {VCSSUnknownSelector} copy node */ copy(props) { return copyStdNode(this, props); } }; /** * The CSS Comment node. */ var VCSSComment = class VCSSComment extends HasParentNode { /** * constructor. * @param {object} node The node. * @param {string} text The contents. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, text, loc, start, end, props) { super(node, "VCSSComment", loc, start, end, props); this.node = node; this.text = text; } /** * Copy * @param {object} props The optional change property. * @returns {VCSSComment} copy node */ copy(props) { const parent = props?.parent ?? this.parent; return new VCSSComment(props?.node ?? this.node, props?.text ?? this.text, props?.loc ?? this.loc, props?.start ?? this.start, props?.end ?? this.end, { ...this, ...props, parent }); } }; /** * The CSS Inline Comment node. */ var VCSSInlineComment = class VCSSInlineComment extends HasParentNode { /** * constructor. * @param {object} node The node. * @param {string} text The contents. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {object} props The optional property. * @returns {void} */ constructor(node, text, loc, start, end, props) { super(node, "VCSSInlineComment", loc, start, end, props); this.node = node; this.text = text; } /** * Copy * @param {object} props The optional change property. * @returns {VCSSInlineComment} copy node */ copy(props) { const parent = props?.parent ?? this.parent; return new VCSSInlineComment(props?.node ?? this.node, props?.text ?? this.text, props?.loc ?? this.loc, props?.start ?? this.start, props?.end ?? this.end, { ...this, ...props, parent }); } }; /** * Get property from given props or node * @param {object} props The optional property. * @param {object} node The node. * @param {string} name name of property */ function getProp(props, node, name) { if (props?.[name] != null) return props[name]; return node[name]; } /** * Copy the given ASTNode. * @param astNode ASTNode * @param props The optional property. */ function copyStdNode(astNode, props) { const C = astNode.constructor; return new C(props?.node ?? astNode.node, props?.loc ?? astNode.loc, props?.start ?? astNode.start, props?.end ?? astNode.end, { ...astNode, ...props }); } //#endregion //#region lib/styles/utils/css-nodes.ts /** * Checks whether the given node is VCSSAtRule * @param node node to check */ function isVCSSAtRule(node) { return node?.type === "VCSSAtRule"; } /** * Checks whether the given node is VCSSStyleRule * @param node node to check */ function isVCSSStyleRule(node) { return node?.type === "VCSSStyleRule"; } /** * Checks whether the given node is VCSSStyleSheet * @param node node to check */ function isVCSSStyleSheet(node) { return node?.type === "VCSSStyleSheet"; } /** * Checks whether the given node is VCSSDeclarationProperty * @param node node to check */ function isVCSSDeclarationProperty(node) { return node?.type === "VCSSDeclarationProperty"; } /** * Checks whether the given node is VCSSComment * @param node node to check */ function isVCSSComment(node) { return node?.type === "VCSSComment" || node?.type === "VCSSInlineComment"; } /** * Checks whether the given node has nodes node * @param node node to check */ function isVCSSContainerNode(node) { return isVCSSAtRule(node) || isVCSSStyleRule(node) || isVCSSStyleSheet(node) || node?.type === "VCSSUnknown"; } /** * Checks whether the given node has selectors. */ function hasSelectorNodes(node) { if (isVCSSStyleRule(node) || isNestingAtRule(node)) return true; return false; } //#endregion //#region lib/styles/utils/selectors.ts /** * Checks whether the given node is VCSSTypeSelector * @param node node to check */ function hasNodesSelector(node) { return node != null && (node.type === "VCSSSelector" || node.type === "VCSSSelectorPseudo"); } /** * Returns the normalized result of Pseudo params. */ function normalizePseudoParams(pseudo, nodes) { const results = []; let buffer = []; for (const node of nodes) if (node.type === "VCSSSelector") { if (buffer.length) { const startNode = buffer[0]; const endNode = buffer[buffer.length - 1]; const loc = { start: startNode.loc.start, end: endNode.loc.end }; results.push(new VCSSSelector(buffer[0], loc, startNode.start, endNode.end, { parent: pseudo, nodes: buffer })); buffer = []; } results.push(node); } else buffer.push(node); if (buffer.length) { const startNode = buffer[0]; const endNode = buffer[buffer.length - 1]; const loc = { start: startNode.loc.start, end: endNode.loc.end }; results.push(new VCSSSelector(buffer[0], loc, startNode.start, endNode.end, { parent: pseudo, nodes: buffer })); buffer = []; } return results; } /** * Checks whether the given node is ::v-deep or ::v-slotted or ::v-global pseudo * @param node node to check */ function isVueSpecialPseudo(node) { return isVDeepPseudo(node) || isVSlottedPseudo(node) || isVGlobalPseudo(node); } /** * Checks whether the given node is ::v-deep pseudo for Vue.js v2 * @param node node to check */ function isVDeepPseudoV2(node) { if (isVDeepPseudo(node)) return node.nodes.length === 0; return false; } /** * Checks whether the given node is ::v-deep pseudo * @param node node to check */ function isVDeepPseudo(node) { if (isPseudo(node)) { const val = node.value.trim(); return val === "::v-deep" || val === ":deep"; } return false; } /** * Checks whether the given node is ::v-slotted pseudo * @param node node to check */ function isVSlottedPseudo(node) { if (isPseudo(node)) { const val = node.value.trim(); return val === "::v-slotted" || val === ":slotted"; } return false; } /** * Checks whether the given node is ::v-global pseudo * @param node node to check */ function isVGlobalPseudo(node) { if (isPseudo(node)) { const val = node.value.trim(); return val === "::v-global" || val === ":global"; } return false; } /** * Checks whether the given pseudo node is empty arguments * @param node node to check */ function isPseudoEmptyArguments(node) { return node.nodes.length === 0 || node.nodes.length === 1 && node.nodes[0].nodes.length === 0; } /** * Checks whether the given node is VCSSTypeSelector * @param node node to check */ function isTypeSelector(node) { return node?.type === "VCSSTypeSelector"; } /** * Checks whether the given node is VCSSIDSelector * @param node node to check */ function isIDSelector(node) { return node?.type === "VCSSIDSelector"; } /** * Checks whether the given node is VCSSSelectorNode * @param node node to check */ function isClassSelector(node) { return node?.type === "VCSSClassSelector"; } /** * Checks whether the given node is VCSSUniversalSelector * @param node node to check */ function isUniversalSelector(node) { return node?.type === "VCSSUniversalSelector"; } /** * Checks whether the given node is VCSSNestingSelector * @param node node to check */ function isNestingSelector(node) { return node?.type === "VCSSNestingSelector"; } /** * Checks whether the given node is VCSSNestingSelector * @param node node to check */ function isPseudo(node) { return node?.type === "VCSSSelectorPseudo"; } /** * Checks whether the given node is VCSSSelectorCombinator * @param node node to check */ function isSelectorCombinator(node) { return node?.type === "VCSSSelectorCombinator"; } /** * Checks whether the given node is descendant combinator * @param node node to check */ function isDescendantCombinator(node) { return isSelectorCombinator(node) && node.value.trim() === ""; } /** * Checks whether the given node is child combinator * @param node node to check */ function isChildCombinator(node) { return isSelectorCombinator(node) && node.value.trim() === ">"; } /** * Checks whether the given node is adjacent sibling combinator * @param node node to check */ function isAdjacentSiblingCombinator(node) { return isSelectorCombinator(node) && node.value.trim() === "+"; } /** * Checks whether the given node is general sibling combinator * @param node node to check */ function isGeneralSiblingCombinator(node) { return isSelectorCombinator(node) && node.value.trim() === "~"; } /** * Checks whether the given node is deep combinator * @param node node to check */ function isDeepCombinator(node) { if (isSelectorCombinator(node)) { const val = node.value.trim(); return val === ">>>" || val === "/deep/"; } return false; } /** * Checks whether the given node is nesting atrule * @param node node to check */ function isNestingAtRule(node) { if (node == null) return false; return isVCSSAtRule(node) && node.name === "nest" && node.identifier === "@"; } /** * Find nesting selectors * @param {Node[]} nodes selector nodes * @returns {IterableIterator<NestingInfo>} nesting selectors info */ function* findNestingSelectors(nodes) { for (const node of nodes) { if (isNestingSelector(node)) yield { nestingIndex: nodes.indexOf(node), node, nodes }; if (hasNodesSelector(node)) yield* findNestingSelectors(node.nodes); } } /** * Find nesting selector */ function findNestingSelector(nodes) { for (const nest of findNestingSelectors(nodes)) return nest; return null; } //#endregion //#region lib/styles/parser/utils.ts /** * Checks if the given node has nodes property. */ function isPostCSSContainer(node) { return node.nodes != null; } /** * Checks if the given node has nodes property. */ function isPostCSSSPContainer(node) { return node.nodes != null; } //#endregion //#region lib/utils/utils.ts /** * Checks whether the given context has template block */ function hasTemplateBlock(context) { const { ast } = context.sourceCode; return Boolean(ast.templateBody); } /** * Checks whether the given node has defined */ function isDefined(item) { return item !== null && item !== void 0; } //#endregion //#region lib/styles/parser/selector/css-selector-parser.ts var CSSSelectorParser = class { /** * constructor. * @param {SourceCode} sourceCode the SourceCode object that you can use to work with the source that was passed to ESLint. * @param {Node[]} commentContainer comment nodes container */ constructor(sourceCode, commentContainer) { this.lang = "css"; this.sourceCode = sourceCode; this.commentContainer = commentContainer; } /** * Parse CSS selector. * @param {string} rawSelector `<style>` node * @param {LineAndColumnData} offsetLocation start location of selector. * @param {Node} parent parent node * @return {Node[]} parsed result */ parse(rawSelector, offsetLocation, parent) { const selectorParserRoot = this.parseInternal(rawSelector); return this._postcssSelectorParserNodeChiildrenToASTNodes(offsetLocation, selectorParserRoot, parent); } parseInternal(selector) { return selectorParser().astSync(selector); } parseCommentsInternal(selector) { return selectorParser().astSync(selector); } _postcssSelectorParserNodeChiildrenToASTNodes(offsetLocation, node, parent) { const astNodes = removeInvalidDescendantCombinator(node.nodes.map((child) => this._postcssSelectorParserNodeToASTNode(offsetLocation, child, parent)).filter(isDefined)); if (astNodes.length !== node.nodes.length) { if (node.type === "selector") { const firstAstNode = astNodes[0]; parent.loc.start = { ...firstAstNode.loc.start }; parent.start = firstAstNode.start; parent.range = [firstAstNode.start, parent.range[1]]; } if (node.type === "selector") { const lastAstNode = astNodes[astNodes.length - 1]; parent.loc.end = { ...lastAstNode.loc.end }; parent.end = lastAstNode.end; parent.range = [parent.range[0], lastAstNode.end]; } } return astNodes; } /** * Convert `postcss-selector-parser` node to node that can be handled by ESLint. * @param {LineAndColumnData} offsetLocation start location of selector. * @param {object} node the `postcss-selector-parser` node to convert * @param {Node} parent parent node * @return {Node} converted node. */ _postcssSelectorParserNodeToASTNode(offsetLocation, node, parent) { const { sourceCode } = this; /** * Get index from location */ function getIndexFromLoc(loc) { if (loc.column >= 0) return sourceCode.getIndexFromLoc(loc); return sourceCode.getIndexFromLoc({ line: loc.line, column: 0 }) + loc.column; } const loc = { start: getESLintLineAndColumnFromPostCSSSelectorParserNode(offsetLocation, node, "start"), end: getESLintLineAndColumnFromPostCSSSelectorParserNode(offsetLocation, node, "end") }; const start = getIndexFromLoc(loc.start); const end = getIndexFromLoc(loc.end); const astNode = this[typeToConvertMethodName$1(node.type)](node, loc, start, end, parent); if (astNode == null) return null; this.parseRawsSpaces(astNode, node, parent); if (isPostCSSSPContainer(node)) { if (astNode.type === "VCSSSelectorPseudo") astNode.nodes = normalizePseudoParams(astNode, this._postcssSelectorParserNodeChiildrenToASTNodes(offsetLocation, node, astNode)); else if (astNode.type === "VCSSSelector") astNode.nodes = this._postcssSelectorParserNodeChiildrenToASTNodes(offsetLocation, node, astNode); } return astNode; } parseRawsSpaces(astNode, node, parent) { if (!hasRaws$1(node) || !node.raws.spaces) return; const { after, before } = node.raws.spaces; if (after?.trim()) this.parseCommentsInternal(after).walkComments((comment) => { this._postcssSelectorParserNodeToASTNode(astNode.loc.end, comment, parent); }); if (before?.trim()) { const startLoc = this.sourceCode.getLocFromIndex(astNode.range[0] - before.length); this.parseCommentsInternal(before).walkComments((comment) => { this._postcssSelectorParserNodeToASTNode(startLoc, comment, parent); }); } } /** * Convert selector Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {VCSSSelector} */ convertSelectorNode(node, loc, start, end, parent) { const sourceCode = this.sourceCode; const code = sourceCode.text; let source = code.slice(start, end); const beforeSpaces = /^\s+/u.exec(source); if (beforeSpaces?.[0]) { start = start + beforeSpaces[0].length; loc.start = this.sourceCode.getLocFromIndex(start); source = source.slice(beforeSpaces[0].length); } const afterSpaces = /\s+$/u.exec(source); if (afterSpaces?.[0]) { end = end - afterSpaces[0].length; loc.end = this.sourceCode.getLocFromIndex(end); source = source.slice(0, -afterSpaces[0].length); } adjustBeforeParenLocation(); adjustAfterParenLocation(); return new VCSSSelector(node, loc, start, end, { parent }); /** * Adjust before paren token * `:not(.bar)` * ^ */ function adjustBeforeParenLocation() { const beforeTrivials = /^\(\s*/u.exec(source); if (!beforeTrivials?.[0]) return; let withinParen = false; for (let index = end - 1; index < code.length; index++) { const ch = code[index]; if (ch === ")") { withinParen = true; break; } else if (ch?.trim() && index !== end - 1) return; } if (!withinParen) return; start = start + beforeTrivials[0].length; loc.start = sourceCode.getLocFromIndex(start); source = source.slice(beforeTrivials[0].length); } /** * Adjust after paren token * `:not(.bar)` * ^ */ function adjustAfterParenLocation() { const afterTrivials = /\s*\)$/u.exec(source); if (!afterTrivials?.[0]) return; let withinParen = false; for (let index = start - 1; index >= 0; index--) { const ch = code[index]; if (ch === "(") { withinParen = true; break; } else if (ch?.trim()) return; } if (!withinParen) return; end = end - afterTrivials[0].length; loc.end = sourceCode.getLocFromIndex(end); source = source.slice(0, -afterTrivials[0].length); } } /** * Convert tag Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {VCSSTypeSelector} */ convertTagNode(node, loc, start, end, parent) { return new VCSSTypeSelector(node, loc, start, end, { parent }); } /** * Convert id Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {VCSSIDSelector} */ convertIdNode(node, loc, start, end, parent) { return new VCSSIDSelector(node, loc, start, end, { parent }); } /** * Convert class Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {VCSSClassSelector} */ convertClassNode(node, loc, start, end, parent) { return new VCSSClassSelector(node, loc, start, end, { parent }); } /** * Convert nesting Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {VCSSNestingSelector} */ convertNestingNode(node, loc, start, end, parent) { return new VCSSNestingSelector(node, loc, start, end, { parent }); } /** * Convert universal Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {VCSSUniversalSelector} */ convertUniversalNode(node, loc, start, end, parent) { return new VCSSUniversalSelector(node, loc, start, end, { parent }); } /** * Convert attribute Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {VCSSAttributeSelector} */ convertAttributeNode(node, loc, start, end, parent) { return new VCSSAttributeSelector(node, loc, start, end, { parent }); } /** * Convert pseudo Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {VCSSSelectorPseudo} */ convertPseudoNode(node, loc, start, end, parent) { return new VCSSSelectorPseudo(node, loc, start, end, { parent }); } /** * Convert combinator Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {VCSSSelectorCombinator} */ convertCombinatorNode(node, loc, start, end, parent) { const astNode = new VCSSSelectorCombinator(node, loc, start, end, { parent }); adjustEndLocation(astNode, start + astNode.value.length, this.sourceCode); return astNode; } /** * Convert string Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {VCSSSelectorCombinator} */ convertStringNode(node, loc, start, end, parent) { const astNode = new VCSSUnknownSelector(node, loc, start, end, { parent }); adjustEndLocation(astNode, start + astNode.value.length, this.sourceCode); return astNode; } /** * Convert comment Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {null} */ convertCommentNode(node, loc, start, end, parent) { const text = node.value.replace(/^\s*\/\*/u, "").replace(/\*\/\s*$/u, ""); this.commentContainer.push(new VCSSComment(node, text, loc, start, end, { parent })); return null; } /** * Convert unknown Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {Node} */ convertUnknownTypeNode(node, loc, start, end, parent) { return new VCSSUnknownSelector(node, loc, start, end, { parent }); } }; /** * Convert `postcss-selector-parser` location to ESLint location. * @param {LineAndColumnData} offsetLocation start location of selector. * @param {object} node the `postcss-selector-parser` node to comvert * @param {"start"|"end"} locName the name of location * @return {LineAndColumnData} converted location. */ function getESLintLineAndColumnFromPostCSSSelectorParserNode(offsetLocation, node, locName) { const sourceLoc = node.source && node.source[locName] || { line: 0, column: 1 }; let { line } = sourceLoc; let column = sourceLoc.column - 1; if (line === 1) { line = offsetLocation.line; column = offsetLocation.column + column; } else line = offsetLocation.line + line - 1; if (locName === "end") column++; return { line, column }; } /** * Adjust end location */ function adjustEndLocation(astNode, endIndex, sourceCode) { if (astNode.range[1] === endIndex) return; astNode.range[1] = endIndex; astNode.end = endIndex; astNode.loc.end = sourceCode.getLocFromIndex(endIndex); let p = astNode.parent; while (p && p.end < endIndex) { p.end = endIndex; p.range[1] = endIndex; p.loc.end = { ...astNode.loc.end }; p = p.parent; } } /** * Remove invalid descendant combinators */ function removeInvalidDescendantCombinator(nodes) { const results = []; let prev = null; for (let index = 0; index < nodes.length; index++) { const node = nodes[index]; if (isDescendantCombinator(node)) { if (results.length === 0) continue; if (isSelectorCombinator(prev) || isVDeepPseudoV2(prev)) continue; const next = nodes[index + 1]; if (isSelectorCombinator(next)) continue; } else if (isVueSpecialPseudo(node)) { if (prev && !isSelectorCombinator(prev)) results.push(new VCSSSelectorCombinator(node.node, node.loc, node.start, node.end, { parent: node.parent, value: " " })); } results.push(node); prev = node; } return results; } const convertNodeTypes$1 = { tag: "convertTagNode", string: "convertStringNode", selector: "convertSelectorNode", pseudo: "convertPseudoNode", nesting: "convertNestingNode", id: "convertIdNode", comment: "convertCommentNode", combinator: "convertCombinatorNode", class: "convertClassNode", attribute: "convertAttributeNode", universal: "convertUniversalNode" }; /** * Get convert method name from given type */ function typeToConvertMethodName$1(type) { if (type === "root") return "convertUnknownTypeNode"; return convertNodeTypes$1[type] || "convertUnknownTypeNode"; } /** * Checks whether has raws */ function hasRaws$1(node) { return node.raws != null; } //#endregion //#region lib/styles/parser/css-parser.ts /** * CSS Parser */ var CSSParser = class { /** * constructor. * @param {SourceCode} sourceCode the SourceCode object that you can use to work with the source that was passed to ESLint. */ constructor(sourceCode, lang) { this._selectorParser = null; this.anyErrors = []; this.sourceCode = sourceCode; this.commentContainer = []; this.lang = lang; } /** * Parse the CSS. * @param {string} css the CSS to parse * @param {LineAndColumnData} offsetLocation start location of css. * @return {VCSSStyleSheet} parsed result */ parse(css, offsetLocation) { const { sourceCode } = this; this.commentContainer = []; this._selectorParser = this.createSelectorParser(); this.anyErrors = []; try { const postcssRoot = this.parseInternal(css); const rootNode = this._postcssNodeToASTNode(offsetLocation, postcssRoot); rootNode.comments = this.commentContainer; rootNode.errors.push(...this.collectErrors(this.anyErrors, offsetLocation)); return rootNode; } catch (e) { const startIndex = sourceCode.getIndexFromLoc(offsetLocation); const endIndex = startIndex + css.length; return new VCSSStyleSheet(null, { start: offsetLocation, end: sourceCode.getLocFromIndex(endIndex) }, startIndex, endIndex, { errors: this.collectErrors([...this.anyErrors, e], offsetLocation), lang: this.lang }); } } addError(error) { this.anyErrors.push(error); } collectErrors(errors, offsetLocation) { const errorNodes = []; const duplicate = /* @__PURE__ */ new Set(); for (const error of errors) { const errorLoc = error.line != null && error.column != null ? getESLintLineAndColumnFromPostCSSPosition(offsetLocation, error) : offsetLocation; const message = error.reason || error.message; const key = `[${errorLoc.line}:${errorLoc.column}]: ${message}`; if (duplicate.has(key)) continue; duplicate.add(key); const errorIndex = this.sourceCode.getIndexFromLoc(errorLoc); errorNodes.push(new VCSSParsingError(null, { start: errorLoc, end: errorLoc }, errorIndex, errorIndex, { lang: this.lang, message })); } return errorNodes; } get selectorParser() { return this._selectorParser || (this._selectorParser = this.createSelectorParser()); } _postcssNodeToASTNode(offsetLocation, node, parent) { const { sourceCode } = this; const startLoc = getESLintLineAndColumnFromPostCSSNode(offsetLocation, node, "start") || { line: 0, column: 1 }; const start = sourceCode.getIndexFromLoc(startLoc); const endLoc = getESLintLineAndColumnFromPostCSSNode(offsetLocation, node, "end") || sourceCode.getLocFromIndex(sourceCode.getIndexFromLoc(offsetLocation) + node.source.input.css.length); const end = sourceCode.getIndexFromLoc(endLoc); const loc = { start: startLoc, end: endLoc }; const astNode = this[typeToConvertMethodName(node.type)](node, loc, start, end, parent); if (astNode == null) return null; if (isPostCSSContainer(node) && isVCSSContainerNode(astNode)) astNode.nodes = node.nodes.map((n) => this._postcssNodeToASTNode(offsetLocation, n, astNode)).filter(isDefined); return astNode; } parseInternal(css) { try { return postcss.parse(css); } catch (e) { this.addError(e); return postcssSafeParser(css); } } createSelectorParser() { return new CSSSelectorParser(this.sourceCode, this.commentContainer); } /** * Convert root Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {VCSSStyleSheet} */ convertRootNode(node, loc, start, end) { return new VCSSStyleSheet(node, loc, start, end, { lang: this.lang }); } /** * Convert rule Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {VCSSStyleRule} */ convertRuleNode(node, loc, start, end, parent) { const astNode = new VCSSStyleRule(node, loc, start, end, { parent, rawSelectorText: this.getRaw(node, "selector")?.raw ?? null }); astNode.selectors = this.selectorParser.parse(astNode.rawSelectorText, astNode.loc.start, astNode); if (this.getRaw(node, "between")?.trim()) this.parseRuleRawsBetween(node, astNode); return astNode; } parseRuleRawsBetween(node, astNode) { const between = this.getRaw(node, "between"); const rawSelector = this.getRaw(node, "selector")?.raw ?? node.selector; const betweenStart = astNode.range[0] + rawSelector.length; const postcssRoot = this.parseInternal(between || ""); this._postcssNodeToASTNode(this.sourceCode.getLocFromIndex(betweenStart), postcssRoot); } /** * Convert atrule Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {VCSSAtRule} */ convertAtruleNode(node, loc, start, end, parent) { const astNode = new VCSSAtRule(node, loc, start, end, { parent, rawParamsText: this.getRaw(node, "params")?.raw ?? null, identifier: this.getRaw(node, "identifier") ?? "@" }); if (node.name === "nest") { const paramsStartIndex = astNode.range[0] + astNode.identifier.length + astNode.name.length + (this.getRaw(node, "afterName") || "").length; astNode.selectors = this.selectorParser.parse(astNode.rawParamsText, this.sourceCode.getLocFromIndex(paramsStartIndex), astNode); } if (this.getRaw(node, "afterName")?.trim()) this.parseAtruleRawsAfterName(node, astNode); if (this.getRaw(node, "between")?.trim()) this.parseAtruleRawsBetween(node, astNode); return astNode; } parseAtruleRawsAfterName(node, astNode) { const afterName = this.getRaw(node, "afterName"); const afterNameStart = astNode.range[0] + astNode.identifier.length + astNode.name.length; const postcssRoot = this.parseInternal(afterName || ""); this._postcssNodeToASTNode(this.sourceCode.getLocFromIndex(afterNameStart), postcssRoot); } parseAtruleRawsBetween(node, astNode) { const between = this.getRaw(node, "between"); const rawParams = this.getRaw(node, "params")?.raw ?? node.params; const betweenStart = astNode.range[0] + astNode.identifier.length + astNode.name.length + (this.getRaw(node, "afterName") || "").length + rawParams.length; const postcssRoot = this.parseInternal(between || ""); this._postcssNodeToASTNode(this.sourceCode.getLocFromIndex(betweenStart), postcssRoot); } /** * Convert decl Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {VCSSDeclarationProperty} */ convertDeclNode(node, loc, start, end, parent) { let property = node.prop; let starLength = 1; let textProp = this.sourceCode.text.slice(start, start + property.length); while (property !== textProp) { property = textProp.slice(0, starLength) + node.prop; starLength++; textProp = this.sourceCode.text.slice(start, start + property.length); } return new VCSSDeclarationProperty(node, loc, start, end, { parent, property }); } /** * Convert comment Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {void} */ convertCommentNode(node, loc, start, end, parent) { this.commentContainer.push(new VCSSComment(node, node.text, loc, start, end, { parent })); return null; } /** * Convert unknown Node * @param {object} node The node. * @param {SourceLocation} loc The location. * @param {number} start The index of start. * @param {number} end The index of end. * @param {Node} parent The parent node. * @returns {Node} */ convertUnknownTypeNode(node, loc, start, end, parent) { return new VCSSUnknown(node, loc, start, end, { parent, unknownType: node.type }); } getRaw(node, keyName) { return node.raws[keyName]; } }; /** * Convert PostCSS location to ESLint location. * @param {LineAndColumnData} offsetLocation start location of selector. * @param {object} loc the PostCSS location to convert * @return {LineAndColumnData} converted location. */ function getESLintLineAndColumnFromPostCSSPosition(offsetLocation, loc) { let { line } = loc; let column = loc.column - 1; if (line === 1) { line = offsetLocation.line; column = offsetLocation.column + column; } else line = offsetLocation.line + line - 1; return { line, column }; } /** * Convert PostCSS location to ESLint location. * @param {LineAndColumnData} offsetLocation location of inside the `<style>` node. * @param {object} node the PostCSS node to convert * @param {"start"|"end"} locName the name of location * @return {LineAndColumnData} converted location. */ function getESLintLineAndColumnFromPostCSSNode(offsetLocation, node, locName) { const sourceLoc = node.source[locName]; if (!sourceLoc) return null; const { line, column } = getESLintLineAndColumnFromPostCSSPosition(offsetLocation, sourceLoc); if (locName === "end" && node.type !== "root") return { line, column: column + 1 }; return { line, column }; } const convertNodeTypes = { root: "convertRootNode", atrule: "convertAtruleNode", rule: "convertRuleNode", decl: "convertDeclNode", comment: "convertCommentNode" }; /** * Get convert method name from given type */ function typeToConvertMethodName(type) { return convertNodeTypes[type] || "convertUnknownTypeNode"; } //#endregion //#region lib/styles/parser/load-optional-dep.ts const _require = createRequire(import.meta.url); /** * Attempts to load an optional peer dependency by name. * Returns the loaded module, or `null` if the dependency is not installed. * Re-throws any error that is NOT a MODULE_NOT_FOUND for the named package. */ function loadOptionalDep(depName) { try { return _require(depName); } catch (e) { const err = e; const message = typeof err.message === "string" ? err.message : ""; if (err.code !== "MODULE_NOT_FOUND" || !message.includes(depName)) throw err; return null; } } //#endregion //#region lib/styles/parser/selector/replace-utils.ts var SourceCodeLocationResolver = class { /** * constructor */ constructor(code) { const lineStartIndices = [0]; let match = void 0; const lineEndingPattern = /\r\n|[\n\r\u2028\u2029]/gu; while (match = lineEndingPattern.exec(code)) lineStartIndices.push(match.index + match[0].length); this.text = code; this.lineStartIndices = lineStartIndices; } /** * Converts a source text index into a (line, column) pair. * @param {number} index The index of a character in a file * @returns {object} A {line, column} location object with a 0-indexed column */ getLocFromIndex(index) { const code = this.text; const lineStartIndices = this.lineStartIndices; if (index === code.length) return { line: lineStartIndices.length, column: index - lineStartIndices[lineStartIndices.length - 1] }; const lineNumber = sortedLastIndex(lineStartIndices, index); return { line: lineNumber, column: index - lineStartIndices[lineNumber - 1] }; } /** * Converts a (line, column) pair into a range index. * @param {Object} loc A line/column location * @param {number} loc.line The line number of the location (1-indexed) * @param {number} loc.column The column number of the location (0-indexed) * @returns {number} The range index of the location in the file. * @public */ getIndexFromLoc(loc) { return this.lineStartIndices[loc.line - 1] + loc.column; } }; var RemapIndexContext = class { constructor() { this.mappers = []; this.orgIndex = 0; this.newIndex = 0; this.batchLengthOrg = 0; this.batchLengthNew = 0; } applyEq(length) { if (length <= 0) return; this.flush(); const newEnd = this.newIndex + length; const orgEnd = this.orgIndex + length;