_bem_context = { _alias_map: {} _alias_stacks: { }, known_names: {} } bem_debug = false 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=null) if level_name == null 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, caller) if delimiter == null return caller return split(delimiter, caller)[-1] 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_list=null) if parent_list == null return false for parent in parent_list if parent in called-from return true return false 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 string_contains(smaller, greater) if smaller == null || greater == null return true if length(smaller) > length(greater) return false for i in range(0, length(smaller) - 1) //p(i substr(smaller, i, 1) substr(greater, i, 1)) if substr(smaller, i, 1) != substr(greater, i, 1) return false return true contigious_index(call_stack) for i in range(0, length(call_stack) - 1) if !string_contains(call_stack[i+1], call_stack[i]) return i return -1 filter(list, value_list) filtered = () for element in list if not (element in value_list) push(filtered, element) return filtered RV-Level(name_delimiter, selector_callback, name=null) call_stack = split(' ', ''+called-from) call_stack = filter(call_stack, ('RV-Level' 'RV-Block' 'RV-Block--modifier' 'RV-Element' 'RV-Element--modifier' 'RV-Modifier')) mixin_name = call_stack[0] if name == null name = auto_name(name_delimiter, mixin_name) cindex = contigious_index(call_stack) if bem_debug --attempt mixin_name --cindex cindex --nested_in_super_parents nested_in_super_parents // TODO Clear up this logic if cindex != 0 if name == null name = pop_last_alias() name = lookup_alias(name) apply_alias_stack(name) selector_name = selector_callback(name) if name == '' selector_name = split(name_delimiter, selector_name)[0] if cindex > 0 && !(name in _bem_context.known_names) return else _bem_context.known_names[name] = name define('current_selector', selector_name, true) {selector_name} {block} if bem_debug --mixin_name mixin_name --name name else store_alias(name) {block} if bem_debug --mixin_name mixin_name --name name RV-Block(name=null) +RV-Level(null, @(name){ return '.'+name }, name) {block} _bem_context._alias_map = {} _bem_context._alias_stacks = {} _bem_context.known_names = {} RV-Block--shorthand(name) +RV-Block(name) {block} RV-Element(name=null) +RV-Level('__', @(name){ return '& ^[0]__'+name }, name) {block} RV-Element--modifier(name=null) +RV-Level('--', @(name){ return '&--'+name }, name, ('RV-Block--modifier')) {block} RV-Block--modifier(name=null) +RV-Level('--', @(name){ return '&--'+name }, name) {block} RV-Squash() {block} _level_types = { '': { name: 'block', selector: @(mixin_name, level_name){return '.'+level_name} }, '__': { name: 'element', selector: @(mixin_name, level_name){return '&__'+level_name} }, '--': { name: 'modifier', selector: @(mixin_name, level_name){return '&--'+level_name} }, } 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 generate_selector(mixin_name) candidate = null candidate_level = 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 fn = candidate_level.selector return fn(mixin_name, candidate) //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 = split(' ', ''+called-from) if is_contigious(call_stack) {generate_selector(call_stack[0])} {block} else {block}