aboutsummaryrefslogtreecommitdiffstats
path: root/src/bem/_validators.scss
diff options
context:
space:
mode:
Diffstat (limited to 'src/bem/_validators.scss')
-rw-r--r--src/bem/_validators.scss176
1 files changed, 176 insertions, 0 deletions
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 @@
1////
2/// Validators are custom functions that will be called before a BEM entity is created.
3/// They check if the current mixin usage is valid or not and thus they are a flexible way to
4/// let you implement your own rules.
5///
6/// Validator functions receive the following information:
7/// - BEM entity type
8/// - Arguments passed to the mixin
9/// - The generated selector
10/// - The generated context, if any
11///
12/// Additionally, the context stack used by the BEM system can be examined.
13///
14/// @group BEM
15///
16/// @access public
17////
18
19///
20/// A list of validator functions.
21///
22/// @type list
23///
24/// @access private
25///
26$iro-bem-validators: ();
27
28///
29/// Register one or multiple validator functions.
30///
31/// A validator function is a function that accepts 4 arguments:
32/// 1. BEM entity type (string)
33/// 2. Arguments passed to the mixin (map)
34/// 3. The generated selector (selector)
35/// 4. The generated context (list, may be null)
36///
37/// The function must return a list with two items:
38/// 1. `true` if the mixin usage is valid, otherwise `false`,
39/// 2. a string with a rejection reason (empty if the usage is valid).
40///
41/// @param {string} $func-name - First function name.
42/// @param {string} $func-names - Other function names.
43///
44@mixin iro-bem-add-validator($func-name, $func-names...) {
45 $noop: iro-bem-add-validator($func-name, $func-names...);
46}
47
48///
49/// Register one or multiple validator functions. Check the respective mixin documentation for more information.
50///
51/// @see {mixin} iro-bem-add-validator
52///
53@function iro-bem-add-validator($func-name, $func-names...) {
54 @each $fn-name in join($func-name, $func-names) {
55 $fn: get-function($fn-name);
56 $iro-bem-validators: map-merge($iro-bem-validators, ($fn-name: $fn)) !global;
57 }
58 @return null;
59}
60
61///
62/// Unregister one or multiple validator functions.
63///
64/// @param {string} $func-name - First function name.
65/// @param {string} $func-names - Other function names.
66///
67@mixin iro-bem-remove-validator($func-name, $func-names...) {
68 $noop: iro-bem-remove-validator($func-name, $func-names...);
69}
70
71///
72/// Unregister one or multiple validator functions. Check the respective mixin documentation for more information.
73///
74/// @see {mixin} iro-bem-remove-validator
75///
76@function iro-bem-remove-validator($func-name, $func-names...) {
77 $iro-bem-validators: map-remove($iro-bem-validators, $func-name, $func-names...) !global;
78 @return null;
79}
80
81///
82/// @access private
83///
84@mixin iro-bem-validate($type, $args, $selector, $context) {
85 @each $id, $fn in $iro-bem-validators {
86 $result: call($fn, $type, $args, $selector, $context);
87 @if not nth($result, 1) {
88 @error 'A BEM validator rejected this mixin usage due to the following reason: #{nth($result, 2)}';
89 }
90 }
91}
92
93//
94// ---------------------------------------------------------------------------------------------------------
95// Built-in validators
96// ---------------------------------------------------------------------------------------------------------
97//
98
99///
100/// A validator that makes sure blocks are declared in the right order, determined by the
101/// namespace used.
102///
103@function iro-bem-validator--enforce-namespace-order($type, $args, $selector, $context) {
104 @if not global-variable-exists(iro-bem-namespace-order) {
105 $iro-bem-namespace-order: map-keys($iro-bem-namespaces) !global;
106 }
107 @if not global-variable-exists(iro-bem-cur-namespace-index) {
108 $iro-bem-cur-namespace-index: 1 !global;
109 }
110
111 @if $type == 'block' {
112 $block-type: map-get($args, 'type');
113
114 @if $block-type != null {
115 $ns-index: index($iro-bem-namespace-order, $block-type);
116
117 @if $ns-index != null {
118 @if $ns-index < $iro-bem-cur-namespace-index {
119 @return false 'Namespace "#{$block-type}" comes before current namespace #{nth($iro-bem-namespace-order, $iro-bem-cur-namespace-index)}';
120 }
121
122 $iro-bem-cur-namespace-index: $ns-index !global;
123 }
124 }
125 }
126
127 @return true '';
128}
129
130///
131/// A validator that makes all BEM entities immutable.
132///
133@function iro-bem-validator--immutable-entities($type, $args, $selector, $context) {
134 @if not global-variable-exists(iro-bem-generated-selectors) {
135 $iro-bem-generated-selectors: () !global;
136 }
137
138 $block-name: null;
139 $block-type: null;
140 $block-id: null;
141
142 @if $type == 'block' {
143 $block-name: map-get($args, 'name');
144 $block-type: map-get($args, 'type');
145 } @else {
146 $block-context: iro-context-get($iro-bem-context-id, 'block');
147 $block-name: map-get(nth($block-context, 2), 'name');
148 $block-type: map-get(nth($block-context, 2), 'type');
149 }
150
151 @if $block-type != null {
152 $block-id: $block-name + '_' + $block-type;
153 } @else {
154 $block-id: $block-name;
155 }
156
157 @if $type == 'block' {
158 @if map-has-key($iro-bem-generated-selectors, $block-id) {
159 @return false 'Entity "#{$type}" with arguments [ #{iro-map-print($args)} ] was already defined.';
160 }
161
162 $iro-bem-generated-selectors: map-merge($iro-bem-generated-selectors, ($block-id: ())) !global;
163 } @else {
164 $selectors: map-get($iro-bem-generated-selectors, $block-id);
165
166 @if index($selectors, $selector) {
167 @return false 'Entity "#{$type}" with arguments [ #{iro-map-print($args)} ] was already defined.';
168 }
169
170 $selectors: append($selectors, $selector);
171
172 $iro-bem-generated-selectors: map-merge($iro-bem-generated-selectors, ($block-id: $selectors)) !global;
173 }
174
175 @return true '';
176}