From d07f664450ddaaebb44127a4bd057763d13d3f82 Mon Sep 17 00:00:00 2001 From: Feuerfuchs Date: Sun, 1 Nov 2020 20:55:14 +0100 Subject: Init --- src/bem/_validators.scss | 176 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 src/bem/_validators.scss (limited to 'src/bem/_validators.scss') diff --git a/src/bem/_validators.scss b/src/bem/_validators.scss new file mode 100644 index 0000000..eb09a60 --- /dev/null +++ b/src/bem/_validators.scss @@ -0,0 +1,176 @@ +//// +/// Validators are custom functions that will be called before a BEM entity is created. +/// They check if the current mixin usage is valid or not and thus they are a flexible way to +/// let you implement your own rules. +/// +/// Validator functions receive the following information: +/// - BEM entity type +/// - Arguments passed to the mixin +/// - The generated selector +/// - The generated context, if any +/// +/// Additionally, the context stack used by the BEM system can be examined. +/// +/// @group BEM +/// +/// @access public +//// + +/// +/// A list of validator functions. +/// +/// @type list +/// +/// @access private +/// +$iro-bem-validators: (); + +/// +/// Register one or multiple validator functions. +/// +/// A validator function is a function that accepts 4 arguments: +/// 1. BEM entity type (string) +/// 2. Arguments passed to the mixin (map) +/// 3. The generated selector (selector) +/// 4. The generated context (list, may be null) +/// +/// The function must return a list with two items: +/// 1. `true` if the mixin usage is valid, otherwise `false`, +/// 2. a string with a rejection reason (empty if the usage is valid). +/// +/// @param {string} $func-name - First function name. +/// @param {string} $func-names - Other function names. +/// +@mixin iro-bem-add-validator($func-name, $func-names...) { + $noop: iro-bem-add-validator($func-name, $func-names...); +} + +/// +/// Register one or multiple validator functions. Check the respective mixin documentation for more information. +/// +/// @see {mixin} iro-bem-add-validator +/// +@function iro-bem-add-validator($func-name, $func-names...) { + @each $fn-name in join($func-name, $func-names) { + $fn: get-function($fn-name); + $iro-bem-validators: map-merge($iro-bem-validators, ($fn-name: $fn)) !global; + } + @return null; +} + +/// +/// Unregister one or multiple validator functions. +/// +/// @param {string} $func-name - First function name. +/// @param {string} $func-names - Other function names. +/// +@mixin iro-bem-remove-validator($func-name, $func-names...) { + $noop: iro-bem-remove-validator($func-name, $func-names...); +} + +/// +/// Unregister one or multiple validator functions. Check the respective mixin documentation for more information. +/// +/// @see {mixin} iro-bem-remove-validator +/// +@function iro-bem-remove-validator($func-name, $func-names...) { + $iro-bem-validators: map-remove($iro-bem-validators, $func-name, $func-names...) !global; + @return null; +} + +/// +/// @access private +/// +@mixin iro-bem-validate($type, $args, $selector, $context) { + @each $id, $fn in $iro-bem-validators { + $result: call($fn, $type, $args, $selector, $context); + @if not nth($result, 1) { + @error 'A BEM validator rejected this mixin usage due to the following reason: #{nth($result, 2)}'; + } + } +} + +// +// --------------------------------------------------------------------------------------------------------- +// Built-in validators +// --------------------------------------------------------------------------------------------------------- +// + +/// +/// A validator that makes sure blocks are declared in the right order, determined by the +/// namespace used. +/// +@function iro-bem-validator--enforce-namespace-order($type, $args, $selector, $context) { + @if not global-variable-exists(iro-bem-namespace-order) { + $iro-bem-namespace-order: map-keys($iro-bem-namespaces) !global; + } + @if not global-variable-exists(iro-bem-cur-namespace-index) { + $iro-bem-cur-namespace-index: 1 !global; + } + + @if $type == 'block' { + $block-type: map-get($args, 'type'); + + @if $block-type != null { + $ns-index: index($iro-bem-namespace-order, $block-type); + + @if $ns-index != null { + @if $ns-index < $iro-bem-cur-namespace-index { + @return false 'Namespace "#{$block-type}" comes before current namespace #{nth($iro-bem-namespace-order, $iro-bem-cur-namespace-index)}'; + } + + $iro-bem-cur-namespace-index: $ns-index !global; + } + } + } + + @return true ''; +} + +/// +/// A validator that makes all BEM entities immutable. +/// +@function iro-bem-validator--immutable-entities($type, $args, $selector, $context) { + @if not global-variable-exists(iro-bem-generated-selectors) { + $iro-bem-generated-selectors: () !global; + } + + $block-name: null; + $block-type: null; + $block-id: null; + + @if $type == 'block' { + $block-name: map-get($args, 'name'); + $block-type: map-get($args, 'type'); + } @else { + $block-context: iro-context-get($iro-bem-context-id, 'block'); + $block-name: map-get(nth($block-context, 2), 'name'); + $block-type: map-get(nth($block-context, 2), 'type'); + } + + @if $block-type != null { + $block-id: $block-name + '_' + $block-type; + } @else { + $block-id: $block-name; + } + + @if $type == 'block' { + @if map-has-key($iro-bem-generated-selectors, $block-id) { + @return false 'Entity "#{$type}" with arguments [ #{iro-map-print($args)} ] was already defined.'; + } + + $iro-bem-generated-selectors: map-merge($iro-bem-generated-selectors, ($block-id: ())) !global; + } @else { + $selectors: map-get($iro-bem-generated-selectors, $block-id); + + @if index($selectors, $selector) { + @return false 'Entity "#{$type}" with arguments [ #{iro-map-print($args)} ] was already defined.'; + } + + $selectors: append($selectors, $selector); + + $iro-bem-generated-selectors: map-merge($iro-bem-generated-selectors, ($block-id: $selectors)) !global; + } + + @return true ''; +} -- cgit v1.2.3-54-g00ecf