UNPKG

@lwc/style-compiler

Version:

Transform style sheet to be consumed by the LWC engine

92 lines 4.28 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* * Copyright (c) 2018, salesforce.com, inc. * All rights reserved. * SPDX-License-Identifier: MIT * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT */ const postcss_selector_parser_1 = require("postcss-selector-parser"); const html_attributes_1 = require("../utils/html-attributes"); const DEPRECATED_SELECTORS = new Set(['/deep/', '::shadow', '>>>']); const UNSUPPORTED_SELECTORS = new Set(['::slotted', ':root', ':host-context']); function validateSelectors(root) { root.walk(node => { const { value, sourceIndex } = node; if (value) { // Ensure the selector doesn't use a deprecated CSS selector. if (DEPRECATED_SELECTORS.has(value)) { throw root.error(`Invalid usage of deprecated selector "${value}".`, { index: sourceIndex, word: value, }); } // Ensure the selector doesn't use an unsupported selector. if (UNSUPPORTED_SELECTORS.has(value)) { throw root.error(`Invalid usage of unsupported selector "${value}".`, { index: sourceIndex, word: value, }); } } }); } function validateAttribute(root) { root.walk(node => { if (postcss_selector_parser_1.isAttribute(node)) { const { attribute: attributeName, sourceIndex } = node; // Let's check if the attribute name is either a Global HTML attribute, an ARIA attribute // or a data-* attribute since those are available on all the elements. if (html_attributes_1.isGlobalAttribute(attributeName) || html_attributes_1.isAriaAttribute(attributeName) || html_attributes_1.isDataAttribute(attributeName)) { return; } // If the attribute name is not a globally available attribute, the attribute selector is required // to be associated with a tag selector, so we can validate its usage. Let's walk the compound selector // backward to find the associated tag selector. let tagSelector = undefined; let runner = node.prev(); while (tagSelector === undefined && runner !== undefined && !postcss_selector_parser_1.isCombinator(runner)) { if (postcss_selector_parser_1.isTag(runner)) { tagSelector = runner; } else { runner = runner.prev(); } } // If the tag selector is not present in the compound selector, we need to warn the user that // the compound selector need to be more specific. if (tagSelector === undefined) { const message = [ `Invalid usage of attribute selector "${attributeName}". `, `For validation purposes, attributes that are not global attributes must be associated `, `with a tag name when used in a CSS selector. (e.g., "input[min]" instead of "[min]")`, ]; throw root.error(message.join(''), { index: sourceIndex, word: attributeName, }); } // If compound selector is associated with a tag selector, we can validate the usage of the // attribute against the specific tag. const { value: tagName } = tagSelector; if (!html_attributes_1.isKnowAttributeOnElement(tagName, attributeName)) { const message = [ `Invalid usage of attribute selector "${attributeName}". `, `Attribute "${attributeName}" is not a known attribute on <${tagName}> element.`, ]; throw root.error(message.join(''), { index: sourceIndex, word: attributeName, }); } } }); } function validate(root) { validateSelectors(root); validateAttribute(root); } exports.default = validate; //# sourceMappingURL=validate.js.map