def parse(self, scope): """Parse node args: scope (Scope): current scope raises: SyntaxError returns: self """ self.name, args, self.guards = self.tokens[0] self.args = [a for a in utility.flatten(args) if a] self.body = Block([None, self.tokens[1]], 0) self.vars = list(utility.flatten([list(v.values()) for v in [s["__variables__"] for s in scope]])) return self
def process(self, tokens, scope): """ Process tokenslist, flattening and parsing it args: tokens (list): tokenlist scope (Scope): Current scope returns: list """ while True: tokens = list(utility.flatten(tokens)) done = True if any(t for t in tokens if hasattr(t, 'parse')): tokens = [ t.parse(scope) if hasattr(t, 'parse') else t for t in tokens ] done = False if any( t for t in tokens if (utility.is_variable(t)) or str(type(t)) == "<class 'lesscpy.plib.variable.Variable'>"): tokens = self.replace_variables(tokens, scope) done = False if done: break return tokens
def parse(self, scope): """Parse node args: scope (Scope): current scope raises: SyntaxError returns: self """ self.name, args, self.guards = self.tokens[0] self.args = [a for a in utility.flatten(args) if a] self.body = Block([None, self.tokens[1]], 0) self.vars = list( utility.flatten([ list(v.values()) for v in [s['__variables__'] for s in scope] ])) return self
def parse(self, scope): """Parse node. Block identifiers are stored as strings with spaces replaced with ? args: scope (Scope): Current scope raises: SyntaxError returns: self """ names = [] name = [] self._subp = ( '@media', '@keyframes', '@-moz-keyframes', '@-webkit-keyframes', '@-ms-keyframes' ) if self.tokens and hasattr(self.tokens, 'parse'): self.tokens = list(utility.flatten([id.split() + [','] for id in self.tokens.parse(scope).split(',')])) self.tokens.pop() if self.tokens and self.tokens[0] in self._subp: name = list(utility.flatten(self.tokens)) self.subparse = True else: self.subparse = False for n in utility.flatten(self.tokens): if n == '*': name.append('* ') elif n in '>+~': if name and name[-1] == ' ': name.pop() name.append('?%s?' % n) elif n == ',': names.append(name) name = [] else: name.append(n) names.append(name) parsed = self.root(scope, names) if scope else names self.parsed = [[i for i, j in utility.pairwise(part) if i != ' ' or (j and '?' not in j)] for part in parsed] return self
def swap(self, var): """ Replace variable args: var (str): variable raises: SyntaxError returns: str """ var = self.scope.swap('@' + var) var = ''.join(utility.flatten(var)) return var.strip("\"'")
def parse(self, scope): """Parse node args: scope (Scope): current scope raises: SyntaxError returns: self """ self.name, args, self.guards = self.tokens[0] self.args = [a for a in utility.flatten(args) if a] self.body = Block([None, self.tokens[1]], 0) self.scope = copy.deepcopy(scope[-1]) return self
def parse(self, scope): """Parse node. Block identifiers are stored as strings with spaces replaced with ? args: scope (Scope): Current scope raises: SyntaxError returns: self """ names = [] name = [] self._subp = ("@media", "@keyframes", "@-moz-keyframes", "@-webkit-keyframes", "@-ms-keyframes") if self.tokens and hasattr(self.tokens, "parse"): self.tokens = list(utility.flatten([id.split() + [","] for id in self.tokens.parse(scope).split(",")])) self.tokens.pop() if self.tokens and self.tokens[0] in self._subp: name = list(utility.flatten(self.tokens)) self.subparse = True else: self.subparse = False for n in utility.flatten(self.tokens): if n == "*": name.append("* ") elif n in ">+~": if name and name[-1] == " ": name.pop() name.append("?%s?" % n) elif n == ",": names.append(name) name = [] else: name.append(n) names.append(name) parsed = self.root(scope, names) if scope else names self.parsed = [[i for i, j in utility.pairwise(part) if i != " " or (j and "?" not in j)] for part in parsed] return self
def parse(self, scope): """Parse node args: scope (Scope): current scope raises: SyntaxError returns: self """ self.parsed = list(utility.flatten(self.tokens)) if self.parsed[0] == '@import': if len(self.parsed) > 4: # Media @import self.parsed.insert(3, ' ') return self
def parse(self, scope): """Parse block node. args: scope (Scope): Current scope raises: SyntaxError returns: self """ if not self.parsed: scope.push() self.name, inner = self.tokens scope.current = self.name if not self.name.parsed: self.name.parse(scope) if not inner: inner = [] inner = list(utility.flatten([p.parse(scope) for p in inner if p])) self.parsed = [p for p in inner if p and type(p) is not Block] self.inner = [p for p in inner if p and type(p) is Block] scope.pop() return self
def parse(self, scope): """Parse block node. args: scope (Scope): Current scope raises: SyntaxError returns: self """ if not self.parsed: scope.push() self.name, inner = self.tokens scope.current = self.name scope.real.append(self.name) if not self.name.parsed: self.name.parse(scope) if not inner: inner = [] inner = list(utility.flatten([p.parse(scope) for p in inner if p])) self.parsed = [p for p in inner if p and not isinstance(p, Block)] self.inner = [p for p in inner if p and isinstance(p, Block)] scope.real.pop() scope.pop() return self
def process(self, tokens, scope): """ Process tokenslist, flattening and parsing it args: tokens (list): tokenlist scope (Scope): Current scope returns: list """ while True: tokens = list(utility.flatten(tokens)) done = True if any(t for t in tokens if hasattr(t, 'parse')): tokens = [ t.parse(scope) if hasattr(t, 'parse') else t for t in tokens ] done = False if any(t for t in tokens if (utility.is_variable(t)) or str(type( t)) == "<class 'lesscpy.plib.variable.Variable'>"): tokens = self.replace_variables(tokens, scope) done = False if done: break return tokens
def parse(self, scope): """Parse node. Block identifiers are stored as strings with spaces replaced with ? args: scope (Scope): Current scope raises: SyntaxError returns: self """ names = [] name = [] self._subp = ( '@media', '@keyframes', '@-moz-keyframes', '@-webkit-keyframes', '@-ms-keyframes' ) if self.tokens and hasattr(self.tokens, 'parse'): self.tokens = list(utility.flatten([id.split() + [','] for id in self.tokens.parse(scope).split(',')])) self.tokens.pop() if self.tokens and any(hasattr(t, 'parse') for t in self.tokens): tmp_tokens = [] for t in self.tokens: if hasattr(t, 'parse'): tmp_tokens.append(t.parse(scope)) else: tmp_tokens.append(t) self.tokens = list(utility.flatten(tmp_tokens)) if self.tokens and self.tokens[0] in self._subp: name = list(utility.flatten(self.tokens)) self.subparse = True else: self.subparse = False for n in utility.flatten(self.tokens): if n == '*': name.append('* ') elif n in '>+~': if name and name[-1] == ' ': name.pop() name.append('?%s?' % n) elif n == ',': names.append(name) name = [] else: name.append(n) names.append(name) parsed = self.root(scope, names) if scope else names # Interpolated selectors need another step, we have to replace variables. Avoid reserved words though # # Example: '.@{var}' results in [['.', '@{var}']] # But: '@media print' results in [['@media', ' ', 'print']] # def replace_variables(tokens, scope): return [scope.swap(t) if (utility.is_variable(t) and not t in reserved.tokens) else t for t in tokens] parsed = [list(utility.flatten(replace_variables(part, scope))) for part in parsed] self.parsed = [[i for i, j in utility.pairwise(part) if i != ' ' or (j and '?' not in j)] for part in parsed] return self
def parse(self, scope): """Parse block node. args: scope (Scope): Current scope raises: SyntaxError returns: self """ if not self.parsed: scope.push() self.name, inner = self.tokens scope.current = self.name scope.real.append(self.name) if not self.name.parsed: self.name.parse(scope) if not inner: inner = [] inner = list(utility.flatten([p.parse(scope) for p in inner if p])) self.parsed = [] self.inner = [] if not hasattr(self, "inner_media_queries"): self.inner_media_queries = [] for p in inner: if p is not None: if isinstance(p, Block): if len(scope) == 2 and p.tokens[1] is not None: p_is_mediaquery = p.name.tokens[0] == '@media' # Inner block @media ... { ... } is a nested media # query. But double-nested media queries have to be # removed and marked as well. While parsing ".foo", # both nested "@media print" and double-nested # "@media all" will be handled as we have to # re-arrange the scope and block layout quite a bit: # # .foo { # @media print { # color: blue; # @media screen { font-size: 12em; } # } # } # # Expected result: # # @media print { # .foo { color: blue; } # } # @media print and screen { # .foo { font-size: 12 em; } # } append_list = [] reparse_p = False for child in p.tokens[1]: if isinstance(child, Block) and child.name.raw( ).startswith("@media"): # Remove child from the nested media query, it will be re-added to # the parent with 'merged' media query (see above example). p.tokens[1].remove(child) if p_is_mediaquery: # Media query inside a & block # Double-nested media query found. We remove it from 'p' and add # it to this block with a new 'name'. reparse_p = True part_a = p.name.tokens[2:][0][0][0] part_b = child.name.tokens[2:][0][0] new_ident_tokens = [ '@media', ' ', [ part_a, (' ', 'and', ' '), part_b ] ] # Parse child again with new @media $BLA {} part child.tokens[0] = Identifier( new_ident_tokens) child.parsed = None child = child.parse(scope) else: child.block_name = p.name append_list.append(child) if reparse_p: p.parsed = None p = p.parse(scope) if not p_is_mediaquery and not append_list: self.inner.append(p) else: append_list.insert( 0, p ) # This media query should occur before it's children for media_query in append_list: self.inner_media_queries.append( media_query) # NOTE(saschpe): The code is not recursive but we hope that people # wont use triple-nested media queries. else: self.inner.append(p) else: self.parsed.append(p) if self.inner_media_queries: # Nested media queries, we have to remove self from scope and # push all nested @media ... {} blocks. scope.remove_block(self, index=-2) for mb in self.inner_media_queries: # New inner block with current name and media block contents if hasattr(mb, 'block_name'): cb_name = mb.block_name else: cb_name = self.tokens[0] cb = Block([cb_name, mb.tokens[1]]).parse(scope) # Replace inner block contents with new block new_mb = Block([mb.tokens[0], [cb]]).parse(scope) self.inner.append(new_mb) scope.add_block(new_mb) scope.real.pop() scope.pop() return self
def expression(self): """Return str representation of expression returns: str """ return utility.flatten(self.tokens)
def parse(self, scope): """Parse node. Block identifiers are stored as strings with spaces replaced with ? args: scope (Scope): Current scope raises: SyntaxError returns: self """ names = [] name = [] self._subp = ('@media', '@keyframes', '@-moz-keyframes', '@-webkit-keyframes', '@-ms-keyframes') if self.tokens and hasattr(self.tokens, 'parse'): self.tokens = list( utility.flatten([ id.split() + [','] for id in self.tokens.parse(scope).split(',') ])) self.tokens.pop() if self.tokens and any(hasattr(t, 'parse') for t in self.tokens): tmp_tokens = [] for t in self.tokens: if hasattr(t, 'parse'): tmp_tokens.append(t.parse(scope)) else: tmp_tokens.append(t) self.tokens = list(utility.flatten(tmp_tokens)) if self.tokens and self.tokens[0] in self._subp: name = list(utility.flatten(self.tokens)) self.subparse = True else: self.subparse = False for n in utility.flatten(self.tokens): if n == '*': name.append('* ') elif n in '>+~': if name and name[-1] == ' ': name.pop() name.append('?%s?' % n) elif n == ',': names.append(name) name = [] else: name.append(n) names.append(name) parsed = self.root(scope, names) if scope else names # Interpolated selectors need another step, we have to replace variables. Avoid reserved words though # # Example: '.@{var}' results in [['.', '@{var}']] # But: '@media print' results in [['@media', ' ', 'print']] # def replace_variables(tokens, scope): return [ scope.swap(t) if (utility.is_variable(t) and not t in reserved.tokens) else t for t in tokens ] parsed = [ list(utility.flatten(replace_variables(part, scope))) for part in parsed ] self.parsed = [[ i for i, j in utility.pairwise(part) if i != ' ' or (j and '?' not in j) ] for part in parsed] return self
def parse(self, scope): """Parse block node. args: scope (Scope): Current scope raises: SyntaxError returns: self """ if not self.parsed: scope.push() self.name, inner = self.tokens scope.current = self.name scope.real.append(self.name) if not self.name.parsed: self.name.parse(scope) if not inner: inner = [] inner = list(utility.flatten([p.parse(scope) for p in inner if p])) self.parsed = [] self.inner = [] if not hasattr(self, "inner_media_queries"): self.inner_media_queries = [] for p in inner: if p is not None: if isinstance(p, Block): if (len(scope) == 2 and p.tokens[1] is not None): p_is_mediaquery = p.name.tokens[0] == '@media' # Inner block @media ... { ... } is a nested media # query. But double-nested media queries have to be # removed and marked as well. While parsing ".foo", # both nested "@media print" and double-nested # "@media all" will be handled as we have to # re-arrange the scope and block layout quite a bit: # # .foo { # @media print { # color: blue; # @media screen { font-size: 12em; } # } # } # # Expected result: # # @media print { # .foo { color: blue; } # } # @media print and screen { # .foo { font-size: 12 em; } # } append_list = [] reparse_p = False for child in p.tokens[1]: if isinstance(child, Block) and child.name.raw().startswith("@media"): # Remove child from the nested media query, it will be re-added to # the parent with 'merged' media query (see above example). p.tokens[1].remove(child) if p_is_mediaquery: # Media query inside a & block # Double-nested media query found. We remove it from 'p' and add # it to this block with a new 'name'. reparse_p = True part_a = p.name.tokens[2:][0][0][0] part_b = child.name.tokens[2:][0][0] new_ident_tokens = ['@media', ' ', [part_a, (' ', 'and', ' '), part_b]] # Parse child again with new @media $BLA {} part child.tokens[0] = Identifier(new_ident_tokens) child.parsed = None child = child.parse(scope) else: child.block_name = p.name append_list.append(child) if reparse_p: p.parsed = None p = p.parse(scope) if not p_is_mediaquery and not append_list: self.inner.append(p) else: append_list.insert(0, p) # This media query should occur before it's children for media_query in append_list: self.inner_media_queries.append(media_query) # NOTE(saschpe): The code is not recursive but we hope that people # wont use triple-nested media queries. else: self.inner.append(p) else: self.parsed.append(p) if self.inner_media_queries: # Nested media queries, we have to remove self from scope and # push all nested @media ... {} blocks. scope.remove_block(self, index=-2) for mb in self.inner_media_queries: # New inner block with current name and media block contents if hasattr(mb, 'block_name'): cb_name = mb.block_name else: cb_name = self.tokens[0] cb = Block([cb_name, mb.tokens[1]]).parse(scope) # Replace inner block contents with new block new_mb = Block([mb.tokens[0], [cb]]).parse(scope) self.inner.append(new_mb) scope.add_block(new_mb) scope.real.pop() scope.pop() return self