UNPKG

@atlaskit/eslint-plugin-ui-styling-standard

Version:

The eslint plugin to enforce and educate on Atlassian's UI Styling Standard

206 lines (204 loc) • 4.89 kB
/** * 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". */ const allowedGroupedAtRules = new Set(['@starting-style' // Has no parameters, can only be written in grouped form ]); export function walkCssMapCall(call, visitor) { const variantMap = call.arguments[0]; if ((variantMap === null || variantMap === void 0 ? void 0 : variantMap.type) === 'ObjectExpression') { walkCssMapVariantMap({ variantMap, visitor }); } } function walkCssMapVariantMap({ variantMap, visitor }) { variantMap.properties.forEach(property => { if (property.type !== 'Property') { return; } walkCssMapVariant({ variant: property, visitor }); }); } function walkCssMapVariant({ variant, visitor }) { visitor({ type: 'variant', node: variant }); if (variant.value.type !== 'ObjectExpression') { return; } variant.value.properties.forEach(property => { if (property.type !== 'Property') { return; } if (property.value.type !== 'ObjectExpression') { visitor({ type: 'declaration', node: property }); return; } const keyValue = getKeyValue(property.key); if (keyValue && /^@[A-z-]+$/.test(keyValue)) { walkCssMapAtRuleGrouping({ atRuleGrouping: property, visitor }); return; } if (keyValue === 'selectors') { walkCssMapSelectors({ selectors: property, visitor }); } walkStyleRuleset({ ruleset: property, visitor }); }); } function walkCssMapAtRuleGrouping({ atRuleGrouping, visitor }) { const 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 }); } if (atRuleGrouping.value.type !== 'ObjectExpression') { return; } atRuleGrouping.value.properties.forEach(property => { if (property.type !== 'Property') { return; } walkStyleRuleset({ ruleset: property, visitor }); }); } function walkCssMapSelectors({ selectors, visitor }) { visitor({ type: 'selectors', node: selectors }); if (selectors.value.type !== 'ObjectExpression') { return; } selectors.value.properties.forEach(property => { if (property.type !== 'Property') { return; } walkStyleRuleset({ ruleset: property, visitor }); }); } function walkStyleRuleset({ ruleset, visitor }) { visitor({ type: 'ruleset', node: ruleset }); if (ruleset.value.type !== 'ObjectExpression') { return; } ruleset.value.properties.forEach(property => { if (property.type !== 'Property') { return; } if (property.value.type === 'ObjectExpression') { walkStyleRuleset({ ruleset: property, 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; }