_bem_context = { _alias_map: {} _alias_stacks: { } } work_stack(stack, callback) while length(stack) > 0 entry = pop(stack) if entry != () callback(entry) set_alias(alias, name) if name != null && alias != null _bem_context._alias_map[alias] = name lookup_alias(name) if name in _bem_context._alias_map return _bem_context._alias_map[name] else return name store_alias(alias) level_name = called-from[1] if not level_name in _bem_context._alias_stacks _bem_context._alias_stacks[level_name] = () () if alias != null push(_bem_context._alias_stacks[level_name], alias) pop_last_alias() level_name = called-from[1] if not level_name in _bem_context._alias_stacks return null return pop(_bem_context._alias_stacks[level_name]) apply_alias_stack(name) level_name = called-from[1] if level_name in _bem_context._alias_stacks work_stack(_bem_context._alias_stacks[level_name], @(element){ set_alias(element, name) }) auto_name(delimiter) if length(called-from) < 3 return null block_name = called-from[2] if delimiter == null return block_name name = split(delimiter, block_name)[-1] if name in ('RV-Element' 'RV-Block' 'RV-Block--shorthand' 'RV-Element--modifier' 'RV-Block--modifier' 'RV-Generate') return null return name is_nested(mixin_name=null) _free_hits = 0 if mixin_name == null shift(called-from) mixin_name = shift(called-from) else _free_hits = 1 for parent in called-from if parent == mixin_name if _free_hits == 0 return true else _free_hits = _free_hits - 1 return false is_nested_in(parent_name) return parent_name in called-from not_nested_in(parent_name) return !(parent_name in called-from) is_any_parent_nested() //RV-Level RV-Element--modifier RV-Element RV-Block--modifier RV-BreakPoint--horizontal RV-Block--modifier RV-Fan--horizontal RV-Block for i in (length(called-from)...0) i = i - 1 if i != index(called-from, called-from[i]) return true return false RV-Level(name_delimiter, allowed_parent_levels=null, selector_callback, squash_if_parent_nested=false) name = auto_name(name_delimiter) not_in_parent = true for parent_level in allowed_parent_levels not_in_parent = not_in_parent && not_nested_in(parent_level) if not_in_parent //|| is_nested_in('RV-Squash') {block} else if is_nested() store_alias(name) {block} else if name == null name = pop_last_alias() name = lookup_alias(name) apply_alias_stack(name) if squash_if_parent_nested && is_any_parent_nested() {block} else selector_name = selector_callback(name) if name == '' selector_name = split(name_delimiter, selector_name)[0] {selector_name} {block} // RV-Fan--horizontal RV-Fan--horizontal __ Base -- wurst // RV-BreakPoint__Item--outside RV-Fan--horizontal__Base RV-Fan--horizontal RV-Block(name) .{name} {block} _bem_context._alias_map = {} _bem_context._alias_stacks = {} RV-Generate() {block} _bem_context._alias_map = {} _bem_context._alias_stacks = {} RV-Block() +RV-Level(null, ('RV-Generate'), @(name){ define('current_block', name, true) return '.'+name }) {block} RV-Block--shorthand(name) +RV-Block(name) {block} RV-Element() +RV-Level('__', ('RV-Generate' 'RV-Block--modifier'), @(name){ return '& .' + current_block +'__' + name }) {block} RV-Element--modifier() +RV-Level('--', ('RV-Element'), @(name){return '&--' + name}, true) {block} RV-Block--modifier() +RV-Level('--', ('RV-Generate' 'RV-Block--shorthand'), @(name){ '.' + current_block +'--' + name }, true) if is_nested_in('RV-Block--shorthand') && length(called-from) > 0 mixin_name = split('--', called-from[0])[0] convert(unquote(mixin_name)+'()') {block} RV-Squash() {block} filter(list, value) filtered = () for element in list if element != value push(filtered, element) return filtered _level_types = { '': 'block' '__': 'element' '--': 'modifier' } get_first_level_name(mixin_name) shortest_split = null for delimiter, level_type in _level_types if length(delimiter) > 0 current_split = split(delimiter, mixin_name)[0] if shortest_split == null || length(current_split) <= length(shortest_split) shortest_split = current_split return shortest_split string_contains(smaller, greater) if smaller == null || greater == null return false if length(smaller) > length(greater) return false p('%s'%smaller length('%s'%smaller)) for i in range(0, length(smaller)) if smaller[i] != greater[i] return false return true is_contigious(call_stack) for i in range(0, length(call_stack) - 1) p(call_stack[i+1] call_stack[i]) p(string_contains(call_stack[i+1], call_stack[i])) if !call_stack[i+1] in call_stack[i] return false return true determine_level_type(mixin_name) candidate = null candidate_level = null candidate_delimiter = null // This is why humanity is doomed mixin_name = split('äöü', mixin_name)[0] for delimiter, level in _level_types if length(delimiter) <= 0 splited_level = mixin_name else splited_level = split(delimiter, mixin_name)[-1] if candidate == null || length(candidate) > length(splited_level) candidate = splited_level candidate_level = level candidate_delimiter = delimiter return unquote(candidate) candidate_level unquote(candidate_delimiter) generate_selector(mixin_name) block_name = get_first_level_name(mixin_name) level_info = determine_level_type(mixin_name) return '&%s%s' % (level_info[2] level_info[0]) RV-BEM() call_stack = filter(called-from, 'RV-BEM') p(cs call_stack) if is_contigious(call_stack) {generate_selector(called-from[0])} {block} p('###')