File: matchers.py

package info (click to toggle)
python-libcst 1.8.6-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,240 kB
  • sloc: python: 78,096; makefile: 15; sh: 2
file content (45 lines) | stat: -rw-r--r-- 1,708 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
#

from dataclasses import fields, is_dataclass, MISSING

from libcst import matchers
from libcst._nodes.base import CSTNode


def node_to_matcher(
    node: CSTNode, *, match_syntactic_trivia: bool = False
) -> matchers.BaseMatcherNode:
    """Convert a concrete node to a matcher."""
    if not is_dataclass(node):
        raise ValueError(f"{node} is not a CSTNode")

    attrs = {}
    for field in fields(node):
        name = field.name
        child = getattr(node, name)
        if not match_syntactic_trivia and field.name.startswith("whitespace"):
            # Not all nodes have whitespace fields, some have multiple, but they all
            # start with whitespace*
            child = matchers.DoNotCare()
        elif field.default is not MISSING and child == field.default:
            child = matchers.DoNotCare()
        # pyre-ignore[29]: Union[MISSING_TYPE, ...] is not a function.
        elif field.default_factory is not MISSING and child == field.default_factory():
            child = matchers.DoNotCare()
        elif isinstance(child, (list, tuple)):
            child = type(child)(
                node_to_matcher(item, match_syntactic_trivia=match_syntactic_trivia)
                for item in child
            )
        elif hasattr(matchers, type(child).__name__):
            child = node_to_matcher(
                child, match_syntactic_trivia=match_syntactic_trivia
            )
        attrs[name] = child

    matcher = getattr(matchers, type(node).__name__)
    return matcher(**attrs)