Skip to content

Add tinycss2.ast.Node.get_child_nodes to allow walking the tree #66

@encukou

Description

@encukou

It would be nice to allow walking the AST even in code that does not understand all the node types, for example to:

  • gather all ParseError nodes
  • gather all URLs
  • display the AST in a GUI tree widget

... and so on.

Currently, it seems that code to gather URLs would look like this (click to expand)
def get_urls_from_tinycss2_nodes(nodes):
    if nodes is None:
        return
    for node in nodes:
        match node:
            case tinycss2.ast.QualifiedRule():
                yield from get_urls_from_tinycss2_nodes(node.prelude)
                yield from get_urls_from_tinycss2_nodes(node.content)
            case tinycss2.ast.AtRule():
                yield from get_urls_from_tinycss2_nodes(node.prelude)
                yield from get_urls_from_tinycss2_nodes(node.content)
            case tinycss2.ast.Declaration():
                yield from get_urls_from_tinycss2_nodes(node.value)
            case tinycss2.ast.ParseError():
                pass
            case tinycss2.ast.Comment():
                pass
            case tinycss2.ast.WhitespaceToken():
                pass
            case tinycss2.ast.LiteralToken():
                pass
            case tinycss2.ast.IdentToken():
                pass
            case tinycss2.ast.AtKeywordToken():
                pass
            case tinycss2.ast.HashToken():
                pass
            case tinycss2.ast.StringToken():
                pass
            case tinycss2.ast.URLToken():
                # TODO: unescape
                yield node.value
            case tinycss2.ast.UnicodeRangeToken():
                pass
            case tinycss2.ast.NumberToken():
                pass
            case tinycss2.ast.PercentageToken():
                pass
            case tinycss2.ast.DimensionToken():
                pass
            case tinycss2.ast.ParenthesesBlock():
                yield from get_urls_from_tinycss2_nodes(node.content)
            case tinycss2.ast.SquareBracketsBlock():
                yield from get_urls_from_tinycss2_nodes(node.content)
            case tinycss2.ast.CurlyBracketsBlock():
                yield from get_urls_from_tinycss2_nodes(node.content)
            case tinycss2.ast.FunctionBlock():
                yield from get_urls_from_tinycss2_nodes(node.arguments)
                if node.name == 'url':
                    match node.arguments:
                        case [tinycss2.ast.StringToken() as string]:
                            # TODO: unescape
                            yield string.value
            case _:
                raise TypeError(node)

Would it make sense to add a method like get_child_nodes() (or child_nodes iterable property) to all Node classes, to make this both easier and resistant to tinycss2 adding new node types?

I'm willing to do the work :)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions