def test_groups(self): fl = {'ws': ' ', 'nl': '\n'} sc = Scope() sc.push() sc.current = Identifier(['.a', ',', '.b'], 0).parse(sc) for i in [ (['&', '.scope', ' ', 'a'], '.a.scope a,\n.b.scope a'), (['.scope', '&', ' ', 'a'], '.scope.a a,\n.scope.b a'), (['.scope', ' ', 'a', '&'], '.scope a.a,\n.scope a.b'), (['>', '&', '.scope', ' ', 'a'], ' > .a.scope a,\n > .b.scope a'), ]: t, r = i id = Identifier(t, 0) self.assertEqual(id.parse(sc).fmt(fl), r, i) sc.current = Identifier(['.next'], 0).parse(sc) sc.push() sc.current = Identifier(['.c', ',', '.d'], 0).parse(sc) id = Identifier(['.deep'], 0) self.assertEqual( id.parse(sc).fmt(fl), '.a .next .c .deep,\n' '.b .next .c .deep,\n' '.a .next .d .deep,\n' '.b .next .d .deep') self.assertEqual( id.raw(), '.a% %.next% %.c% %.deep%' '.b% %.next% %.c% %.deep%' '.a% %.next% %.d% %.deep%' '.b% %.next% %.d% %.deep')
def test_groups(self): fl = {'ws': ' '} sc = Scope() sc.push() sc.current = Identifier(['.a', ',', '.b'], 0).parse(sc) for i in [ (['&', '.scope', ' ', 'a'], '.a.scope a, .b.scope a'), (['.scope', '&', ' ', 'a'], '.scope.a a, .scope.b a'), (['.scope', ' ', 'a', '&'], '.scope a.a, .scope a.b'), (['>', '&', '.scope', ' ', 'a'], ' > .a.scope a, > .b.scope a'), ]: t, r = i id = Identifier(t, 0) self.assertEqual(id.parse(sc).fmt(fl), r, i) sc.current = Identifier(['.next'], 0).parse(sc) sc.push() sc.current = Identifier(['.c', ',', '.d'], 0).parse(sc) id = Identifier(['.deep'], 0) self.assertEqual(id.parse(sc).fmt(fl), '.a .next .c .deep, ' '.a .next .d .deep, ' '.b .next .c .deep, ' '.b .next .d .deep') self.assertEqual(id.raw(), '.a% %.next% %.c% %.deep%.a%' ' %.next% %.d% %.deep%.b% %.next%' ' %.c% %.deep%.b% %.next% %.d% %.deep')
def test_media(self): fl = {'ws': ' '} sc = Scope() sc.push() sc.current = Identifier( ['@media', ' ', 'screen', ',', 'projection'], 0).parse(sc) self.assertEqual(sc.current.fmt(fl), '@media screen,projection') for i in [ (['html'], 'html'), ]: t, r = i id = Identifier(t, 0) self.assertEqual(id.parse(sc).fmt(fl), r, i)
def test_media(self): fl = {'ws': ' ', 'nl': '\n'} sc = Scope() sc.push() sc.current = Identifier(['@media', ' ', 'screen', ',', 'projection'], 0).parse(sc) self.assertEqual(sc.current.fmt(fl), '@media screen,projection') for i in [ (['html'], 'html'), ]: t, r = i id = Identifier(t, 0) self.assertEqual(id.parse(sc).fmt(fl), r, i)
def test_basic(self): fl = {'ws': ' '} for i in [ ([], ''), (['.scope', ' ', 'a'], '.scope a'), (['a', ' ', '.scope'], 'a .scope'), (['a', '.scope'], 'a.scope'), (['a', '>', 'p', '>', 'h2'], 'a > p > h2'), (['a', '~', 'p', '+', 'h2'], 'a ~ p + h2'), (['*', 'html'], '* html'), ]: t, r = i id = Identifier(t, 0) self.assertEqual(id.parse(None).fmt(fl), r, i)
def test_basic(self): fl = {'ws': ' ', 'nl': '\n'} for i in [ ([], ''), (['.scope', ' ', 'a'], '.scope a'), (['a', ' ', '.scope'], 'a .scope'), (['a', '.scope'], 'a.scope'), (['a', '>', 'p', '>', 'h2'], 'a > p > h2'), (['a', '~', 'p', '+', 'h2'], 'a ~ p + h2'), (['*', 'html'], '* html'), ]: t, r = i id = Identifier(t, 0) self.assertEqual(id.parse(None).fmt(fl), r, i)
def test_scope(self): fl = {'ws': ' '} sc = Scope() sc.push() sc.current = Identifier(['.current'], 0).parse(sc) for i in [ (['.scope', ' ', 'a'], '.current .scope a'), (['a', ' ', '.scope'], '.current a .scope'), (['a', '.scope'], '.current a.scope'), (['a', '>', 'p', '>', 'h2'], '.current a > p > h2'), (['a', '~', 'p', '+', 'h2'], '.current a ~ p + h2'), (['>', 'p', '+', 'h2'], '.current > p + h2'), ]: t, r = i id = Identifier(t, 0) self.assertEqual(id.parse(sc).fmt(fl), r, i)
def test_scope(self): fl = {'ws': ' ', 'nl': '\n'} sc = Scope() sc.push() sc.current = Identifier(['.current'], 0).parse(sc) for i in [ (['.scope', ' ', 'a'], '.current .scope a'), (['a', ' ', '.scope'], '.current a .scope'), (['a', '.scope'], '.current a.scope'), (['a', '>', 'p', '>', 'h2'], '.current a > p > h2'), (['a', '~', 'p', '+', 'h2'], '.current a ~ p + h2'), (['>', 'p', '+', 'h2'], '.current > p + h2'), ]: t, r = i id = Identifier(t, 0) self.assertEqual(id.parse(sc).fmt(fl), r, i)
def test_combinators(self): fl = {'ws': ' '} sc = Scope() sc.push() sc.current = Identifier(['.current'], 0).parse(sc) for i in [ (['&', '.scope', ' ', 'a'], '.current.scope a'), (['.scope', '&', ' ', 'a'], '.scope.current a'), (['.scope', ' ', 'a', '&'], '.scope a.current'), (['&', '>', '.scope', ' ', 'a'], '.current > .scope a'), (['.span', '&', '.scope', ' ', 'a', '&'], '.span.current.scope a.current'), ]: t, r = i id = Identifier(t, 0) self.assertEqual(id.parse(sc).fmt(fl), r, i) sc.push() sc.current = Identifier(['&', '.next'], 0).parse(sc) id = Identifier(['&', '.top'], 0) self.assertEqual(id.parse(sc).fmt(fl), '.current.next.top')
def test_combinators(self): fl = {'ws': ' ', 'nl': '\n'} sc = Scope() sc.push() sc.current = Identifier(['.current'], 0).parse(sc) for i in [ (['&', '.scope', ' ', 'a'], '.current.scope a'), (['.scope', '&', ' ', 'a'], '.scope.current a'), (['.scope', ' ', 'a', '&'], '.scope a.current'), (['&', '>', '.scope', ' ', 'a'], '.current > .scope a'), (['.span', '&', '.scope', ' ', 'a', '&'], '.span.current.scope a.current'), ]: t, r = i id = Identifier(t, 0) self.assertEqual(id.parse(sc).fmt(fl), r, i) sc.push() sc.current = Identifier(['&', '.next'], 0).parse(sc) id = Identifier(['&', '.top'], 0) self.assertEqual(id.parse(sc).fmt(fl), '.current.next.top')
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