@stylable/core
Version:
CSS for Components
277 lines • 11.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.processNamespace = exports.StylableProcessor = void 0;
const diagnostics_1 = require("./diagnostics");
const native_reserved_lists_1 = require("./native-reserved-lists");
const stylable_meta_1 = require("./stylable-meta");
const features_1 = require("./features");
const diagnostics_2 = require("./features/diagnostics");
const features_2 = require("./features");
const process_declaration_functions_1 = require("./process-declaration-functions");
const selector_1 = require("./helpers/selector");
const rule_1 = require("./helpers/rule");
const feature_1 = require("./features/feature");
class StylableProcessor {
constructor(diagnostics = new diagnostics_1.Diagnostics(), resolveNamespace = features_2.STNamespace.defaultProcessNamespace, flags = { ...feature_1.defaultFeatureFlags }) {
this.diagnostics = diagnostics;
this.resolveNamespace = resolveNamespace;
this.flags = flags;
}
process(root) {
this.meta = new stylable_meta_1.StylableMeta(root, this.diagnostics, this.flags);
features_2.STStructure.hooks.analyzeInit(this);
features_2.STImport.hooks.analyzeInit(this);
features_1.CSSCustomProperty.hooks.analyzeInit(this);
this.handleAtRules(root);
root.walkRules((rule) => {
if (!(0, rule_1.isChildOfAtRule)(rule, 'keyframes')) {
this.handleRule(rule, {
isScoped: (0, rule_1.isChildOfAtRule)(rule, `st-scope`),
reportUnscoped: true,
});
}
});
root.walkDecls((decl) => {
features_2.CSSClass.hooks.analyzeDeclaration({ context: this, decl });
features_1.CSSCustomProperty.hooks.analyzeDeclaration({ context: this, decl });
features_2.CSSContains.hooks.analyzeDeclaration({ context: this, decl });
this.collectUrls(decl);
});
features_2.STNamespace.hooks.analyzeDone(this);
features_1.STCustomSelector.hooks.analyzeDone(this);
features_2.STStructure.hooks.analyzeDone(this);
features_2.STNamespace.setMetaNamespace(this, this.resolveNamespace);
features_2.STSymbol.reportRedeclare(this);
return this.meta;
}
handleAtRules(root) {
const analyzeRule = (rule, { isScoped, originalNode, }) => {
return this.handleRule(rule, {
isScoped,
originalNode,
reportUnscoped: false,
});
};
root.walkAtRules((atRule) => {
switch (atRule.name) {
case 'st-import': {
features_2.STImport.hooks.analyzeAtRule({
context: this,
atRule,
analyzeRule,
});
break;
}
case 'namespace':
case 'st-namespace': {
features_2.STNamespace.hooks.analyzeAtRule({
context: this,
atRule,
analyzeRule,
});
break;
}
case 'keyframes':
features_2.CSSKeyframes.hooks.analyzeAtRule({
context: this,
atRule,
analyzeRule,
});
break;
case 'layer':
features_2.CSSLayer.hooks.analyzeAtRule({
context: this,
atRule,
analyzeRule,
});
break;
case 'import':
features_2.STImport.hooks.analyzeAtRule({
context: this,
atRule,
analyzeRule,
});
features_2.CSSLayer.hooks.analyzeAtRule({
context: this,
atRule,
analyzeRule,
});
break;
case 'custom-selector': {
features_1.STCustomSelector.hooks.analyzeAtRule({
context: this,
atRule,
analyzeRule,
});
break;
}
case 'st-scope':
features_2.STScope.hooks.analyzeAtRule({ context: this, atRule, analyzeRule });
break;
case 'property':
case 'st-global-custom-property': {
features_1.CSSCustomProperty.hooks.analyzeAtRule({
context: this,
atRule,
analyzeRule,
});
break;
}
case 'container': {
features_2.CSSContains.hooks.analyzeAtRule({
context: this,
atRule,
analyzeRule,
});
break;
}
case 'st': {
features_2.STStructure.hooks.analyzeAtRule({
context: this,
atRule,
analyzeRule,
});
break;
}
}
});
}
collectUrls(decl) {
(0, process_declaration_functions_1.processDeclarationFunctions)(decl, (node) => {
if (node.type === 'url') {
this.meta.urls.push(node.url);
}
}, false);
}
handleRule(rule, { isScoped, reportUnscoped, originalNode = rule, }) {
const selectorAst = (0, selector_1.parseSelectorWithCache)(rule.selector);
let locallyScoped = isScoped;
let topSelectorIndex = -1;
(0, selector_1.walkSelector)(selectorAst, (node, ...nodeContext) => {
const [index, nodes, parents] = nodeContext;
const type = node.type;
if (type === 'selector' && !(0, selector_1.isInPseudoClassContext)(parents)) {
// reset scope check between top level selectors
locallyScoped = isScoped;
topSelectorIndex++;
}
const walkSkip = features_2.STGlobal.hooks.analyzeSelectorNode({
context: this,
node,
topSelectorIndex,
rule,
originalNode,
walkContext: nodeContext,
});
if (walkSkip !== undefined) {
return walkSkip;
}
if (node.type === 'pseudo_class') {
if (node.value === 'import') {
features_2.STImport.hooks.analyzeSelectorNode({
context: this,
node,
topSelectorIndex,
rule,
originalNode,
walkContext: nodeContext,
});
}
else if (node.value === 'vars') {
return features_1.STVar.hooks.analyzeSelectorNode({
context: this,
node,
topSelectorIndex,
rule,
originalNode,
walkContext: nodeContext,
});
}
else if (node.value.startsWith('--')) {
// ToDo: move to css-class feature
locallyScoped =
locallyScoped ||
features_1.STCustomSelector.isScoped(this.meta, node.value.slice(2)) ||
false;
}
else if (!native_reserved_lists_1.knownPseudoClassesWithNestedSelectors.includes(node.value)) {
return selector_1.walkSelector.skipNested;
}
}
else if (node.type === 'class') {
features_2.CSSClass.hooks.analyzeSelectorNode({
context: this,
node,
topSelectorIndex,
rule,
originalNode,
walkContext: nodeContext,
});
locallyScoped = features_2.CSSClass.validateClassScoping({
context: this,
classSymbol: features_2.CSSClass.get(this.meta, node.value),
locallyScoped,
reportUnscoped,
node,
nodes,
index,
rule,
});
}
else if (node.type === 'type') {
features_2.CSSType.hooks.analyzeSelectorNode({
context: this,
node,
topSelectorIndex,
rule,
originalNode,
walkContext: nodeContext,
});
locallyScoped = features_2.CSSType.validateTypeScoping({
context: this,
locallyScoped,
reportUnscoped,
node,
nodes,
index,
rule,
});
}
else if (node.type === `id`) {
if (node.nodes) {
this.diagnostics.report(diagnostics_2.generalDiagnostics.INVALID_FUNCTIONAL_SELECTOR(`#` + node.value, `id`), {
node: rule,
word: (0, selector_1.stringifySelector)(node),
});
}
}
else if (node.type === `attribute`) {
if (node.nodes) {
this.diagnostics.report(diagnostics_2.generalDiagnostics.INVALID_FUNCTIONAL_SELECTOR(`[${node.value}]`, `attribute`), {
node: rule,
word: (0, selector_1.stringifySelector)(node),
});
}
}
else if (node.type === `nesting`) {
if (node.nodes) {
this.diagnostics.report(diagnostics_2.generalDiagnostics.INVALID_FUNCTIONAL_SELECTOR(node.value, `nesting`), {
node: rule,
word: (0, selector_1.stringifySelector)(node),
});
}
}
return;
});
features_2.STGlobal.hooks.analyzeSelectorDone({
context: this,
rule,
originalNode,
});
return locallyScoped;
}
}
exports.StylableProcessor = StylableProcessor;
// ToDo: remove export and reroute import from feature
exports.processNamespace = features_2.STNamespace.defaultProcessNamespace;
//# sourceMappingURL=stylable-processor.js.map