@stylable/core
Advanced tools
Comparing version 0.1.13 to 0.1.14
@@ -23,2 +23,3 @@ import * as postcss from 'postcss'; | ||
export declare const createSimpleSelectorChecker: () => (node: SelectorAstNode) => boolean; | ||
export declare function isSimpleSelector(selectorAst: SelectorAstNode): boolean | void; | ||
export declare function isImport(ast: SelectorAstNode): boolean; | ||
@@ -37,5 +38,5 @@ export declare function matchAtKeyframes(selector: string): RegExpMatchArray | null; | ||
export declare function fixChunkOrdering(selectorNode: SelectorAstNode, prefixType: SelectorAstNode): void; | ||
export declare function isChildOfAtRule(rule: postcss.Rule, atRuleName: string): boolean; | ||
export declare function isChildOfAtRule(rule: postcss.Container, atRuleName: string): boolean; | ||
export declare function isCompRoot(name: string): RegExpMatchArray | null; | ||
export declare function createWarningRule(extendedNode: string, scopedExtendedNode: string, extendedFile: string, extendingNode: string, scopedExtendingNode: string, extendingFile: string): postcss.Rule; | ||
//# sourceMappingURL=selector-utils.d.ts.map |
@@ -48,5 +48,2 @@ "use strict"; | ||
doNext = traverseNode(node.nodes[i], visitor, i, node.nodes); | ||
if (doNext === true) { | ||
continue; | ||
} | ||
if (doNext === false) { | ||
@@ -110,2 +107,8 @@ return false; | ||
exports.createSimpleSelectorChecker = createChecker(['selectors', 'selector', ['element', 'class']]); | ||
function isSimpleSelector(selectorAst) { | ||
var isSimpleSelectorASTNode = exports.createSimpleSelectorChecker(); | ||
var isSimple = traverseNode(selectorAst, function (node) { return (isSimpleSelectorASTNode(node) !== false /*stop on complex selector */); }); | ||
return isSimple; | ||
} | ||
exports.isSimpleSelector = isSimpleSelector; | ||
function isImport(ast) { | ||
@@ -244,3 +247,3 @@ var selectors = ast.nodes[0]; | ||
function isChildOfAtRule(rule, atRuleName) { | ||
return rule.parent && rule.parent.type === 'atrule' && rule.parent.name === atRuleName; | ||
return !!rule.parent && rule.parent.type === 'atrule' && rule.parent.name === atRuleName; | ||
} | ||
@@ -247,0 +250,0 @@ exports.isChildOfAtRule = isChildOfAtRule; |
@@ -25,2 +25,3 @@ import * as postcss from 'postcss'; | ||
transformDiagnostics: Diagnostics | null; | ||
scopes: postcss.AtRule[]; | ||
constructor(ast: postcss.Root, diagnostics: Diagnostics); | ||
@@ -27,0 +28,0 @@ } |
@@ -33,2 +33,3 @@ "use strict"; | ||
this.urls = []; | ||
this.scopes = []; | ||
this.transformDiagnostics = null; | ||
@@ -35,0 +36,0 @@ } |
@@ -26,2 +26,7 @@ import * as postcss from 'postcss'; | ||
MULTIPLE_FROM_IN_IMPORT(): string; | ||
NO_VARS_DEF_IN_ST_SCOPE(): string; | ||
NO_IMPORT_IN_ST_SCOPE(): string; | ||
NO_KEYFRAMES_IN_ST_SCOPE(): string; | ||
SCOPE_PARAM_NOT_SIMPLE_SELECTOR(selector: string): string; | ||
MISSING_SCOPING_PARAM(): string; | ||
}; | ||
@@ -37,3 +42,3 @@ export declare class StylableProcessor { | ||
protected handleAtRules(root: postcss.Root): void; | ||
protected handleRule(rule: SRule): void; | ||
protected handleRule(rule: SRule, inStScope?: boolean): void; | ||
protected checkRedeclareSymbol(symbolName: string, node: postcss.Node): void; | ||
@@ -49,2 +54,3 @@ protected addElementSymbolOnce(name: string, rule: postcss.Rule): void; | ||
} | ||
export declare function validateScopingSelector(atRule: postcss.AtRule, { selector: scopingSelector, isSimpleSelector }: SRule, diagnostics: Diagnostics): void; | ||
export declare function createEmptyMeta(root: postcss.Root, diagnostics: Diagnostics): StylableMeta; | ||
@@ -51,0 +57,0 @@ export declare function processNamespace(namespace: string, source: string): string; |
@@ -34,8 +34,8 @@ "use strict"; | ||
exports.processorWarnings = { | ||
UNSCOPED_CLASS: function (name) { return "unscoped native element \"" + name + "\" will affect all elements of the same type in the document"; }, | ||
UNSCOPED_ELEMENT: function (name) { return "unscoped native element \"" + name + "\" will affect all elements of the same type in the document"; }, | ||
UNSCOPED_CLASS: function (name) { return "unscoped class \"" + name + "\" will affect all elements of the same type in the document"; }, | ||
UNSCOPED_ELEMENT: function (name) { return "unscoped element \"" + name + "\" will affect all elements of the same type in the document"; }, | ||
FORBIDDEN_DEF_IN_COMPLEX_SELECTOR: function (name) { return "cannot define \"" + name + "\" inside a complex selector"; }, | ||
ROOT_AFTER_SPACING: function () { return '".root" class cannot be used after native elements or selectors external to the stylesheet'; }, | ||
DEFAULT_IMPORT_IS_LOWER_CASE: function () { return 'Default import of a Stylable stylesheet must start with an upper-case letter'; }, | ||
ILLEGAL_PROP_IN_IMPORT: function (propName) { return "\"" + propName + "\" css attribute cannot be used inside :import block"; }, | ||
ILLEGAL_PROP_IN_IMPORT: function (propName) { return "\"" + propName + "\" css attribute cannot be used inside " + stylable_value_parsers_1.rootValueMapping.import + " block"; }, | ||
STATE_DEFINITION_IN_ELEMENT: function () { return 'cannot define pseudo states inside element selectors'; }, | ||
@@ -49,7 +49,12 @@ STATE_DEFINITION_IN_COMPLEX: function () { return 'cannot define pseudo states inside complex selectors'; }, | ||
OVERRIDE_TYPED_RULE: function (key, name) { return "override \"" + key + "\" on typed rule \"" + name + "\""; }, | ||
FROM_PROP_MISSING_IN_IMPORT: function () { return "\"" + stylable_value_parsers_1.valueMapping.from + "\" is missing in :import block"; }, | ||
FROM_PROP_MISSING_IN_IMPORT: function () { return "\"" + stylable_value_parsers_1.valueMapping.from + "\" is missing in " + stylable_value_parsers_1.rootValueMapping.import + " block"; }, | ||
INVALID_NAMESPACE_DEF: function () { return 'invalid @namespace'; }, | ||
EMPTY_NAMESPACE_DEF: function () { return '@namespace must contain at least one character or digit'; }, | ||
EMPTY_IMPORT_FROM: function () { return '"-st-from" cannot be empty'; }, | ||
MULTIPLE_FROM_IN_IMPORT: function () { return "cannot define multiple \"" + stylable_value_parsers_1.valueMapping.from + "\" declarations in a single import"; } | ||
MULTIPLE_FROM_IN_IMPORT: function () { return "cannot define multiple \"" + stylable_value_parsers_1.valueMapping.from + "\" declarations in a single import"; }, | ||
NO_VARS_DEF_IN_ST_SCOPE: function () { return "cannot define \"" + stylable_value_parsers_1.rootValueMapping.vars + "\" inside of \"@st-scope\""; }, | ||
NO_IMPORT_IN_ST_SCOPE: function () { return "cannot use \"" + stylable_value_parsers_1.rootValueMapping.import + "\" inside of \"@st-scope\""; }, | ||
NO_KEYFRAMES_IN_ST_SCOPE: function () { return "cannot use \"@keyframes\" inside of \"@st-scope\""; }, | ||
SCOPE_PARAM_NOT_SIMPLE_SELECTOR: function (selector) { return "\"@st-scope\" must receive a simple selector, but instead got: \"" + selector + "\""; }, | ||
MISSING_SCOPING_PARAM: function () { return '"@st-scope" must receive a simple selector or stylesheet "root" as its scoping parameter'; } | ||
}; | ||
@@ -72,3 +77,3 @@ /* tslint:enable:max-line-length */ | ||
_this.handleCustomSelectors(rule); | ||
_this.handleRule(rule); | ||
_this.handleRule(rule, selector_utils_1.isChildOfAtRule(rule, stylable_value_parsers_1.rootValueMapping.stScope)); | ||
} | ||
@@ -84,2 +89,13 @@ }); | ||
}); | ||
this.meta.scopes.forEach(function (atRule) { | ||
var scopingRule = postcss.rule({ selector: atRule.params }); | ||
_this.handleRule(scopingRule, true); | ||
validateScopingSelector(atRule, scopingRule, _this.diagnostics); | ||
if (scopingRule.selector) { | ||
atRule.walkRules(function (rule) { | ||
rule.replaceWith(rule.clone({ selector: scopingRule.selector + " " + rule.selector })); | ||
}); | ||
} | ||
atRule.replaceWith(atRule.nodes || []); | ||
}); | ||
stubs.forEach(function (s) { return s && s.remove(); }); | ||
@@ -124,3 +140,8 @@ return this.meta; | ||
case 'keyframes': | ||
_this.meta.keyframes.push(atRule); | ||
if (!selector_utils_1.isChildOfAtRule(atRule, stylable_value_parsers_1.rootValueMapping.stScope)) { | ||
_this.meta.keyframes.push(atRule); | ||
} | ||
else { | ||
_this.diagnostics.warn(atRule, exports.processorWarnings.NO_KEYFRAMES_IN_ST_SCOPE()); | ||
} | ||
break; | ||
@@ -138,2 +159,5 @@ case 'custom-selector': | ||
break; | ||
case 'st-scope': | ||
_this.meta.scopes.push(atRule); | ||
break; | ||
} | ||
@@ -145,4 +169,5 @@ }); | ||
}; | ||
StylableProcessor.prototype.handleRule = function (rule) { | ||
StylableProcessor.prototype.handleRule = function (rule, inStScope) { | ||
var _this = this; | ||
if (inStScope === void 0) { inStScope = false; } | ||
rule.selectorAst = selector_utils_1.parseSelector(rule.selector); | ||
@@ -159,3 +184,8 @@ var checker = selector_utils_1.createSimpleSelectorChecker(); | ||
if (name === 'import') { | ||
if (rule.selector === ':import') { | ||
if (rule.selector === stylable_value_parsers_1.rootValueMapping.import) { | ||
if (selector_utils_1.isChildOfAtRule(rule, stylable_value_parsers_1.rootValueMapping.stScope)) { | ||
_this.diagnostics.warn(rule, exports.processorWarnings.NO_IMPORT_IN_ST_SCOPE()); | ||
rule.remove(); | ||
return false; | ||
} | ||
var _import = _this.handleImport(rule); | ||
@@ -167,7 +197,12 @@ _this.meta.imports.push(_import); | ||
else { | ||
_this.diagnostics.warn(rule, exports.processorWarnings.FORBIDDEN_DEF_IN_COMPLEX_SELECTOR(':import')); | ||
_this.diagnostics.warn(rule, exports.processorWarnings.FORBIDDEN_DEF_IN_COMPLEX_SELECTOR(stylable_value_parsers_1.rootValueMapping.import)); | ||
} | ||
} | ||
else if (name === 'vars') { | ||
if (rule.selector === ':vars') { | ||
if (rule.selector === stylable_value_parsers_1.rootValueMapping.vars) { | ||
if (selector_utils_1.isChildOfAtRule(rule, stylable_value_parsers_1.rootValueMapping.stScope)) { | ||
_this.diagnostics.warn(rule, exports.processorWarnings.NO_VARS_DEF_IN_ST_SCOPE()); | ||
rule.remove(); | ||
return false; | ||
} | ||
_this.addVarSymbols(rule); | ||
@@ -177,3 +212,3 @@ return false; | ||
else { | ||
_this.diagnostics.warn(rule, exports.processorWarnings.FORBIDDEN_DEF_IN_COMPLEX_SELECTOR(':vars')); | ||
_this.diagnostics.warn(rule, exports.processorWarnings.FORBIDDEN_DEF_IN_COMPLEX_SELECTOR(stylable_value_parsers_1.rootValueMapping.vars)); | ||
} | ||
@@ -195,3 +230,3 @@ } | ||
_this.addElementSymbolOnce(name, rule); | ||
if (locallyScoped === false) { | ||
if (locallyScoped === false && !inStScope) { | ||
_this.diagnostics.warn(rule, exports.processorWarnings.UNSCOPED_ELEMENT(name), { word: name }); | ||
@@ -425,2 +460,12 @@ } | ||
exports.StylableProcessor = StylableProcessor; | ||
function validateScopingSelector(atRule, _a, diagnostics) { | ||
var scopingSelector = _a.selector, isSimpleSelector = _a.isSimpleSelector; | ||
if (!scopingSelector) { | ||
diagnostics.warn(atRule, exports.processorWarnings.MISSING_SCOPING_PARAM()); | ||
} | ||
else if (!isSimpleSelector) { | ||
diagnostics.warn(atRule, exports.processorWarnings.SCOPE_PARAM_NOT_SIMPLE_SELECTOR(scopingSelector), { word: scopingSelector }); | ||
} | ||
} | ||
exports.validateScopingSelector = validateScopingSelector; | ||
function createEmptyMeta(root, diagnostics) { | ||
@@ -427,0 +472,0 @@ utils_1.deprecated('createEmptyMeta is deprecated and will be removed in the next version. Use "new StylableMeta()"'); |
@@ -61,2 +61,5 @@ import * as postcss from 'postcss'; | ||
UNKNOWN_IMPORT_ALIAS(name: string): string; | ||
SCOPE_PARAM_NOT_ROOT(name: string): string; | ||
SCOPE_PARAM_NOT_CSS(name: string): string; | ||
UNKNOWN_SCOPING_PARAM(name: string): string; | ||
}; | ||
@@ -63,0 +66,0 @@ export declare class StylableTransformer { |
@@ -26,3 +26,6 @@ "use strict"; | ||
KEYFRAME_NAME_RESERVED: function (name) { return "keyframes \"" + name + "\" is reserved"; }, | ||
UNKNOWN_IMPORT_ALIAS: function (name) { return "cannot use alias for unknown import \"" + name + "\""; } | ||
UNKNOWN_IMPORT_ALIAS: function (name) { return "cannot use alias for unknown import \"" + name + "\""; }, | ||
SCOPE_PARAM_NOT_ROOT: function (name) { return "\"@st-scope\" parameter \"" + name + "\" does not resolve to a stylesheet root"; }, | ||
SCOPE_PARAM_NOT_CSS: function (name) { return "\"@st-scope\" parameter \"" + name + "\" must be a Stylable stylesheet, instead name originated from a JavaScript file"; }, | ||
UNKNOWN_SCOPING_PARAM: function (name) { return "\"@st-scope\" received an unknown symbol: \"" + name + "\""; } | ||
}; | ||
@@ -55,2 +58,3 @@ /* tslint:enable:max-line-length */ | ||
this.resolver.validateImports(meta, this.diagnostics); | ||
validateScopes(meta, this.resolver, this.diagnostics); | ||
ast.walkRules(function (rule) { | ||
@@ -555,2 +559,31 @@ if (selector_utils_1.isChildOfAtRule(rule, 'keyframes')) { | ||
exports.removeSTDirective = removeSTDirective; | ||
function validateScopes(meta, resolver, diagnostics) { | ||
for (var _i = 0, _a = meta.scopes; _i < _a.length; _i++) { | ||
var scope = _a[_i]; | ||
var name_1 = scope.params.startsWith('.') ? scope.params.slice(1) : scope.params; | ||
if (!name_1) { | ||
continue; | ||
} | ||
else if (!meta.mappedSymbols[name_1]) { | ||
diagnostics.error(scope, exports.transformerWarnings.UNKNOWN_SCOPING_PARAM(scope.params), { word: scope.params }); | ||
continue; | ||
} | ||
var resolvedScope = resolver.deepResolve(meta.mappedSymbols[name_1]); | ||
if (resolvedScope && resolvedScope._kind === 'css') { | ||
var scopingMeta = resolvedScope.meta, scopingSymbol = resolvedScope.symbol; | ||
if (scopingSymbol.name !== scopingMeta.root) { | ||
diagnostics.error(scope, exports.transformerWarnings.SCOPE_PARAM_NOT_ROOT(scope.params), { word: scope.params }); | ||
} | ||
} | ||
else if (resolvedScope && resolvedScope._kind === 'js') { | ||
diagnostics.error(scope, exports.transformerWarnings.SCOPE_PARAM_NOT_CSS(scope.params), { word: scope.params }); | ||
} | ||
else if (meta.classes[name_1] || meta.elements[scope.params] && meta.elements[scope.params].alias) { | ||
// do nothing valid input | ||
} | ||
else { | ||
diagnostics.error(scope, exports.transformerWarnings.UNKNOWN_SCOPING_PARAM(scope.params), { word: scope.params }); | ||
} | ||
} | ||
} | ||
//# sourceMappingURL=stylable-transformer.js.map |
@@ -30,2 +30,8 @@ import * as postcss from 'postcss'; | ||
} | ||
export declare const rootValueMapping: { | ||
vars: ":vars"; | ||
import: ":import"; | ||
stScope: "st-scope"; | ||
namespace: "namespace"; | ||
}; | ||
export declare const valueMapping: { | ||
@@ -32,0 +38,0 @@ from: "-st-from"; |
@@ -20,2 +20,8 @@ "use strict"; | ||
}; | ||
exports.rootValueMapping = { | ||
vars: ':vars', | ||
import: ':import', | ||
stScope: 'st-scope', | ||
namespace: 'namespace' | ||
}; | ||
exports.valueMapping = { | ||
@@ -22,0 +28,0 @@ from: '-st-from', |
@@ -268,3 +268,5 @@ "use strict"; | ||
it('should return warning when defined in a complex selector', function () { | ||
diagnostics_1.expectWarnings("\n |.gaga:vars|{\n myColor:red;\n }\n\n ", [{ message: stylable_processor_1.processorWarnings.FORBIDDEN_DEF_IN_COMPLEX_SELECTOR(':vars'), file: 'main.css' }]); | ||
diagnostics_1.expectWarnings("\n |.gaga:vars|{\n myColor:red;\n }\n\n ", | ||
// tslint:disable-next-line:max-line-length | ||
[{ message: stylable_processor_1.processorWarnings.FORBIDDEN_DEF_IN_COMPLEX_SELECTOR(stylable_value_parsers_1.rootValueMapping.vars), file: 'main.css' }]); | ||
}); | ||
@@ -271,0 +273,0 @@ }); |
import { StylableResults } from '../../src/index'; | ||
import { StylableMeta } from '../../src/stylable-processor'; | ||
import { Config } from './generate-test-util'; | ||
export interface Diagnostic { | ||
severity?: 'warn' | 'error'; | ||
severity?: 'warning' | 'error'; | ||
message: string; | ||
@@ -24,2 +25,3 @@ file: string; | ||
export declare function expectWarningsFromTransform(config: Config, warnings: Diagnostic[]): StylableResults; | ||
export declare function shouldReportNoDiagnostics(meta: StylableMeta, checkTransformDiagnostics?: boolean): void; | ||
//# sourceMappingURL=diagnostics.d.ts.map |
@@ -50,10 +50,15 @@ "use strict"; | ||
res.diagnostics.reports.forEach(function (report, i) { | ||
if (warnings[i].skip) { | ||
var expectedWarning = warnings[i]; | ||
if (expectedWarning.skip) { | ||
return; | ||
} | ||
chai_1.expect(report.message).to.equal(warnings[i].message); | ||
chai_1.expect(report.message).to.equal(expectedWarning.message); | ||
chai_1.expect(report.node.source.start, 'start').to.eql(source.start); | ||
if (source.word !== null) { | ||
chai_1.expect(report.options.word).to.eql(source.word); | ||
chai_1.expect(report.options.word).to.equal(source.word); | ||
} | ||
if (expectedWarning.severity) { | ||
chai_1.expect(report.type, "diagnostics severity mismatch, expected \"" + expectedWarning.severity + "\" but received \"" + report.type + "\"") | ||
.to.equal(expectedWarning.severity); | ||
} | ||
}); | ||
@@ -77,5 +82,6 @@ chai_1.expect(res.diagnostics.reports.length, 'diagnostics reports match').to.equal(warnings.length); | ||
diagnostics.reports.forEach(function (report, i) { | ||
var path = warnings[i].file; | ||
chai_1.expect(report.message).to.equal(warnings[i].message); | ||
if (!warnings[i].skipLocationCheck) { | ||
var expectedWarning = warnings[i]; | ||
var path = expectedWarning.file; | ||
chai_1.expect(report.message).to.equal(expectedWarning.message); | ||
if (!expectedWarning.skipLocationCheck) { | ||
chai_1.expect(report.node.source.start).to.eql(locations[path].start); | ||
@@ -86,2 +92,6 @@ } | ||
} | ||
if (expectedWarning.severity) { | ||
chai_1.expect(report.type, "diagnostics severity mismatch, expected " + expectedWarning.severity + " but received " + report.type) | ||
.to.equal(expectedWarning.severity); | ||
} | ||
}); | ||
@@ -92,2 +102,12 @@ chai_1.expect(warnings.length, 'diagnostics reports match').to.equal(diagnostics.reports.length); | ||
exports.expectWarningsFromTransform = expectWarningsFromTransform; | ||
function shouldReportNoDiagnostics(meta, checkTransformDiagnostics) { | ||
if (checkTransformDiagnostics === void 0) { checkTransformDiagnostics = true; } | ||
var processReports = meta.diagnostics.reports; | ||
chai_1.expect(processReports.length, "processing diagnostics: " + processReports.map(function (r) { return r.message; })).to.equal(0); | ||
if (meta.transformDiagnostics && checkTransformDiagnostics) { | ||
var transformerReports = meta.transformDiagnostics.reports; | ||
chai_1.expect(transformerReports.length, "transforming diagnostics: " + transformerReports.map(function (r) { return r.message; })).to.equal(0); | ||
} | ||
} | ||
exports.shouldReportNoDiagnostics = shouldReportNoDiagnostics; | ||
//# sourceMappingURL=diagnostics.js.map |
{ | ||
"name": "@stylable/core", | ||
"version": "0.1.13", | ||
"version": "0.1.14", | ||
"description": "CSS for Components", | ||
@@ -24,3 +24,3 @@ "main": "./dist/src/index.js", | ||
"murmurhash": "^0.0.2", | ||
"postcss": "^7.0.5", | ||
"postcss": "^7.0.6", | ||
"postcss-js": "^2.0.0", | ||
@@ -52,3 +52,3 @@ "postcss-nested": "^4.1.0", | ||
"license": "BSD-3-Clause", | ||
"gitHead": "e2230521e4531534bfa43621ba26196f338a9971" | ||
"gitHead": "2105bf12df2653163597b11bcef1f72b0d5ea15b" | ||
} |
@@ -49,5 +49,2 @@ import * as postcss from 'postcss'; | ||
doNext = traverseNode(node.nodes[i], visitor, i, node.nodes); | ||
if (doNext === true) { | ||
continue; | ||
} | ||
if (doNext === false) { | ||
@@ -112,2 +109,11 @@ return false; | ||
export function isSimpleSelector(selectorAst: SelectorAstNode) { | ||
const isSimpleSelectorASTNode = createSimpleSelectorChecker(); | ||
const isSimple = traverseNode(selectorAst, node => ( | ||
isSimpleSelectorASTNode(node) !== false /*stop on complex selector */ | ||
)); | ||
return isSimple; | ||
} | ||
export function isImport(ast: SelectorAstNode): boolean { | ||
@@ -258,4 +264,4 @@ const selectors = ast.nodes[0]; | ||
export function isChildOfAtRule(rule: postcss.Rule, atRuleName: string) { | ||
return rule.parent && rule.parent.type === 'atrule' && rule.parent.name === atRuleName; | ||
export function isChildOfAtRule(rule: postcss.Container, atRuleName: string) { | ||
return !!rule.parent && rule.parent.type === 'atrule' && rule.parent.name === atRuleName; | ||
} | ||
@@ -262,0 +268,0 @@ |
@@ -25,2 +25,3 @@ import * as postcss from 'postcss'; | ||
public transformDiagnostics: Diagnostics | null; | ||
public scopes: postcss.AtRule[]; | ||
constructor(public ast: postcss.Root, public diagnostics: Diagnostics) { | ||
@@ -49,2 +50,3 @@ const rootSymbol: ClassSymbol = { | ||
this.urls = []; | ||
this.scopes = []; | ||
this.transformDiagnostics = null; | ||
@@ -51,0 +53,0 @@ } |
@@ -10,2 +10,3 @@ import hash from 'murmurhash'; | ||
isRootValid, | ||
isSimpleSelector, | ||
parseSelector, | ||
@@ -27,3 +28,3 @@ SelectorAstNode, | ||
import { CUSTOM_SELECTOR_RE, expandCustomSelectors, getAlias } from './stylable-utils'; | ||
import { SBTypesParsers, stValuesMap, valueMapping } from './stylable-value-parsers'; | ||
import { rootValueMapping, SBTypesParsers, stValuesMap, valueMapping } from './stylable-value-parsers'; | ||
import { deprecated, filename2varname, stripQuotation } from './utils'; | ||
@@ -40,8 +41,8 @@ export * from './stylable-meta'; /* TEMP EXPORT */ | ||
export const processorWarnings = { | ||
UNSCOPED_CLASS(name: string) { return `unscoped native element "${name}" will affect all elements of the same type in the document`; }, | ||
UNSCOPED_ELEMENT(name: string) { return `unscoped native element "${name}" will affect all elements of the same type in the document`; }, | ||
UNSCOPED_CLASS(name: string) { return `unscoped class "${name}" will affect all elements of the same type in the document`; }, | ||
UNSCOPED_ELEMENT(name: string) { return `unscoped element "${name}" will affect all elements of the same type in the document`; }, | ||
FORBIDDEN_DEF_IN_COMPLEX_SELECTOR(name: string) { return `cannot define "${name}" inside a complex selector`; }, | ||
ROOT_AFTER_SPACING() { return '".root" class cannot be used after native elements or selectors external to the stylesheet'; }, | ||
DEFAULT_IMPORT_IS_LOWER_CASE() { return 'Default import of a Stylable stylesheet must start with an upper-case letter'; }, | ||
ILLEGAL_PROP_IN_IMPORT(propName: string) { return `"${propName}" css attribute cannot be used inside :import block`; }, | ||
ILLEGAL_PROP_IN_IMPORT(propName: string) { return `"${propName}" css attribute cannot be used inside ${rootValueMapping.import} block`; }, | ||
STATE_DEFINITION_IN_ELEMENT() { return 'cannot define pseudo states inside element selectors'; }, | ||
@@ -55,7 +56,12 @@ STATE_DEFINITION_IN_COMPLEX() { return 'cannot define pseudo states inside complex selectors'; }, | ||
OVERRIDE_TYPED_RULE(key: string, name: string) { return `override "${key}" on typed rule "${name}"`; }, | ||
FROM_PROP_MISSING_IN_IMPORT() { return `"${valueMapping.from}" is missing in :import block`; }, | ||
FROM_PROP_MISSING_IN_IMPORT() { return `"${valueMapping.from}" is missing in ${rootValueMapping.import} block`; }, | ||
INVALID_NAMESPACE_DEF() { return 'invalid @namespace'; }, | ||
EMPTY_NAMESPACE_DEF() { return '@namespace must contain at least one character or digit'; }, | ||
EMPTY_IMPORT_FROM() { return '"-st-from" cannot be empty'; }, | ||
MULTIPLE_FROM_IN_IMPORT() { return `cannot define multiple "${valueMapping.from}" declarations in a single import`; } | ||
MULTIPLE_FROM_IN_IMPORT() { return `cannot define multiple "${valueMapping.from}" declarations in a single import`; }, | ||
NO_VARS_DEF_IN_ST_SCOPE() { return `cannot define "${rootValueMapping.vars}" inside of "@st-scope"`; }, | ||
NO_IMPORT_IN_ST_SCOPE() { return `cannot use "${rootValueMapping.import}" inside of "@st-scope"`; }, | ||
NO_KEYFRAMES_IN_ST_SCOPE() { return `cannot use "@keyframes" inside of "@st-scope"`; }, | ||
SCOPE_PARAM_NOT_SIMPLE_SELECTOR(selector: string) { return `"@st-scope" must receive a simple selector, but instead got: "${selector}"`; }, | ||
MISSING_SCOPING_PARAM() { return '"@st-scope" must receive a simple selector or stylesheet "root" as its scoping parameter'; } | ||
}; | ||
@@ -78,3 +84,3 @@ /* tslint:enable:max-line-length */ | ||
this.handleCustomSelectors(rule); | ||
this.handleRule(rule); | ||
this.handleRule(rule, isChildOfAtRule(rule, rootValueMapping.stScope)); | ||
} | ||
@@ -92,2 +98,15 @@ }); | ||
this.meta.scopes.forEach(atRule => { | ||
const scopingRule = postcss.rule({ selector: atRule.params }) as SRule; | ||
this.handleRule(scopingRule, true); | ||
validateScopingSelector(atRule, scopingRule, this.diagnostics); | ||
if (scopingRule.selector) { | ||
atRule.walkRules(rule => { | ||
rule.replaceWith(rule.clone({ selector: `${scopingRule.selector} ${rule.selector}`})); | ||
}); | ||
} | ||
atRule.replaceWith(atRule.nodes || []); | ||
}); | ||
stubs.forEach(s => s && s.remove()); | ||
@@ -133,3 +152,7 @@ | ||
case 'keyframes': | ||
this.meta.keyframes.push(atRule); | ||
if (!isChildOfAtRule(atRule, rootValueMapping.stScope)) { | ||
this.meta.keyframes.push(atRule); | ||
} else { | ||
this.diagnostics.warn(atRule, processorWarnings.NO_KEYFRAMES_IN_ST_SCOPE()); | ||
} | ||
break; | ||
@@ -146,2 +169,5 @@ case 'custom-selector': | ||
break; | ||
case 'st-scope': | ||
this.meta.scopes.push(atRule); | ||
break; | ||
} | ||
@@ -154,3 +180,3 @@ }); | ||
protected handleRule(rule: SRule) { | ||
protected handleRule(rule: SRule, inStScope: boolean = false) { | ||
rule.selectorAst = parseSelector(rule.selector); | ||
@@ -169,3 +195,9 @@ | ||
if (name === 'import') { | ||
if (rule.selector === ':import') { | ||
if (rule.selector === rootValueMapping.import) { | ||
if (isChildOfAtRule(rule, rootValueMapping.stScope)) { | ||
this.diagnostics.warn(rule, processorWarnings.NO_IMPORT_IN_ST_SCOPE()); | ||
rule.remove(); | ||
return false; | ||
} | ||
const _import = this.handleImport(rule); | ||
@@ -176,10 +208,18 @@ this.meta.imports.push(_import); | ||
} else { | ||
this.diagnostics.warn(rule, processorWarnings.FORBIDDEN_DEF_IN_COMPLEX_SELECTOR(':import')); | ||
this.diagnostics.warn( | ||
rule, processorWarnings.FORBIDDEN_DEF_IN_COMPLEX_SELECTOR(rootValueMapping.import)); | ||
} | ||
} else if (name === 'vars') { | ||
if (rule.selector === ':vars') { | ||
if (rule.selector === rootValueMapping.vars) { | ||
if (isChildOfAtRule(rule, rootValueMapping.stScope)) { | ||
this.diagnostics.warn(rule, processorWarnings.NO_VARS_DEF_IN_ST_SCOPE()); | ||
rule.remove(); | ||
return false; | ||
} | ||
this.addVarSymbols(rule); | ||
return false; | ||
} else { | ||
this.diagnostics.warn(rule, processorWarnings.FORBIDDEN_DEF_IN_COMPLEX_SELECTOR(':vars')); | ||
this.diagnostics.warn( | ||
rule, processorWarnings.FORBIDDEN_DEF_IN_COMPLEX_SELECTOR(rootValueMapping.vars)); | ||
} | ||
@@ -200,3 +240,3 @@ } | ||
if (locallyScoped === false) { | ||
if (locallyScoped === false && !inStScope) { | ||
this.diagnostics.warn(rule, processorWarnings.UNSCOPED_ELEMENT(name), { word: name }); | ||
@@ -469,2 +509,14 @@ } | ||
export function validateScopingSelector( | ||
atRule: postcss.AtRule, | ||
{selector: scopingSelector, isSimpleSelector}: SRule, | ||
diagnostics: Diagnostics) { | ||
if (!scopingSelector) { | ||
diagnostics.warn(atRule, processorWarnings.MISSING_SCOPING_PARAM()); | ||
} else if (!isSimpleSelector) { | ||
diagnostics.warn(atRule, | ||
processorWarnings.SCOPE_PARAM_NOT_SIMPLE_SELECTOR(scopingSelector), { word: scopingSelector }); | ||
} | ||
} | ||
export function createEmptyMeta(root: postcss.Root, diagnostics: Diagnostics): StylableMeta { | ||
@@ -471,0 +523,0 @@ deprecated('createEmptyMeta is deprecated and will be removed in the next version. Use "new StylableMeta()"'); |
@@ -106,3 +106,6 @@ import cloneDeep from 'lodash.clonedeep'; | ||
KEYFRAME_NAME_RESERVED(name: string) { return `keyframes "${name}" is reserved`; }, | ||
UNKNOWN_IMPORT_ALIAS(name: string) { return `cannot use alias for unknown import "${name}"`; } | ||
UNKNOWN_IMPORT_ALIAS(name: string) { return `cannot use alias for unknown import "${name}"`; }, | ||
SCOPE_PARAM_NOT_ROOT(name: string) { return `"@st-scope" parameter "${name}" does not resolve to a stylesheet root`; }, | ||
SCOPE_PARAM_NOT_CSS(name: string) { return `"@st-scope" parameter "${name}" must be a Stylable stylesheet, instead name originated from a JavaScript file`; }, | ||
UNKNOWN_SCOPING_PARAM(name: string) { return `"@st-scope" received an unknown symbol: "${name}"`; } | ||
}; | ||
@@ -150,2 +153,4 @@ /* tslint:enable:max-line-length */ | ||
validateScopes(meta, this.resolver, this.diagnostics); | ||
ast.walkRules((rule: SRule) => { | ||
@@ -494,4 +499,3 @@ if (isChildOfAtRule(rule, 'keyframes')) { return; } | ||
} | ||
public scopeRule( | ||
meta: StylableMeta, rule: postcss.Rule, metaExports?: Pojo<string>): string { | ||
public scopeRule(meta: StylableMeta, rule: postcss.Rule, metaExports?: Pojo<string>): string { | ||
return this.scopeSelector(meta, rule.selector, metaExports, false, rule).selector; | ||
@@ -742,1 +746,34 @@ } | ||
} | ||
function validateScopes(meta: StylableMeta, resolver: StylableResolver, diagnostics: Diagnostics) { | ||
for (const scope of meta.scopes) { | ||
const name = scope.params.startsWith('.') ? scope.params.slice(1) : scope.params; | ||
if (!name) { | ||
continue; | ||
} else if (!meta.mappedSymbols[name]) { | ||
diagnostics.error( | ||
scope, transformerWarnings.UNKNOWN_SCOPING_PARAM(scope.params), { word: scope.params }); | ||
continue; | ||
} | ||
const resolvedScope = resolver.deepResolve(meta.mappedSymbols[name]); | ||
if (resolvedScope && resolvedScope._kind === 'css') { | ||
const { meta: scopingMeta, symbol: scopingSymbol } = resolvedScope; | ||
if (scopingSymbol.name !== scopingMeta.root) { | ||
diagnostics.error( | ||
scope, transformerWarnings.SCOPE_PARAM_NOT_ROOT(scope.params), { word: scope.params }); | ||
} | ||
} else if (resolvedScope && resolvedScope._kind === 'js') { | ||
diagnostics.error( | ||
scope, transformerWarnings.SCOPE_PARAM_NOT_CSS(scope.params), { word: scope.params }); | ||
} else if (meta.classes[name] || meta.elements[scope.params] && meta.elements[scope.params].alias) { | ||
// do nothing valid input | ||
} else { | ||
diagnostics.error( | ||
scope, transformerWarnings.UNKNOWN_SCOPING_PARAM(scope.params), { word: scope.params }); | ||
} | ||
} | ||
} |
@@ -43,2 +43,9 @@ import * as postcss from 'postcss'; | ||
export const rootValueMapping = { | ||
vars: ':vars' as ':vars', | ||
import: ':import' as ':import', | ||
stScope: 'st-scope' as 'st-scope', | ||
namespace: 'namespace' as 'namespace' | ||
}; | ||
export const valueMapping = { | ||
@@ -45,0 +52,0 @@ from: '-st-from' as '-st-from', |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1127454
271
15523
Updatedpostcss@^7.0.6