UNPKG

@stylable/core

Version:

CSS for Components

120 lines 5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.unwrapPseudoGlobals = exports.getGlobalRules = exports.hooks = exports.diagnostics = void 0; const feature_1 = require("./feature"); const plugable_record_1 = require("../helpers/plugable-record"); const selector_1 = require("../helpers/selector"); const diagnostics_1 = require("../diagnostics"); const dataKey = plugable_record_1.plugableRecord.key('globals'); exports.diagnostics = { UNSUPPORTED_MULTI_SELECTOR_IN_GLOBAL: (0, diagnostics_1.createDiagnosticReporter)('04001', 'error', () => `unsupported multi selector in :global()`), }; // HOOKS exports.hooks = (0, feature_1.createFeature)({ metaInit({ meta }) { plugable_record_1.plugableRecord.set(meta.data, dataKey, { rules: new Map() }); }, analyzeSelectorNode({ context, node, topSelectorIndex, rule, originalNode }) { var _a, _b; const { rules } = plugable_record_1.plugableRecord.getUnsafe(context.meta.data, dataKey); if (node.type === 'selector' || node.type === 'combinator' || node.type === 'comment') { return; } if (!rules.has(originalNode)) { rules.set(originalNode, { isGlobal: true, checkedRule: rule, topLevelSelectorsFlags: [], }); } const ruleData = rules.get(originalNode); if (node.type === 'pseudo_class' && node.value === `global`) { // mark selector as global only if it isn't set (_a = ruleData.topLevelSelectorsFlags)[topSelectorIndex] ?? (_a[topSelectorIndex] = true); if (node.nodes && node.nodes?.length > 1) { context.diagnostics.report(exports.diagnostics.UNSUPPORTED_MULTI_SELECTOR_IN_GLOBAL(), { node: rule, word: (0, selector_1.stringifySelector)(node.nodes), }); } return selector_1.walkSelector.skipNested; } else if (node.type === 'universal' || (node.type === 'type' && !(0, selector_1.isCompRoot)(node.value))) { // mark selector as global only if it isn't set (_b = ruleData.topLevelSelectorsFlags)[topSelectorIndex] ?? (_b[topSelectorIndex] = true); } else { // mark selector as local if it has a local selector ruleData.topLevelSelectorsFlags[topSelectorIndex] = false; } return; }, analyzeSelectorDone({ context, originalNode }) { const { rules } = plugable_record_1.plugableRecord.getUnsafe(context.meta.data, dataKey); const data = rules.get(originalNode); if (!data) { return; } // require at least one global selector in rule selectors if (!data.topLevelSelectorsFlags.find((isGlobal) => isGlobal)) { data.isGlobal = false; return; } // rule is global if it doesn't have any local parents let parent = originalNode.parent; while (parent) { const parentData = rules.get(parent); if (parentData) { // quick resolution: parent calculated first data.isGlobal = parentData.isGlobal; break; } // keep searching parent = parent.parent; } }, transformInit({ context }) { context.meta.globals = {}; }, transformLastPass({ context: { meta }, ast }) { ast.walkRules((r) => { if (!r.selector.includes(`:global(`)) { return; } const selectorAst = (0, selector_1.parseSelectorWithCache)(r.selector, { clone: true }); (0, selector_1.walkSelector)(unwrapPseudoGlobals(selectorAst), (inner) => { if (inner.type === 'class') { meta.globals[inner.value] = true; } }); r.selector = (0, selector_1.stringifySelector)(selectorAst); }); }, }); // API function getGlobalRules(meta) { const { rules } = plugable_record_1.plugableRecord.getUnsafe(meta.data, dataKey); const globalRules = []; for (const [rule, { isGlobal, checkedRule }] of rules) { if (isGlobal && checkedRule === rule && rule.type === 'rule') { globalRules.push(rule); } } return globalRules; } exports.getGlobalRules = getGlobalRules; function unwrapPseudoGlobals(selectorAst) { const collectedGlobals = []; (0, selector_1.walkSelector)(selectorAst, (node) => { if (node.type === 'pseudo_class' && node.value === 'global') { if (node.nodes?.length === 1) { collectedGlobals.push((0, selector_1.flattenFunctionalSelector)(node)); } return selector_1.walkSelector.skipNested; } return; }); return collectedGlobals; } exports.unwrapPseudoGlobals = unwrapPseudoGlobals; //# sourceMappingURL=st-global.js.map