@lwc/style-compiler
Version:
Transform style sheet to be consumed by the LWC engine
92 lines • 4.28 kB
JavaScript
;
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