@atlaskit/eslint-plugin-ui-styling-standard
Version:
The eslint plugin to enforce and educate on Atlassian's UI Styling Standard
201 lines (199 loc) • 5.22 kB
JavaScript
/**
* This util is intentionally not in `@atlaskit/eslint-utils` at this time.
*
* This is because the API is likely to change and should not be considered stable.
*/
/**
* At-rules that are allowed to be used in "grouped" form within cssMap.
*
* "Grouped" refers to the legacy Compiled syntax where an at-rule key with no parameters
* (matching `/^@[A-z-]+$/`) contains nested variant keys, like:
*
* ```typescript
* // ❌ GROUPED (not allowed for @media):
* cssMap({
* variant: {
* '@media': { // at-rule key with no parameters
* '(min-width: 900px)': {}, // nested variants
* '(min-width: 1200px)': {},
* }
* }
* })
*
* // ✅ FLAT (preferred for @media):
* cssMap({
* variant: {
* '@media (min-width: 900px)': {}, // at-rule with parameters
* '@media (min-width: 1200px)': {},
* }
* })
* ```
*
* However, some at-rules like `@starting-style` have no parameters and can only be
* written in the "grouped" form at the variant level:
*
* ```typescript
* // ✅ ALLOWED (only valid syntax for @starting-style):
* cssMap({
* fade: {
* '@starting-style': { // at-rule with no parameters
* opacity: 0, // styles to apply
* }
* }
* })
* ```
*
* Note: This only applies to at-rules at the variant level. Nested at-rules inside
* other rulesets (e.g., `@starting-style` inside `@media (...)`) are handled by
* `walkStyleRuleset` and are not considered "grouped".
*/
var allowedGroupedAtRules = new Set(['@starting-style' // Has no parameters, can only be written in grouped form
]);
export function walkCssMapCall(call, visitor) {
var variantMap = call.arguments[0];
if ((variantMap === null || variantMap === void 0 ? void 0 : variantMap.type) === 'ObjectExpression') {
walkCssMapVariantMap({
variantMap: variantMap,
visitor: visitor
});
}
}
function walkCssMapVariantMap(_ref) {
var variantMap = _ref.variantMap,
visitor = _ref.visitor;
variantMap.properties.forEach(function (property) {
if (property.type !== 'Property') {
return;
}
walkCssMapVariant({
variant: property,
visitor: visitor
});
});
}
function walkCssMapVariant(_ref2) {
var variant = _ref2.variant,
visitor = _ref2.visitor;
visitor({
type: 'variant',
node: variant
});
if (variant.value.type !== 'ObjectExpression') {
return;
}
variant.value.properties.forEach(function (property) {
if (property.type !== 'Property') {
return;
}
if (property.value.type !== 'ObjectExpression') {
visitor({
type: 'declaration',
node: property
});
return;
}
var keyValue = getKeyValue(property.key);
if (keyValue && /^@[A-z-]+$/.test(keyValue)) {
walkCssMapAtRuleGrouping({
atRuleGrouping: property,
visitor: visitor
});
return;
}
if (keyValue === 'selectors') {
walkCssMapSelectors({
selectors: property,
visitor: visitor
});
}
walkStyleRuleset({
ruleset: property,
visitor: visitor
});
});
}
function walkCssMapAtRuleGrouping(_ref3) {
var atRuleGrouping = _ref3.atRuleGrouping,
visitor = _ref3.visitor;
var atRule = getKeyValue(atRuleGrouping.key);
if (!atRule) {
return;
}
// Skip reporting if the at-rule is allowed to be grouped
if (!allowedGroupedAtRules.has(atRule)) {
visitor({
type: 'grouped-at-rules',
node: atRuleGrouping,
atRule: atRule
});
}
if (atRuleGrouping.value.type !== 'ObjectExpression') {
return;
}
atRuleGrouping.value.properties.forEach(function (property) {
if (property.type !== 'Property') {
return;
}
walkStyleRuleset({
ruleset: property,
visitor: visitor
});
});
}
function walkCssMapSelectors(_ref4) {
var selectors = _ref4.selectors,
visitor = _ref4.visitor;
visitor({
type: 'selectors',
node: selectors
});
if (selectors.value.type !== 'ObjectExpression') {
return;
}
selectors.value.properties.forEach(function (property) {
if (property.type !== 'Property') {
return;
}
walkStyleRuleset({
ruleset: property,
visitor: visitor
});
});
}
function walkStyleRuleset(_ref5) {
var ruleset = _ref5.ruleset,
visitor = _ref5.visitor;
visitor({
type: 'ruleset',
node: ruleset
});
if (ruleset.value.type !== 'ObjectExpression') {
return;
}
ruleset.value.properties.forEach(function (property) {
if (property.type !== 'Property') {
return;
}
if (property.value.type === 'ObjectExpression') {
walkStyleRuleset({
ruleset: property,
visitor: visitor
});
return;
}
visitor({
type: 'declaration',
node: property
});
});
}
function getKeyValue(key) {
if (key.type === 'Identifier') {
return key.name;
}
if (key.type === 'Literal') {
var _key$value$toString, _key$value;
return (_key$value$toString = (_key$value = key.value) === null || _key$value === void 0 ? void 0 : _key$value.toString()) !== null && _key$value$toString !== void 0 ? _key$value$toString : null;
}
return null;
}