/*
 * Copyright (c) 2018, 2026, Oracle and/or its affiliates.
 * Licensed under The Universal Permissive License (UPL), Version 1.0
 * as shown at https://oss.oracle.com/licenses/upl/
 */
const Utils=require("../jetwc-lib/jetwcutils-componentAuditUtils");const path=require("path");const ruleDef=function(){};ruleDef.prototype.getName=function(){return"jetwc-css-scoping"};ruleDef.prototype.getShortDescription=function(){return"Verify that any styles defined by a component are correctly scoped"};ruleDef.prototype.getDescription=function(){return"Any style defined by a custom component should be scoped to only operate in the context of that component so as not to bleed through to the rest of the page and cause unexpected side effects"};ruleDef.prototype.register=function(context){return{"css-rule":this._doAudit,"css-atrule":this._doAudit}};ruleDef.prototype._doAudit=function(context,cssRule,indentifier){const withinComponent=Utils.matchComponentPath(context,path.dirname(context.filepath));if(withinComponent){const componentInfo=Utils.componentInfo(context,withinComponent);const ruleOptions=context.rulePack.getRuleCustomOptions();let validPrefixes=[];let packContext;if(componentInfo.type==="resource"){packContext=componentInfo.pack;if(packContext){const packInfo=Utils.componentInfo(context,packContext);const packJson=path.join(packInfo.rootFolder,"component.json");const packDef=context.utils.fsUtils.readJsonSync(packJson);validPrefixes=validPrefixes.concat(Object.keys(packDef.dependencies))}}else{validPrefixes.push(withinComponent)}let relaxedForPack=false;if(componentInfo.pack&&ruleOptions?.allowPackScoping){validPrefixes.push(componentInfo.pack);relaxedForPack=true}let globalIgnore=["html","body","oj-color-invert","from","to"];if(ruleOptions?.ignoreScopes&&Array.isArray(ruleOptions.ignoreScopes)){globalIgnore=globalIgnore.concat(ruleOptions.ignoreScopes)}let ruleSelectorName,ruleSelectorType;if(cssRule.type==="Atrule"){ruleSelectorType=cssRule.type;if(cssRule.prelude?.type==="AtrulePrelude"&&cssRule.prelude?.children?.[0]&&cssRule.prelude?.children?.[0].type==="Identifier"){ruleSelectorName=cssRule.prelude.children[0].name}}else{for(let i=0;i<cssRule.prelude.children[0].children.length;i++){const selector=cssRule.prelude.children[0].children[i];if(selector.type==="TypeSelector"&&!globalIgnore.includes(selector.name)){ruleSelectorType=selector.type;ruleSelectorName=selector.name;break}else if(selector.type==="ClassSelector"&&!globalIgnore.includes(selector.name)){ruleSelectorType=selector.type;ruleSelectorName=selector.name;break}}}let errorMessage;let validScopes=`by the custom component tag name: ${withinComponent}`;if(ruleSelectorName&&ruleSelectorType){if(ruleSelectorType==="TypeSelector"){if(!validPrefixes.includes(ruleSelectorName)){if(packContext){validScopes=`by the tag name of one of the custom elements in the pack: ${packContext}`}errorMessage=`CSS Type selector ${ruleSelectorName} must be scoped ${validScopes}`}}else if(ruleSelectorType==="ClassSelector"||ruleSelectorType==="Atrule"){if(packContext){validPrefixes.push(packContext);validScopes=`by the one of the tag names of one of the custom elements in the pack: ${packContext}`}const matchingPrefixes=validPrefixes.filter(prefix=>ruleSelectorName.startsWith(prefix));if(matchingPrefixes.length===0){errorMessage=`Error in class selector naming for class: ${ruleSelectorName}. CSS Class selectors used by custom components must be scoped ${validScopes}${relaxedForPack?" or the pack name itself":""}`}}}if(errorMessage){if(!Utils.shouldIgnoreCheck(context,this.getName(),withinComponent)){const issue=new context.Issue(errorMessage);context.reporter.addIssue(issue,context)}}}};module.exports=ruleDef;