"""Generated by atdpy from type definitions in semgrep_output_v1.atd.

This implements classes for the types defined in 'semgrep_output_v1.atd', providing
methods and functions to convert data from/to JSON.
"""

# Disable flake8 entirely on this file:
# flake8: noqa

# Import annotations to allow forward references
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any, Callable, Dict, List, NoReturn, Optional, Tuple, Union

import json

############################################################################
# Private functions
############################################################################


def _atd_missing_json_field(type_name: str, json_field_name: str) -> NoReturn:
    raise ValueError(f"missing field '{json_field_name}'"
                     f" in JSON object of type '{type_name}'")


def _atd_bad_json(expected_type: str, json_value: Any) -> NoReturn:
    value_str = str(json_value)
    if len(value_str) > 200:
        value_str = value_str[:200] + '…'

    raise ValueError(f"incompatible JSON value where"
                     f" type '{expected_type}' was expected: '{value_str}'")


def _atd_bad_python(expected_type: str, json_value: Any) -> NoReturn:
    value_str = str(json_value)
    if len(value_str) > 200:
        value_str = value_str[:200] + '…'

    raise ValueError(f"incompatible Python value where"
                     f" type '{expected_type}' was expected: '{value_str}'")


def _atd_read_unit(x: Any) -> None:
    if x is None:
        return x
    else:
        _atd_bad_json('unit', x)


def _atd_read_bool(x: Any) -> bool:
    if isinstance(x, bool):
        return x
    else:
        _atd_bad_json('bool', x)


def _atd_read_int(x: Any) -> int:
    if isinstance(x, int):
        return x
    else:
        _atd_bad_json('int', x)


def _atd_read_float(x: Any) -> float:
    if isinstance(x, (int, float)):
        return x
    else:
        _atd_bad_json('float', x)


def _atd_read_string(x: Any) -> str:
    if isinstance(x, str):
        return x
    else:
        _atd_bad_json('str', x)


def _atd_read_list(
            read_elt: Callable[[Any], Any]
        ) -> Callable[[List[Any]], List[Any]]:
    def read_list(elts: List[Any]) -> List[Any]:
        if isinstance(elts, list):
            return [read_elt(elt) for elt in elts]
        else:
            _atd_bad_json('array', elts)
    return read_list


def _atd_read_assoc_array_into_dict(
            read_key: Callable[[Any], Any],
            read_value: Callable[[Any], Any],
        ) -> Callable[[List[Any]], Dict[Any, Any]]:
    def read_assoc(elts: List[List[Any]]) -> Dict[str, Any]:
        if isinstance(elts, list):
            return {read_key(elt[0]): read_value(elt[1]) for elt in elts}
        else:
            _atd_bad_json('array', elts)
            raise AssertionError('impossible')  # keep mypy happy
    return read_assoc


def _atd_read_assoc_object_into_dict(
            read_value: Callable[[Any], Any]
        ) -> Callable[[Dict[str, Any]], Dict[str, Any]]:
    def read_assoc(elts: Dict[str, Any]) -> Dict[str, Any]:
        if isinstance(elts, dict):
            return {_atd_read_string(k): read_value(v)
                    for k, v in elts.items()}
        else:
            _atd_bad_json('object', elts)
            raise AssertionError('impossible')  # keep mypy happy
    return read_assoc


def _atd_read_assoc_object_into_list(
            read_value: Callable[[Any], Any]
        ) -> Callable[[Dict[str, Any]], List[Tuple[str, Any]]]:
    def read_assoc(elts: Dict[str, Any]) -> List[Tuple[str, Any]]:
        if isinstance(elts, dict):
            return [(_atd_read_string(k), read_value(v))
                    for k, v in elts.items()]
        else:
            _atd_bad_json('object', elts)
            raise AssertionError('impossible')  # keep mypy happy
    return read_assoc


def _atd_read_nullable(read_elt: Callable[[Any], Any]) \
        -> Callable[[Optional[Any]], Optional[Any]]:
    def read_nullable(x: Any) -> Any:
        if x is None:
            return None
        else:
            return read_elt(x)
    return read_nullable


def _atd_read_option(read_elt: Callable[[Any], Any]) \
        -> Callable[[Optional[Any]], Optional[Any]]:
    def read_option(x: Any) -> Any:
        if x == 'None':
            return None
        elif isinstance(x, List) and len(x) == 2 and x[0] == 'Some':
            return read_elt(x[1])
        else:
            _atd_bad_json('option', x)
            raise AssertionError('impossible')  # keep mypy happy
    return read_option


def _atd_write_unit(x: Any) -> None:
    if x is None:
        return x
    else:
        _atd_bad_python('unit', x)


def _atd_write_bool(x: Any) -> bool:
    if isinstance(x, bool):
        return x
    else:
        _atd_bad_python('bool', x)


def _atd_write_int(x: Any) -> int:
    if isinstance(x, int):
        return x
    else:
        _atd_bad_python('int', x)


def _atd_write_float(x: Any) -> float:
    if isinstance(x, (int, float)):
        return x
    else:
        _atd_bad_python('float', x)


def _atd_write_string(x: Any) -> str:
    if isinstance(x, str):
        return x
    else:
        _atd_bad_python('str', x)


def _atd_write_list(
            write_elt: Callable[[Any], Any]
        ) -> Callable[[List[Any]], List[Any]]:
    def write_list(elts: List[Any]) -> List[Any]:
        if isinstance(elts, list):
            return [write_elt(elt) for elt in elts]
        else:
            _atd_bad_python('list', elts)
    return write_list


def _atd_write_assoc_dict_to_array(
            write_key: Callable[[Any], Any],
            write_value: Callable[[Any], Any]
        ) -> Callable[[Dict[Any, Any]], List[Tuple[Any, Any]]]:
    def write_assoc(elts: Dict[str, Any]) -> List[Tuple[str, Any]]:
        if isinstance(elts, dict):
            return [(write_key(k), write_value(v)) for k, v in elts.items()]
        else:
            _atd_bad_python('Dict[str, <value type>]]', elts)
            raise AssertionError('impossible')  # keep mypy happy
    return write_assoc


def _atd_write_assoc_dict_to_object(
            write_value: Callable[[Any], Any]
        ) -> Callable[[Dict[str, Any]], Dict[str, Any]]:
    def write_assoc(elts: Dict[str, Any]) -> Dict[str, Any]:
        if isinstance(elts, dict):
            return {_atd_write_string(k): write_value(v)
                    for k, v in elts.items()}
        else:
            _atd_bad_python('Dict[str, <value type>]', elts)
            raise AssertionError('impossible')  # keep mypy happy
    return write_assoc


def _atd_write_assoc_list_to_object(
            write_value: Callable[[Any], Any],
        ) -> Callable[[List[Any]], Dict[str, Any]]:
    def write_assoc(elts: List[List[Any]]) -> Dict[str, Any]:
        if isinstance(elts, list):
            return {_atd_write_string(elt[0]): write_value(elt[1])
                    for elt in elts}
        else:
            _atd_bad_python('List[Tuple[<key type>, <value type>]]', elts)
            raise AssertionError('impossible')  # keep mypy happy
    return write_assoc


def _atd_write_nullable(write_elt: Callable[[Any], Any]) \
        -> Callable[[Optional[Any]], Optional[Any]]:
    def write_nullable(x: Any) -> Any:
        if x is None:
            return None
        else:
            return write_elt(x)
    return write_nullable


def _atd_write_option(write_elt: Callable[[Any], Any]) \
        -> Callable[[Optional[Any]], Optional[Any]]:
    def write_option(x: Any) -> Any:
        if x is None:
            return 'None'
        else:
            return ['Some', write_elt(x)]
    return write_option


############################################################################
# Public classes
############################################################################


@dataclass(frozen=True)
class OSS:
    """Original type: engine_kind = [ ... | OSS | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'OSS'

    @staticmethod
    def to_json() -> Any:
        return 'OSS'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class PRO:
    """Original type: engine_kind = [ ... | PRO | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'PRO'

    @staticmethod
    def to_json() -> Any:
        return 'PRO'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class EngineKind:
    """Original type: engine_kind = [ ... ]"""

    value: Union[OSS, PRO]

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return self.value.kind

    @classmethod
    def from_json(cls, x: Any) -> 'EngineKind':
        if isinstance(x, str):
            if x == 'OSS':
                return cls(OSS())
            if x == 'PRO':
                return cls(PRO())
            _atd_bad_json('EngineKind', x)
        _atd_bad_json('EngineKind', x)

    def to_json(self) -> Any:
        return self.value.to_json()

    @classmethod
    def from_json_string(cls, x: str) -> 'EngineKind':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Fpath:
    """Original type: fpath"""

    value: str

    @classmethod
    def from_json(cls, x: Any) -> 'Fpath':
        return cls(_atd_read_string(x))

    def to_json(self) -> Any:
        return _atd_write_string(self.value)

    @classmethod
    def from_json_string(cls, x: str) -> 'Fpath':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class And:
    """Original type: matching_operation = [ ... | And | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'And'

    @staticmethod
    def to_json() -> Any:
        return 'And'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Or:
    """Original type: matching_operation = [ ... | Or | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Or'

    @staticmethod
    def to_json() -> Any:
        return 'Or'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Inside:
    """Original type: matching_operation = [ ... | Inside | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Inside'

    @staticmethod
    def to_json() -> Any:
        return 'Inside'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class XPat:
    """Original type: matching_operation = [ ... | XPat of ... | ... ]"""

    value: str

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'XPat'

    def to_json(self) -> Any:
        return ['XPat', _atd_write_string(self.value)]

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Negation:
    """Original type: matching_operation = [ ... | Negation | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Negation'

    @staticmethod
    def to_json() -> Any:
        return 'Negation'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Filter:
    """Original type: matching_operation = [ ... | Filter of ... | ... ]"""

    value: str

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Filter'

    def to_json(self) -> Any:
        return ['Filter', _atd_write_string(self.value)]

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Taint:
    """Original type: matching_operation = [ ... | Taint | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Taint'

    @staticmethod
    def to_json() -> Any:
        return 'Taint'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class TaintSource:
    """Original type: matching_operation = [ ... | TaintSource | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'TaintSource'

    @staticmethod
    def to_json() -> Any:
        return 'TaintSource'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class TaintSink:
    """Original type: matching_operation = [ ... | TaintSink | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'TaintSink'

    @staticmethod
    def to_json() -> Any:
        return 'TaintSink'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class TaintSanitizer:
    """Original type: matching_operation = [ ... | TaintSanitizer | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'TaintSanitizer'

    @staticmethod
    def to_json() -> Any:
        return 'TaintSanitizer'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class EllipsisAndStmts:
    """Original type: matching_operation = [ ... | EllipsisAndStmts | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'EllipsisAndStmts'

    @staticmethod
    def to_json() -> Any:
        return 'EllipsisAndStmts'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class ClassHeaderAndElems:
    """Original type: matching_operation = [ ... | ClassHeaderAndElems | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'ClassHeaderAndElems'

    @staticmethod
    def to_json() -> Any:
        return 'ClassHeaderAndElems'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class MatchingOperation:
    """Original type: matching_operation = [ ... ]"""

    value: Union[And, Or, Inside, XPat, Negation, Filter, Taint, TaintSource, TaintSink, TaintSanitizer, EllipsisAndStmts, ClassHeaderAndElems]

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return self.value.kind

    @classmethod
    def from_json(cls, x: Any) -> 'MatchingOperation':
        if isinstance(x, str):
            if x == 'And':
                return cls(And())
            if x == 'Or':
                return cls(Or())
            if x == 'Inside':
                return cls(Inside())
            if x == 'Negation':
                return cls(Negation())
            if x == 'Taint':
                return cls(Taint())
            if x == 'TaintSource':
                return cls(TaintSource())
            if x == 'TaintSink':
                return cls(TaintSink())
            if x == 'TaintSanitizer':
                return cls(TaintSanitizer())
            if x == 'EllipsisAndStmts':
                return cls(EllipsisAndStmts())
            if x == 'ClassHeaderAndElems':
                return cls(ClassHeaderAndElems())
            _atd_bad_json('MatchingOperation', x)
        if isinstance(x, List) and len(x) == 2:
            cons = x[0]
            if cons == 'XPat':
                return cls(XPat(_atd_read_string(x[1])))
            if cons == 'Filter':
                return cls(Filter(_atd_read_string(x[1])))
            _atd_bad_json('MatchingOperation', x)
        _atd_bad_json('MatchingOperation', x)

    def to_json(self) -> Any:
        return self.value.to_json()

    @classmethod
    def from_json_string(cls, x: str) -> 'MatchingOperation':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class Position:
    """Original type: position = { ... }"""

    line: int
    col: int
    offset: int = field(default_factory=lambda: 0)

    @classmethod
    def from_json(cls, x: Any) -> 'Position':
        if isinstance(x, dict):
            return cls(
                line=_atd_read_int(x['line']) if 'line' in x else _atd_missing_json_field('Position', 'line'),
                col=_atd_read_int(x['col']) if 'col' in x else _atd_missing_json_field('Position', 'col'),
                offset=_atd_read_int(x['offset']) if 'offset' in x else 0,
            )
        else:
            _atd_bad_json('Position', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['line'] = _atd_write_int(self.line)
        res['col'] = _atd_write_int(self.col)
        res['offset'] = _atd_write_int(self.offset)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'Position':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Location:
    """Original type: location = { ... }"""

    path: Fpath
    start: Position
    end: Position

    @classmethod
    def from_json(cls, x: Any) -> 'Location':
        if isinstance(x, dict):
            return cls(
                path=Fpath.from_json(x['path']) if 'path' in x else _atd_missing_json_field('Location', 'path'),
                start=Position.from_json(x['start']) if 'start' in x else _atd_missing_json_field('Location', 'start'),
                end=Position.from_json(x['end']) if 'end' in x else _atd_missing_json_field('Location', 'end'),
            )
        else:
            _atd_bad_json('Location', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['path'] = (lambda x: x.to_json())(self.path)
        res['start'] = (lambda x: x.to_json())(self.start)
        res['end'] = (lambda x: x.to_json())(self.end)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'Location':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class MatchIntermediateVar:
    """Original type: match_intermediate_var = { ... }"""

    location: Location
    content: str

    @classmethod
    def from_json(cls, x: Any) -> 'MatchIntermediateVar':
        if isinstance(x, dict):
            return cls(
                location=Location.from_json(x['location']) if 'location' in x else _atd_missing_json_field('MatchIntermediateVar', 'location'),
                content=_atd_read_string(x['content']) if 'content' in x else _atd_missing_json_field('MatchIntermediateVar', 'content'),
            )
        else:
            _atd_bad_json('MatchIntermediateVar', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['location'] = (lambda x: x.to_json())(self.location)
        res['content'] = _atd_write_string(self.content)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'MatchIntermediateVar':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class RawJson:
    """Original type: raw_json"""

    value: Any

    @classmethod
    def from_json(cls, x: Any) -> 'RawJson':
        return cls((lambda x: x)(x))

    def to_json(self) -> Any:
        return (lambda x: x)(self.value)

    @classmethod
    def from_json_string(cls, x: str) -> 'RawJson':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class RuleId:
    """Original type: rule_id"""

    value: str

    @classmethod
    def from_json(cls, x: Any) -> 'RuleId':
        return cls(_atd_read_string(x))

    def to_json(self) -> Any:
        return _atd_write_string(self.value)

    @classmethod
    def from_json_string(cls, x: str) -> 'RuleId':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class SvalueValue:
    """Original type: svalue_value = { ... }"""

    svalue_abstract_content: str
    svalue_start: Optional[Position] = None
    svalue_end: Optional[Position] = None

    @classmethod
    def from_json(cls, x: Any) -> 'SvalueValue':
        if isinstance(x, dict):
            return cls(
                svalue_abstract_content=_atd_read_string(x['svalue_abstract_content']) if 'svalue_abstract_content' in x else _atd_missing_json_field('SvalueValue', 'svalue_abstract_content'),
                svalue_start=Position.from_json(x['svalue_start']) if 'svalue_start' in x else None,
                svalue_end=Position.from_json(x['svalue_end']) if 'svalue_end' in x else None,
            )
        else:
            _atd_bad_json('SvalueValue', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['svalue_abstract_content'] = _atd_write_string(self.svalue_abstract_content)
        if self.svalue_start is not None:
            res['svalue_start'] = (lambda x: x.to_json())(self.svalue_start)
        if self.svalue_end is not None:
            res['svalue_end'] = (lambda x: x.to_json())(self.svalue_end)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'SvalueValue':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class MetavarValue:
    """Original type: metavar_value = { ... }"""

    start: Position
    end: Position
    abstract_content: str
    propagated_value: Optional[SvalueValue] = None

    @classmethod
    def from_json(cls, x: Any) -> 'MetavarValue':
        if isinstance(x, dict):
            return cls(
                start=Position.from_json(x['start']) if 'start' in x else _atd_missing_json_field('MetavarValue', 'start'),
                end=Position.from_json(x['end']) if 'end' in x else _atd_missing_json_field('MetavarValue', 'end'),
                abstract_content=_atd_read_string(x['abstract_content']) if 'abstract_content' in x else _atd_missing_json_field('MetavarValue', 'abstract_content'),
                propagated_value=SvalueValue.from_json(x['propagated_value']) if 'propagated_value' in x else None,
            )
        else:
            _atd_bad_json('MetavarValue', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['start'] = (lambda x: x.to_json())(self.start)
        res['end'] = (lambda x: x.to_json())(self.end)
        res['abstract_content'] = _atd_write_string(self.abstract_content)
        if self.propagated_value is not None:
            res['propagated_value'] = (lambda x: x.to_json())(self.propagated_value)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'MetavarValue':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Metavars:
    """Original type: metavars"""

    value: Dict[str, MetavarValue]

    @classmethod
    def from_json(cls, x: Any) -> 'Metavars':
        return cls(_atd_read_assoc_object_into_dict(MetavarValue.from_json)(x))

    def to_json(self) -> Any:
        return _atd_write_assoc_dict_to_object((lambda x: x.to_json()))(self.value)

    @classmethod
    def from_json_string(cls, x: str) -> 'Metavars':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class CONFIRMEDVALID:
    """Original type: validation_state = [ ... | CONFIRMED_VALID | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'CONFIRMEDVALID'

    @staticmethod
    def to_json() -> Any:
        return 'CONFIRMED_VALID'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class CONFIRMEDINVALID:
    """Original type: validation_state = [ ... | CONFIRMED_INVALID | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'CONFIRMEDINVALID'

    @staticmethod
    def to_json() -> Any:
        return 'CONFIRMED_INVALID'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class VALIDATIONERROR:
    """Original type: validation_state = [ ... | VALIDATION_ERROR | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'VALIDATIONERROR'

    @staticmethod
    def to_json() -> Any:
        return 'VALIDATION_ERROR'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class NOVALIDATOR:
    """Original type: validation_state = [ ... | NO_VALIDATOR | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'NOVALIDATOR'

    @staticmethod
    def to_json() -> Any:
        return 'NO_VALIDATOR'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class ValidationState:
    """Original type: validation_state = [ ... ]"""

    value: Union[CONFIRMEDVALID, CONFIRMEDINVALID, VALIDATIONERROR, NOVALIDATOR]

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return self.value.kind

    @classmethod
    def from_json(cls, x: Any) -> 'ValidationState':
        if isinstance(x, str):
            if x == 'CONFIRMED_VALID':
                return cls(CONFIRMEDVALID())
            if x == 'CONFIRMED_INVALID':
                return cls(CONFIRMEDINVALID())
            if x == 'VALIDATION_ERROR':
                return cls(VALIDATIONERROR())
            if x == 'NO_VALIDATOR':
                return cls(NOVALIDATOR())
            _atd_bad_json('ValidationState', x)
        _atd_bad_json('ValidationState', x)

    def to_json(self) -> Any:
        return self.value.to_json()

    @classmethod
    def from_json_string(cls, x: str) -> 'ValidationState':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class CliLoc:
    """Original type: match_call_trace = [ ... | CliLoc of ... | ... ]"""

    value: Tuple[Location, str]

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'CliLoc'

    def to_json(self) -> Any:
        return ['CliLoc', (lambda x: [(lambda x: x.to_json())(x[0]), _atd_write_string(x[1])] if isinstance(x, tuple) and len(x) == 2 else _atd_bad_python('tuple of length 2', x))(self.value)]

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class CliCall:
    """Original type: match_call_trace = [ ... | CliCall of ... | ... ]"""

    value: Tuple[Tuple[Location, str], List[MatchIntermediateVar], MatchCallTrace]

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'CliCall'

    def to_json(self) -> Any:
        return ['CliCall', (lambda x: [(lambda x: [(lambda x: x.to_json())(x[0]), _atd_write_string(x[1])] if isinstance(x, tuple) and len(x) == 2 else _atd_bad_python('tuple of length 2', x))(x[0]), _atd_write_list((lambda x: x.to_json()))(x[1]), (lambda x: x.to_json())(x[2])] if isinstance(x, tuple) and len(x) == 3 else _atd_bad_python('tuple of length 3', x))(self.value)]

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class MatchCallTrace:
    """Original type: match_call_trace = [ ... ]"""

    value: Union[CliLoc, CliCall]

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return self.value.kind

    @classmethod
    def from_json(cls, x: Any) -> 'MatchCallTrace':
        if isinstance(x, List) and len(x) == 2:
            cons = x[0]
            if cons == 'CliLoc':
                return cls(CliLoc((lambda x: (Location.from_json(x[0]), _atd_read_string(x[1])) if isinstance(x, list) and len(x) == 2 else _atd_bad_json('array of length 2', x))(x[1])))
            if cons == 'CliCall':
                return cls(CliCall((lambda x: ((lambda x: (Location.from_json(x[0]), _atd_read_string(x[1])) if isinstance(x, list) and len(x) == 2 else _atd_bad_json('array of length 2', x))(x[0]), _atd_read_list(MatchIntermediateVar.from_json)(x[1]), MatchCallTrace.from_json(x[2])) if isinstance(x, list) and len(x) == 3 else _atd_bad_json('array of length 3', x))(x[1])))
            _atd_bad_json('MatchCallTrace', x)
        _atd_bad_json('MatchCallTrace', x)

    def to_json(self) -> Any:
        return self.value.to_json()

    @classmethod
    def from_json_string(cls, x: str) -> 'MatchCallTrace':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class MatchDataflowTrace:
    """Original type: match_dataflow_trace = { ... }"""

    taint_source: Optional[MatchCallTrace] = None
    intermediate_vars: Optional[List[MatchIntermediateVar]] = None
    taint_sink: Optional[MatchCallTrace] = None

    @classmethod
    def from_json(cls, x: Any) -> 'MatchDataflowTrace':
        if isinstance(x, dict):
            return cls(
                taint_source=MatchCallTrace.from_json(x['taint_source']) if 'taint_source' in x else None,
                intermediate_vars=_atd_read_list(MatchIntermediateVar.from_json)(x['intermediate_vars']) if 'intermediate_vars' in x else None,
                taint_sink=MatchCallTrace.from_json(x['taint_sink']) if 'taint_sink' in x else None,
            )
        else:
            _atd_bad_json('MatchDataflowTrace', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        if self.taint_source is not None:
            res['taint_source'] = (lambda x: x.to_json())(self.taint_source)
        if self.intermediate_vars is not None:
            res['intermediate_vars'] = _atd_write_list((lambda x: x.to_json()))(self.intermediate_vars)
        if self.taint_sink is not None:
            res['taint_sink'] = (lambda x: x.to_json())(self.taint_sink)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'MatchDataflowTrace':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class CoreMatchExtra:
    """Original type: core_match_extra = { ... }"""

    metavars: Metavars
    engine_kind: EngineKind
    message: Optional[str] = None
    dataflow_trace: Optional[MatchDataflowTrace] = None
    rendered_fix: Optional[str] = None
    validation_state: Optional[ValidationState] = None
    extra_extra: Optional[RawJson] = None

    @classmethod
    def from_json(cls, x: Any) -> 'CoreMatchExtra':
        if isinstance(x, dict):
            return cls(
                metavars=Metavars.from_json(x['metavars']) if 'metavars' in x else _atd_missing_json_field('CoreMatchExtra', 'metavars'),
                engine_kind=EngineKind.from_json(x['engine_kind']) if 'engine_kind' in x else _atd_missing_json_field('CoreMatchExtra', 'engine_kind'),
                message=_atd_read_string(x['message']) if 'message' in x else None,
                dataflow_trace=MatchDataflowTrace.from_json(x['dataflow_trace']) if 'dataflow_trace' in x else None,
                rendered_fix=_atd_read_string(x['rendered_fix']) if 'rendered_fix' in x else None,
                validation_state=ValidationState.from_json(x['validation_state']) if 'validation_state' in x else None,
                extra_extra=RawJson.from_json(x['extra_extra']) if 'extra_extra' in x else None,
            )
        else:
            _atd_bad_json('CoreMatchExtra', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['metavars'] = (lambda x: x.to_json())(self.metavars)
        res['engine_kind'] = (lambda x: x.to_json())(self.engine_kind)
        if self.message is not None:
            res['message'] = _atd_write_string(self.message)
        if self.dataflow_trace is not None:
            res['dataflow_trace'] = (lambda x: x.to_json())(self.dataflow_trace)
        if self.rendered_fix is not None:
            res['rendered_fix'] = _atd_write_string(self.rendered_fix)
        if self.validation_state is not None:
            res['validation_state'] = (lambda x: x.to_json())(self.validation_state)
        if self.extra_extra is not None:
            res['extra_extra'] = (lambda x: x.to_json())(self.extra_extra)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'CoreMatchExtra':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class CoreMatch:
    """Original type: core_match = { ... }"""

    check_id: RuleId
    path: Fpath
    start: Position
    end: Position
    extra: CoreMatchExtra

    @classmethod
    def from_json(cls, x: Any) -> 'CoreMatch':
        if isinstance(x, dict):
            return cls(
                check_id=RuleId.from_json(x['check_id']) if 'check_id' in x else _atd_missing_json_field('CoreMatch', 'check_id'),
                path=Fpath.from_json(x['path']) if 'path' in x else _atd_missing_json_field('CoreMatch', 'path'),
                start=Position.from_json(x['start']) if 'start' in x else _atd_missing_json_field('CoreMatch', 'start'),
                end=Position.from_json(x['end']) if 'end' in x else _atd_missing_json_field('CoreMatch', 'end'),
                extra=CoreMatchExtra.from_json(x['extra']) if 'extra' in x else _atd_missing_json_field('CoreMatch', 'extra'),
            )
        else:
            _atd_bad_json('CoreMatch', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['check_id'] = (lambda x: x.to_json())(self.check_id)
        res['path'] = (lambda x: x.to_json())(self.path)
        res['start'] = (lambda x: x.to_json())(self.start)
        res['end'] = (lambda x: x.to_json())(self.end)
        res['extra'] = (lambda x: x.to_json())(self.extra)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'CoreMatch':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class MatchingExplanation:
    """Original type: matching_explanation = { ... }"""

    op: MatchingOperation
    children: List[MatchingExplanation]
    matches: List[CoreMatch]
    loc: Location

    @classmethod
    def from_json(cls, x: Any) -> 'MatchingExplanation':
        if isinstance(x, dict):
            return cls(
                op=MatchingOperation.from_json(x['op']) if 'op' in x else _atd_missing_json_field('MatchingExplanation', 'op'),
                children=_atd_read_list(MatchingExplanation.from_json)(x['children']) if 'children' in x else _atd_missing_json_field('MatchingExplanation', 'children'),
                matches=_atd_read_list(CoreMatch.from_json)(x['matches']) if 'matches' in x else _atd_missing_json_field('MatchingExplanation', 'matches'),
                loc=Location.from_json(x['loc']) if 'loc' in x else _atd_missing_json_field('MatchingExplanation', 'loc'),
            )
        else:
            _atd_bad_json('MatchingExplanation', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['op'] = (lambda x: x.to_json())(self.op)
        res['children'] = _atd_write_list((lambda x: x.to_json()))(self.children)
        res['matches'] = _atd_write_list((lambda x: x.to_json()))(self.matches)
        res['loc'] = (lambda x: x.to_json())(self.loc)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'MatchingExplanation':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Version:
    """Original type: version"""

    value: str

    @classmethod
    def from_json(cls, x: Any) -> 'Version':
        return cls(_atd_read_string(x))

    def to_json(self) -> Any:
        return _atd_write_string(self.value)

    @classmethod
    def from_json_string(cls, x: str) -> 'Version':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Uri:
    """Original type: uri"""

    value: str

    @classmethod
    def from_json(cls, x: Any) -> 'Uri':
        return cls(_atd_read_string(x))

    def to_json(self) -> Any:
        return _atd_write_string(self.value)

    @classmethod
    def from_json_string(cls, x: str) -> 'Uri':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Direct:
    """Original type: transitivity = [ ... | Direct | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Direct'

    @staticmethod
    def to_json() -> Any:
        return 'direct'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Transitive:
    """Original type: transitivity = [ ... | Transitive | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Transitive'

    @staticmethod
    def to_json() -> Any:
        return 'transitive'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Unknown:
    """Original type: transitivity = [ ... | Unknown | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Unknown'

    @staticmethod
    def to_json() -> Any:
        return 'unknown'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Transitivity:
    """Original type: transitivity = [ ... ]"""

    value: Union[Direct, Transitive, Unknown]

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return self.value.kind

    @classmethod
    def from_json(cls, x: Any) -> 'Transitivity':
        if isinstance(x, str):
            if x == 'direct':
                return cls(Direct())
            if x == 'transitive':
                return cls(Transitive())
            if x == 'unknown':
                return cls(Unknown())
            _atd_bad_json('Transitivity', x)
        _atd_bad_json('Transitivity', x)

    def to_json(self) -> Any:
        return self.value.to_json()

    @classmethod
    def from_json_string(cls, x: str) -> 'Transitivity':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class TargetTimes:
    """Original type: target_times = { ... }"""

    path: Fpath
    num_bytes: int
    match_times: List[float]
    parse_times: List[float]
    run_time: float

    @classmethod
    def from_json(cls, x: Any) -> 'TargetTimes':
        if isinstance(x, dict):
            return cls(
                path=Fpath.from_json(x['path']) if 'path' in x else _atd_missing_json_field('TargetTimes', 'path'),
                num_bytes=_atd_read_int(x['num_bytes']) if 'num_bytes' in x else _atd_missing_json_field('TargetTimes', 'num_bytes'),
                match_times=_atd_read_list(_atd_read_float)(x['match_times']) if 'match_times' in x else _atd_missing_json_field('TargetTimes', 'match_times'),
                parse_times=_atd_read_list(_atd_read_float)(x['parse_times']) if 'parse_times' in x else _atd_missing_json_field('TargetTimes', 'parse_times'),
                run_time=_atd_read_float(x['run_time']) if 'run_time' in x else _atd_missing_json_field('TargetTimes', 'run_time'),
            )
        else:
            _atd_bad_json('TargetTimes', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['path'] = (lambda x: x.to_json())(self.path)
        res['num_bytes'] = _atd_write_int(self.num_bytes)
        res['match_times'] = _atd_write_list(_atd_write_float)(self.match_times)
        res['parse_times'] = _atd_write_list(_atd_write_float)(self.parse_times)
        res['run_time'] = _atd_write_float(self.run_time)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'TargetTimes':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class AlwaysSkipped:
    """Original type: skip_reason = [ ... | Always_skipped | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'AlwaysSkipped'

    @staticmethod
    def to_json() -> Any:
        return 'always_skipped'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class SemgrepignorePatternsMatch:
    """Original type: skip_reason = [ ... | Semgrepignore_patterns_match | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'SemgrepignorePatternsMatch'

    @staticmethod
    def to_json() -> Any:
        return 'semgrepignore_patterns_match'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class CliIncludeFlagsDoNotMatch:
    """Original type: skip_reason = [ ... | Cli_include_flags_do_not_match | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'CliIncludeFlagsDoNotMatch'

    @staticmethod
    def to_json() -> Any:
        return 'cli_include_flags_do_not_match'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class CliExcludeFlagsMatch:
    """Original type: skip_reason = [ ... | Cli_exclude_flags_match | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'CliExcludeFlagsMatch'

    @staticmethod
    def to_json() -> Any:
        return 'cli_exclude_flags_match'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class ExceededSizeLimit:
    """Original type: skip_reason = [ ... | Exceeded_size_limit | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'ExceededSizeLimit'

    @staticmethod
    def to_json() -> Any:
        return 'exceeded_size_limit'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class AnalysisFailedParserOrInternalError:
    """Original type: skip_reason = [ ... | Analysis_failed_parser_or_internal_error | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'AnalysisFailedParserOrInternalError'

    @staticmethod
    def to_json() -> Any:
        return 'analysis_failed_parser_or_internal_error'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class ExcludedByConfig:
    """Original type: skip_reason = [ ... | Excluded_by_config | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'ExcludedByConfig'

    @staticmethod
    def to_json() -> Any:
        return 'excluded_by_config'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class WrongLanguage:
    """Original type: skip_reason = [ ... | Wrong_language | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'WrongLanguage'

    @staticmethod
    def to_json() -> Any:
        return 'wrong_language'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class TooBig:
    """Original type: skip_reason = [ ... | Too_big | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'TooBig'

    @staticmethod
    def to_json() -> Any:
        return 'too_big'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Minified:
    """Original type: skip_reason = [ ... | Minified | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Minified'

    @staticmethod
    def to_json() -> Any:
        return 'minified'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Binary:
    """Original type: skip_reason = [ ... | Binary | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Binary'

    @staticmethod
    def to_json() -> Any:
        return 'binary'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class IrrelevantRule:
    """Original type: skip_reason = [ ... | Irrelevant_rule | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'IrrelevantRule'

    @staticmethod
    def to_json() -> Any:
        return 'irrelevant_rule'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class TooManyMatches:
    """Original type: skip_reason = [ ... | Too_many_matches | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'TooManyMatches'

    @staticmethod
    def to_json() -> Any:
        return 'too_many_matches'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class GitignorePatternsMatch:
    """Original type: skip_reason = [ ... | Gitignore_patterns_match | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'GitignorePatternsMatch'

    @staticmethod
    def to_json() -> Any:
        return 'Gitignore_patterns_match'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Dotfile:
    """Original type: skip_reason = [ ... | Dotfile | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Dotfile'

    @staticmethod
    def to_json() -> Any:
        return 'Dotfile'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class SkipReason:
    """Original type: skip_reason = [ ... ]"""

    value: Union[AlwaysSkipped, SemgrepignorePatternsMatch, CliIncludeFlagsDoNotMatch, CliExcludeFlagsMatch, ExceededSizeLimit, AnalysisFailedParserOrInternalError, ExcludedByConfig, WrongLanguage, TooBig, Minified, Binary, IrrelevantRule, TooManyMatches, GitignorePatternsMatch, Dotfile]

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return self.value.kind

    @classmethod
    def from_json(cls, x: Any) -> 'SkipReason':
        if isinstance(x, str):
            if x == 'always_skipped':
                return cls(AlwaysSkipped())
            if x == 'semgrepignore_patterns_match':
                return cls(SemgrepignorePatternsMatch())
            if x == 'cli_include_flags_do_not_match':
                return cls(CliIncludeFlagsDoNotMatch())
            if x == 'cli_exclude_flags_match':
                return cls(CliExcludeFlagsMatch())
            if x == 'exceeded_size_limit':
                return cls(ExceededSizeLimit())
            if x == 'analysis_failed_parser_or_internal_error':
                return cls(AnalysisFailedParserOrInternalError())
            if x == 'excluded_by_config':
                return cls(ExcludedByConfig())
            if x == 'wrong_language':
                return cls(WrongLanguage())
            if x == 'too_big':
                return cls(TooBig())
            if x == 'minified':
                return cls(Minified())
            if x == 'binary':
                return cls(Binary())
            if x == 'irrelevant_rule':
                return cls(IrrelevantRule())
            if x == 'too_many_matches':
                return cls(TooManyMatches())
            if x == 'Gitignore_patterns_match':
                return cls(GitignorePatternsMatch())
            if x == 'Dotfile':
                return cls(Dotfile())
            _atd_bad_json('SkipReason', x)
        _atd_bad_json('SkipReason', x)

    def to_json(self) -> Any:
        return self.value.to_json()

    @classmethod
    def from_json_string(cls, x: str) -> 'SkipReason':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class SkippedTarget:
    """Original type: skipped_target = { ... }"""

    path: Fpath
    reason: SkipReason
    details: Optional[str] = None
    rule_id: Optional[RuleId] = None

    @classmethod
    def from_json(cls, x: Any) -> 'SkippedTarget':
        if isinstance(x, dict):
            return cls(
                path=Fpath.from_json(x['path']) if 'path' in x else _atd_missing_json_field('SkippedTarget', 'path'),
                reason=SkipReason.from_json(x['reason']) if 'reason' in x else _atd_missing_json_field('SkippedTarget', 'reason'),
                details=_atd_read_string(x['details']) if 'details' in x else None,
                rule_id=RuleId.from_json(x['rule_id']) if 'rule_id' in x else None,
            )
        else:
            _atd_bad_json('SkippedTarget', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['path'] = (lambda x: x.to_json())(self.path)
        res['reason'] = (lambda x: x.to_json())(self.reason)
        if self.details is not None:
            res['details'] = _atd_write_string(self.details)
        if self.rule_id is not None:
            res['rule_id'] = (lambda x: x.to_json())(self.rule_id)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'SkippedTarget':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class SkippedRule:
    """Original type: skipped_rule = { ... }"""

    rule_id: RuleId
    details: str
    position: Position

    @classmethod
    def from_json(cls, x: Any) -> 'SkippedRule':
        if isinstance(x, dict):
            return cls(
                rule_id=RuleId.from_json(x['rule_id']) if 'rule_id' in x else _atd_missing_json_field('SkippedRule', 'rule_id'),
                details=_atd_read_string(x['details']) if 'details' in x else _atd_missing_json_field('SkippedRule', 'details'),
                position=Position.from_json(x['position']) if 'position' in x else _atd_missing_json_field('SkippedRule', 'position'),
            )
        else:
            _atd_bad_json('SkippedRule', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['rule_id'] = (lambda x: x.to_json())(self.rule_id)
        res['details'] = _atd_write_string(self.details)
        res['position'] = (lambda x: x.to_json())(self.position)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'SkippedRule':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Sha1:
    """Original type: sha1"""

    value: str

    @classmethod
    def from_json(cls, x: Any) -> 'Sha1':
        return cls(_atd_read_string(x))

    def to_json(self) -> Any:
        return _atd_write_string(self.value)

    @classmethod
    def from_json_string(cls, x: str) -> 'Sha1':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class ScannedAndSkipped:
    """Original type: scanned_and_skipped = { ... }"""

    scanned: List[Fpath]
    skipped: Optional[List[SkippedTarget]] = None

    @classmethod
    def from_json(cls, x: Any) -> 'ScannedAndSkipped':
        if isinstance(x, dict):
            return cls(
                scanned=_atd_read_list(Fpath.from_json)(x['scanned']) if 'scanned' in x else _atd_missing_json_field('ScannedAndSkipped', 'scanned'),
                skipped=_atd_read_list(SkippedTarget.from_json)(x['skipped']) if 'skipped' in x else None,
            )
        else:
            _atd_bad_json('ScannedAndSkipped', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['scanned'] = _atd_write_list((lambda x: x.to_json()))(self.scanned)
        if self.skipped is not None:
            res['skipped'] = _atd_write_list((lambda x: x.to_json()))(self.skipped)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'ScannedAndSkipped':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class GemfileLock:
    """Original type: sca_parser_name = [ ... | Gemfile_lock | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'GemfileLock'

    @staticmethod
    def to_json() -> Any:
        return 'gemfile_lock'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class GoMod:
    """Original type: sca_parser_name = [ ... | Go_mod | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'GoMod'

    @staticmethod
    def to_json() -> Any:
        return 'go_mod'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class GoSum:
    """Original type: sca_parser_name = [ ... | Go_sum | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'GoSum'

    @staticmethod
    def to_json() -> Any:
        return 'go_sum'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class GradleLockfile:
    """Original type: sca_parser_name = [ ... | Gradle_lockfile | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'GradleLockfile'

    @staticmethod
    def to_json() -> Any:
        return 'gradle_lockfile'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class GradleBuild:
    """Original type: sca_parser_name = [ ... | Gradle_build | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'GradleBuild'

    @staticmethod
    def to_json() -> Any:
        return 'gradle_build'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Jsondoc:
    """Original type: sca_parser_name = [ ... | Jsondoc | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Jsondoc'

    @staticmethod
    def to_json() -> Any:
        return 'jsondoc'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Pipfile:
    """Original type: sca_parser_name = [ ... | Pipfile | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Pipfile'

    @staticmethod
    def to_json() -> Any:
        return 'pipfile'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class PnpmLock:
    """Original type: sca_parser_name = [ ... | Pnpm_lock | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'PnpmLock'

    @staticmethod
    def to_json() -> Any:
        return 'pnpm_lock'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class PoetryLock:
    """Original type: sca_parser_name = [ ... | Poetry_lock | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'PoetryLock'

    @staticmethod
    def to_json() -> Any:
        return 'poetry_lock'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class PyprojectToml:
    """Original type: sca_parser_name = [ ... | Pyproject_toml | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'PyprojectToml'

    @staticmethod
    def to_json() -> Any:
        return 'pyproject_toml'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Requirements:
    """Original type: sca_parser_name = [ ... | Requirements | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Requirements'

    @staticmethod
    def to_json() -> Any:
        return 'requirements'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Yarn1:
    """Original type: sca_parser_name = [ ... | Yarn_1 | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Yarn1'

    @staticmethod
    def to_json() -> Any:
        return 'yarn_1'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Yarn2:
    """Original type: sca_parser_name = [ ... | Yarn_2 | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Yarn2'

    @staticmethod
    def to_json() -> Any:
        return 'yarn_2'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Pomtree:
    """Original type: sca_parser_name = [ ... | Pomtree | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Pomtree'

    @staticmethod
    def to_json() -> Any:
        return 'pomtree'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class CargoParser:
    """Original type: sca_parser_name = [ ... | Cargo_parser | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'CargoParser'

    @staticmethod
    def to_json() -> Any:
        return 'cargo'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class ComposerLock:
    """Original type: sca_parser_name = [ ... | Composer_lock | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'ComposerLock'

    @staticmethod
    def to_json() -> Any:
        return 'composer_lock'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class ScaParserName:
    """Original type: sca_parser_name = [ ... ]"""

    value: Union[GemfileLock, GoMod, GoSum, GradleLockfile, GradleBuild, Jsondoc, Pipfile, PnpmLock, PoetryLock, PyprojectToml, Requirements, Yarn1, Yarn2, Pomtree, CargoParser, ComposerLock]

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return self.value.kind

    @classmethod
    def from_json(cls, x: Any) -> 'ScaParserName':
        if isinstance(x, str):
            if x == 'gemfile_lock':
                return cls(GemfileLock())
            if x == 'go_mod':
                return cls(GoMod())
            if x == 'go_sum':
                return cls(GoSum())
            if x == 'gradle_lockfile':
                return cls(GradleLockfile())
            if x == 'gradle_build':
                return cls(GradleBuild())
            if x == 'jsondoc':
                return cls(Jsondoc())
            if x == 'pipfile':
                return cls(Pipfile())
            if x == 'pnpm_lock':
                return cls(PnpmLock())
            if x == 'poetry_lock':
                return cls(PoetryLock())
            if x == 'pyproject_toml':
                return cls(PyprojectToml())
            if x == 'requirements':
                return cls(Requirements())
            if x == 'yarn_1':
                return cls(Yarn1())
            if x == 'yarn_2':
                return cls(Yarn2())
            if x == 'pomtree':
                return cls(Pomtree())
            if x == 'cargo':
                return cls(CargoParser())
            if x == 'composer_lock':
                return cls(ComposerLock())
            _atd_bad_json('ScaParserName', x)
        _atd_bad_json('ScaParserName', x)

    def to_json(self) -> Any:
        return self.value.to_json()

    @classmethod
    def from_json_string(cls, x: str) -> 'ScaParserName':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Npm:
    """Original type: ecosystem = [ ... | Npm | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Npm'

    @staticmethod
    def to_json() -> Any:
        return 'npm'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Pypi:
    """Original type: ecosystem = [ ... | Pypi | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Pypi'

    @staticmethod
    def to_json() -> Any:
        return 'pypi'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Gem:
    """Original type: ecosystem = [ ... | Gem | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Gem'

    @staticmethod
    def to_json() -> Any:
        return 'gem'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Gomod:
    """Original type: ecosystem = [ ... | Gomod | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Gomod'

    @staticmethod
    def to_json() -> Any:
        return 'gomod'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Cargo:
    """Original type: ecosystem = [ ... | Cargo | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Cargo'

    @staticmethod
    def to_json() -> Any:
        return 'cargo'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Maven:
    """Original type: ecosystem = [ ... | Maven | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Maven'

    @staticmethod
    def to_json() -> Any:
        return 'maven'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Composer:
    """Original type: ecosystem = [ ... | Composer | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Composer'

    @staticmethod
    def to_json() -> Any:
        return 'composer'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Nuget:
    """Original type: ecosystem = [ ... | Nuget | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Nuget'

    @staticmethod
    def to_json() -> Any:
        return 'nuget'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Ecosystem:
    """Original type: ecosystem = [ ... ]"""

    value: Union[Npm, Pypi, Gem, Gomod, Cargo, Maven, Composer, Nuget]

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return self.value.kind

    @classmethod
    def from_json(cls, x: Any) -> 'Ecosystem':
        if isinstance(x, str):
            if x == 'npm':
                return cls(Npm())
            if x == 'pypi':
                return cls(Pypi())
            if x == 'gem':
                return cls(Gem())
            if x == 'gomod':
                return cls(Gomod())
            if x == 'cargo':
                return cls(Cargo())
            if x == 'maven':
                return cls(Maven())
            if x == 'composer':
                return cls(Composer())
            if x == 'nuget':
                return cls(Nuget())
            _atd_bad_json('Ecosystem', x)
        _atd_bad_json('Ecosystem', x)

    def to_json(self) -> Any:
        return self.value.to_json()

    @classmethod
    def from_json_string(cls, x: str) -> 'Ecosystem':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class DependencyChild:
    """Original type: dependency_child = { ... }"""

    package: str
    version: str

    @classmethod
    def from_json(cls, x: Any) -> 'DependencyChild':
        if isinstance(x, dict):
            return cls(
                package=_atd_read_string(x['package']) if 'package' in x else _atd_missing_json_field('DependencyChild', 'package'),
                version=_atd_read_string(x['version']) if 'version' in x else _atd_missing_json_field('DependencyChild', 'version'),
            )
        else:
            _atd_bad_json('DependencyChild', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['package'] = _atd_write_string(self.package)
        res['version'] = _atd_write_string(self.version)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'DependencyChild':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class FoundDependency:
    """Original type: found_dependency = { ... }"""

    package: str
    version: str
    ecosystem: Ecosystem
    allowed_hashes: Dict[str, List[str]]
    transitivity: Transitivity
    resolved_url: Optional[str] = None
    line_number: Optional[int] = None
    children: Optional[List[DependencyChild]] = None

    @classmethod
    def from_json(cls, x: Any) -> 'FoundDependency':
        if isinstance(x, dict):
            return cls(
                package=_atd_read_string(x['package']) if 'package' in x else _atd_missing_json_field('FoundDependency', 'package'),
                version=_atd_read_string(x['version']) if 'version' in x else _atd_missing_json_field('FoundDependency', 'version'),
                ecosystem=Ecosystem.from_json(x['ecosystem']) if 'ecosystem' in x else _atd_missing_json_field('FoundDependency', 'ecosystem'),
                allowed_hashes=_atd_read_assoc_object_into_dict(_atd_read_list(_atd_read_string))(x['allowed_hashes']) if 'allowed_hashes' in x else _atd_missing_json_field('FoundDependency', 'allowed_hashes'),
                transitivity=Transitivity.from_json(x['transitivity']) if 'transitivity' in x else _atd_missing_json_field('FoundDependency', 'transitivity'),
                resolved_url=_atd_read_string(x['resolved_url']) if 'resolved_url' in x else None,
                line_number=_atd_read_int(x['line_number']) if 'line_number' in x else None,
                children=_atd_read_list(DependencyChild.from_json)(x['children']) if 'children' in x else None,
            )
        else:
            _atd_bad_json('FoundDependency', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['package'] = _atd_write_string(self.package)
        res['version'] = _atd_write_string(self.version)
        res['ecosystem'] = (lambda x: x.to_json())(self.ecosystem)
        res['allowed_hashes'] = _atd_write_assoc_dict_to_object(_atd_write_list(_atd_write_string))(self.allowed_hashes)
        res['transitivity'] = (lambda x: x.to_json())(self.transitivity)
        if self.resolved_url is not None:
            res['resolved_url'] = _atd_write_string(self.resolved_url)
        if self.line_number is not None:
            res['line_number'] = _atd_write_int(self.line_number)
        if self.children is not None:
            res['children'] = _atd_write_list((lambda x: x.to_json()))(self.children)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'FoundDependency':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class DependencyPattern:
    """Original type: dependency_pattern = { ... }"""

    ecosystem: Ecosystem
    package: str
    semver_range: str

    @classmethod
    def from_json(cls, x: Any) -> 'DependencyPattern':
        if isinstance(x, dict):
            return cls(
                ecosystem=Ecosystem.from_json(x['ecosystem']) if 'ecosystem' in x else _atd_missing_json_field('DependencyPattern', 'ecosystem'),
                package=_atd_read_string(x['package']) if 'package' in x else _atd_missing_json_field('DependencyPattern', 'package'),
                semver_range=_atd_read_string(x['semver_range']) if 'semver_range' in x else _atd_missing_json_field('DependencyPattern', 'semver_range'),
            )
        else:
            _atd_bad_json('DependencyPattern', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['ecosystem'] = (lambda x: x.to_json())(self.ecosystem)
        res['package'] = _atd_write_string(self.package)
        res['semver_range'] = _atd_write_string(self.semver_range)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'DependencyPattern':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class DependencyMatch:
    """Original type: dependency_match = { ... }"""

    dependency_pattern: DependencyPattern
    found_dependency: FoundDependency
    lockfile: str

    @classmethod
    def from_json(cls, x: Any) -> 'DependencyMatch':
        if isinstance(x, dict):
            return cls(
                dependency_pattern=DependencyPattern.from_json(x['dependency_pattern']) if 'dependency_pattern' in x else _atd_missing_json_field('DependencyMatch', 'dependency_pattern'),
                found_dependency=FoundDependency.from_json(x['found_dependency']) if 'found_dependency' in x else _atd_missing_json_field('DependencyMatch', 'found_dependency'),
                lockfile=_atd_read_string(x['lockfile']) if 'lockfile' in x else _atd_missing_json_field('DependencyMatch', 'lockfile'),
            )
        else:
            _atd_bad_json('DependencyMatch', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['dependency_pattern'] = (lambda x: x.to_json())(self.dependency_pattern)
        res['found_dependency'] = (lambda x: x.to_json())(self.found_dependency)
        res['lockfile'] = _atd_write_string(self.lockfile)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'DependencyMatch':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class ScaInfo:
    """Original type: sca_info = { ... }"""

    reachable: bool
    reachability_rule: bool
    sca_finding_schema: int
    dependency_match: DependencyMatch

    @classmethod
    def from_json(cls, x: Any) -> 'ScaInfo':
        if isinstance(x, dict):
            return cls(
                reachable=_atd_read_bool(x['reachable']) if 'reachable' in x else _atd_missing_json_field('ScaInfo', 'reachable'),
                reachability_rule=_atd_read_bool(x['reachability_rule']) if 'reachability_rule' in x else _atd_missing_json_field('ScaInfo', 'reachability_rule'),
                sca_finding_schema=_atd_read_int(x['sca_finding_schema']) if 'sca_finding_schema' in x else _atd_missing_json_field('ScaInfo', 'sca_finding_schema'),
                dependency_match=DependencyMatch.from_json(x['dependency_match']) if 'dependency_match' in x else _atd_missing_json_field('ScaInfo', 'dependency_match'),
            )
        else:
            _atd_bad_json('ScaInfo', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['reachable'] = _atd_write_bool(self.reachable)
        res['reachability_rule'] = _atd_write_bool(self.reachability_rule)
        res['sca_finding_schema'] = _atd_write_int(self.sca_finding_schema)
        res['dependency_match'] = (lambda x: x.to_json())(self.dependency_match)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'ScaInfo':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class RuleIdAndEngineKind:
    """Original type: rule_id_and_engine_kind"""

    value: Tuple[RuleId, EngineKind]

    @classmethod
    def from_json(cls, x: Any) -> 'RuleIdAndEngineKind':
        return cls((lambda x: (RuleId.from_json(x[0]), EngineKind.from_json(x[1])) if isinstance(x, list) and len(x) == 2 else _atd_bad_json('array of length 2', x))(x))

    def to_json(self) -> Any:
        return (lambda x: [(lambda x: x.to_json())(x[0]), (lambda x: x.to_json())(x[1])] if isinstance(x, tuple) and len(x) == 2 else _atd_bad_python('tuple of length 2', x))(self.value)

    @classmethod
    def from_json_string(cls, x: str) -> 'RuleIdAndEngineKind':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class ProjectMetadata:
    """Original type: project_metadata = { ... }"""

    semgrep_version: Version
    repository: str
    repo_url: Optional[str]
    branch: Optional[str]
    ci_job_url: Optional[str]
    commit: Optional[str]
    commit_author_email: Optional[str]
    commit_author_name: Optional[str]
    commit_author_username: Optional[str]
    commit_author_image_url: Optional[str]
    commit_title: Optional[str]
    on: str
    pull_request_author_username: Optional[str]
    pull_request_author_image_url: Optional[str]
    pull_request_id: Optional[str]
    pull_request_title: Optional[str]
    scan_environment: str
    is_full_scan: bool
    commit_timestamp: Optional[str] = None
    base_sha: Optional[str] = None
    start_sha: Optional[str] = None
    is_sca_scan: Optional[bool] = None
    is_code_scan: Optional[bool] = None
    is_secrets_scan: Optional[bool] = None

    @classmethod
    def from_json(cls, x: Any) -> 'ProjectMetadata':
        if isinstance(x, dict):
            return cls(
                semgrep_version=Version.from_json(x['semgrep_version']) if 'semgrep_version' in x else _atd_missing_json_field('ProjectMetadata', 'semgrep_version'),
                repository=_atd_read_string(x['repository']) if 'repository' in x else _atd_missing_json_field('ProjectMetadata', 'repository'),
                repo_url=_atd_read_nullable(_atd_read_string)(x['repo_url']) if 'repo_url' in x else _atd_missing_json_field('ProjectMetadata', 'repo_url'),
                branch=_atd_read_nullable(_atd_read_string)(x['branch']) if 'branch' in x else _atd_missing_json_field('ProjectMetadata', 'branch'),
                ci_job_url=_atd_read_nullable(_atd_read_string)(x['ci_job_url']) if 'ci_job_url' in x else _atd_missing_json_field('ProjectMetadata', 'ci_job_url'),
                commit=_atd_read_nullable(_atd_read_string)(x['commit']) if 'commit' in x else _atd_missing_json_field('ProjectMetadata', 'commit'),
                commit_author_email=_atd_read_nullable(_atd_read_string)(x['commit_author_email']) if 'commit_author_email' in x else _atd_missing_json_field('ProjectMetadata', 'commit_author_email'),
                commit_author_name=_atd_read_nullable(_atd_read_string)(x['commit_author_name']) if 'commit_author_name' in x else _atd_missing_json_field('ProjectMetadata', 'commit_author_name'),
                commit_author_username=_atd_read_nullable(_atd_read_string)(x['commit_author_username']) if 'commit_author_username' in x else _atd_missing_json_field('ProjectMetadata', 'commit_author_username'),
                commit_author_image_url=_atd_read_nullable(_atd_read_string)(x['commit_author_image_url']) if 'commit_author_image_url' in x else _atd_missing_json_field('ProjectMetadata', 'commit_author_image_url'),
                commit_title=_atd_read_nullable(_atd_read_string)(x['commit_title']) if 'commit_title' in x else _atd_missing_json_field('ProjectMetadata', 'commit_title'),
                on=_atd_read_string(x['on']) if 'on' in x else _atd_missing_json_field('ProjectMetadata', 'on'),
                pull_request_author_username=_atd_read_nullable(_atd_read_string)(x['pull_request_author_username']) if 'pull_request_author_username' in x else _atd_missing_json_field('ProjectMetadata', 'pull_request_author_username'),
                pull_request_author_image_url=_atd_read_nullable(_atd_read_string)(x['pull_request_author_image_url']) if 'pull_request_author_image_url' in x else _atd_missing_json_field('ProjectMetadata', 'pull_request_author_image_url'),
                pull_request_id=_atd_read_nullable(_atd_read_string)(x['pull_request_id']) if 'pull_request_id' in x else _atd_missing_json_field('ProjectMetadata', 'pull_request_id'),
                pull_request_title=_atd_read_nullable(_atd_read_string)(x['pull_request_title']) if 'pull_request_title' in x else _atd_missing_json_field('ProjectMetadata', 'pull_request_title'),
                scan_environment=_atd_read_string(x['scan_environment']) if 'scan_environment' in x else _atd_missing_json_field('ProjectMetadata', 'scan_environment'),
                is_full_scan=_atd_read_bool(x['is_full_scan']) if 'is_full_scan' in x else _atd_missing_json_field('ProjectMetadata', 'is_full_scan'),
                commit_timestamp=_atd_read_string(x['commit_timestamp']) if 'commit_timestamp' in x else None,
                base_sha=_atd_read_string(x['base_sha']) if 'base_sha' in x else None,
                start_sha=_atd_read_string(x['start_sha']) if 'start_sha' in x else None,
                is_sca_scan=_atd_read_bool(x['is_sca_scan']) if 'is_sca_scan' in x else None,
                is_code_scan=_atd_read_bool(x['is_code_scan']) if 'is_code_scan' in x else None,
                is_secrets_scan=_atd_read_bool(x['is_secrets_scan']) if 'is_secrets_scan' in x else None,
            )
        else:
            _atd_bad_json('ProjectMetadata', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['semgrep_version'] = (lambda x: x.to_json())(self.semgrep_version)
        res['repository'] = _atd_write_string(self.repository)
        res['repo_url'] = _atd_write_nullable(_atd_write_string)(self.repo_url)
        res['branch'] = _atd_write_nullable(_atd_write_string)(self.branch)
        res['ci_job_url'] = _atd_write_nullable(_atd_write_string)(self.ci_job_url)
        res['commit'] = _atd_write_nullable(_atd_write_string)(self.commit)
        res['commit_author_email'] = _atd_write_nullable(_atd_write_string)(self.commit_author_email)
        res['commit_author_name'] = _atd_write_nullable(_atd_write_string)(self.commit_author_name)
        res['commit_author_username'] = _atd_write_nullable(_atd_write_string)(self.commit_author_username)
        res['commit_author_image_url'] = _atd_write_nullable(_atd_write_string)(self.commit_author_image_url)
        res['commit_title'] = _atd_write_nullable(_atd_write_string)(self.commit_title)
        res['on'] = _atd_write_string(self.on)
        res['pull_request_author_username'] = _atd_write_nullable(_atd_write_string)(self.pull_request_author_username)
        res['pull_request_author_image_url'] = _atd_write_nullable(_atd_write_string)(self.pull_request_author_image_url)
        res['pull_request_id'] = _atd_write_nullable(_atd_write_string)(self.pull_request_id)
        res['pull_request_title'] = _atd_write_nullable(_atd_write_string)(self.pull_request_title)
        res['scan_environment'] = _atd_write_string(self.scan_environment)
        res['is_full_scan'] = _atd_write_bool(self.is_full_scan)
        if self.commit_timestamp is not None:
            res['commit_timestamp'] = _atd_write_string(self.commit_timestamp)
        if self.base_sha is not None:
            res['base_sha'] = _atd_write_string(self.base_sha)
        if self.start_sha is not None:
            res['start_sha'] = _atd_write_string(self.start_sha)
        if self.is_sca_scan is not None:
            res['is_sca_scan'] = _atd_write_bool(self.is_sca_scan)
        if self.is_code_scan is not None:
            res['is_code_scan'] = _atd_write_bool(self.is_code_scan)
        if self.is_secrets_scan is not None:
            res['is_secrets_scan'] = _atd_write_bool(self.is_secrets_scan)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'ProjectMetadata':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Profile:
    """Original type: profile = { ... }"""

    rules: List[RuleId]
    rules_parse_time: float
    profiling_times: Dict[str, float]
    targets: List[TargetTimes]
    total_bytes: int
    max_memory_bytes: Optional[int] = None

    @classmethod
    def from_json(cls, x: Any) -> 'Profile':
        if isinstance(x, dict):
            return cls(
                rules=_atd_read_list(RuleId.from_json)(x['rules']) if 'rules' in x else _atd_missing_json_field('Profile', 'rules'),
                rules_parse_time=_atd_read_float(x['rules_parse_time']) if 'rules_parse_time' in x else _atd_missing_json_field('Profile', 'rules_parse_time'),
                profiling_times=_atd_read_assoc_object_into_dict(_atd_read_float)(x['profiling_times']) if 'profiling_times' in x else _atd_missing_json_field('Profile', 'profiling_times'),
                targets=_atd_read_list(TargetTimes.from_json)(x['targets']) if 'targets' in x else _atd_missing_json_field('Profile', 'targets'),
                total_bytes=_atd_read_int(x['total_bytes']) if 'total_bytes' in x else _atd_missing_json_field('Profile', 'total_bytes'),
                max_memory_bytes=_atd_read_int(x['max_memory_bytes']) if 'max_memory_bytes' in x else None,
            )
        else:
            _atd_bad_json('Profile', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['rules'] = _atd_write_list((lambda x: x.to_json()))(self.rules)
        res['rules_parse_time'] = _atd_write_float(self.rules_parse_time)
        res['profiling_times'] = _atd_write_assoc_dict_to_object(_atd_write_float)(self.profiling_times)
        res['targets'] = _atd_write_list((lambda x: x.to_json()))(self.targets)
        res['total_bytes'] = _atd_write_int(self.total_bytes)
        if self.max_memory_bytes is not None:
            res['max_memory_bytes'] = _atd_write_int(self.max_memory_bytes)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'Profile':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class SAST:
    """Original type: product = [ ... | SAST | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'SAST'

    @staticmethod
    def to_json() -> Any:
        return 'sast'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class SCA:
    """Original type: product = [ ... | SCA | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'SCA'

    @staticmethod
    def to_json() -> Any:
        return 'sca'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Secrets:
    """Original type: product = [ ... | Secrets | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Secrets'

    @staticmethod
    def to_json() -> Any:
        return 'secrets'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Product:
    """Original type: product = [ ... ]"""

    value: Union[SAST, SCA, Secrets]

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return self.value.kind

    @classmethod
    def from_json(cls, x: Any) -> 'Product':
        if isinstance(x, str):
            if x == 'sast':
                return cls(SAST())
            if x == 'sca':
                return cls(SCA())
            if x == 'secrets':
                return cls(Secrets())
            _atd_bad_json('Product', x)
        _atd_bad_json('Product', x)

    def to_json(self) -> Any:
        return self.value.to_json()

    @classmethod
    def from_json_string(cls, x: str) -> 'Product':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class ParsingStats:
    """Original type: parsing_stats = { ... }"""

    targets_parsed: int
    num_targets: int
    bytes_parsed: int
    num_bytes: int

    @classmethod
    def from_json(cls, x: Any) -> 'ParsingStats':
        if isinstance(x, dict):
            return cls(
                targets_parsed=_atd_read_int(x['targets_parsed']) if 'targets_parsed' in x else _atd_missing_json_field('ParsingStats', 'targets_parsed'),
                num_targets=_atd_read_int(x['num_targets']) if 'num_targets' in x else _atd_missing_json_field('ParsingStats', 'num_targets'),
                bytes_parsed=_atd_read_int(x['bytes_parsed']) if 'bytes_parsed' in x else _atd_missing_json_field('ParsingStats', 'bytes_parsed'),
                num_bytes=_atd_read_int(x['num_bytes']) if 'num_bytes' in x else _atd_missing_json_field('ParsingStats', 'num_bytes'),
            )
        else:
            _atd_bad_json('ParsingStats', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['targets_parsed'] = _atd_write_int(self.targets_parsed)
        res['num_targets'] = _atd_write_int(self.num_targets)
        res['bytes_parsed'] = _atd_write_int(self.bytes_parsed)
        res['num_bytes'] = _atd_write_int(self.num_bytes)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'ParsingStats':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Meta:
    """Original type: meta = { ... }"""

    meta: ProjectMetadata

    @classmethod
    def from_json(cls, x: Any) -> 'Meta':
        if isinstance(x, dict):
            return cls(
                meta=ProjectMetadata.from_json(x['meta']) if 'meta' in x else _atd_missing_json_field('Meta', 'meta'),
            )
        else:
            _atd_bad_json('Meta', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['meta'] = (lambda x: x.to_json())(self.meta)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'Meta':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class IncompatibleRule:
    """Original type: incompatible_rule = { ... }"""

    rule_id: RuleId
    this_version: Version
    min_version: Optional[Version] = None
    max_version: Optional[Version] = None

    @classmethod
    def from_json(cls, x: Any) -> 'IncompatibleRule':
        if isinstance(x, dict):
            return cls(
                rule_id=RuleId.from_json(x['rule_id']) if 'rule_id' in x else _atd_missing_json_field('IncompatibleRule', 'rule_id'),
                this_version=Version.from_json(x['this_version']) if 'this_version' in x else _atd_missing_json_field('IncompatibleRule', 'this_version'),
                min_version=Version.from_json(x['min_version']) if 'min_version' in x else None,
                max_version=Version.from_json(x['max_version']) if 'max_version' in x else None,
            )
        else:
            _atd_bad_json('IncompatibleRule', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['rule_id'] = (lambda x: x.to_json())(self.rule_id)
        res['this_version'] = (lambda x: x.to_json())(self.this_version)
        if self.min_version is not None:
            res['min_version'] = (lambda x: x.to_json())(self.min_version)
        if self.max_version is not None:
            res['max_version'] = (lambda x: x.to_json())(self.max_version)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'IncompatibleRule':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class FixRegex:
    """Original type: fix_regex = { ... }"""

    regex: str
    replacement: str
    count: Optional[int] = None

    @classmethod
    def from_json(cls, x: Any) -> 'FixRegex':
        if isinstance(x, dict):
            return cls(
                regex=_atd_read_string(x['regex']) if 'regex' in x else _atd_missing_json_field('FixRegex', 'regex'),
                replacement=_atd_read_string(x['replacement']) if 'replacement' in x else _atd_missing_json_field('FixRegex', 'replacement'),
                count=_atd_read_int(x['count']) if 'count' in x else None,
            )
        else:
            _atd_bad_json('FixRegex', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['regex'] = _atd_write_string(self.regex)
        res['replacement'] = _atd_write_string(self.replacement)
        if self.count is not None:
            res['count'] = _atd_write_int(self.count)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'FixRegex':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class FindingHashes:
    """Original type: finding_hashes = { ... }"""

    start_line_hash: str
    end_line_hash: str
    code_hash: str
    pattern_hash: str

    @classmethod
    def from_json(cls, x: Any) -> 'FindingHashes':
        if isinstance(x, dict):
            return cls(
                start_line_hash=_atd_read_string(x['start_line_hash']) if 'start_line_hash' in x else _atd_missing_json_field('FindingHashes', 'start_line_hash'),
                end_line_hash=_atd_read_string(x['end_line_hash']) if 'end_line_hash' in x else _atd_missing_json_field('FindingHashes', 'end_line_hash'),
                code_hash=_atd_read_string(x['code_hash']) if 'code_hash' in x else _atd_missing_json_field('FindingHashes', 'code_hash'),
                pattern_hash=_atd_read_string(x['pattern_hash']) if 'pattern_hash' in x else _atd_missing_json_field('FindingHashes', 'pattern_hash'),
            )
        else:
            _atd_bad_json('FindingHashes', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['start_line_hash'] = _atd_write_string(self.start_line_hash)
        res['end_line_hash'] = _atd_write_string(self.end_line_hash)
        res['code_hash'] = _atd_write_string(self.code_hash)
        res['pattern_hash'] = _atd_write_string(self.pattern_hash)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'FindingHashes':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Finding:
    """Original type: finding = { ... }"""

    check_id: RuleId
    path: Fpath
    line: int
    column: int
    end_line: int
    end_column: int
    message: str
    severity: Any
    index: int
    commit_date: str
    syntactic_id: str
    metadata: RawJson
    is_blocking: bool
    match_based_id: Optional[str] = None
    hashes: Optional[FindingHashes] = None
    fixed_lines: Optional[List[str]] = None
    sca_info: Optional[ScaInfo] = None
    dataflow_trace: Optional[MatchDataflowTrace] = None
    validation_state: Optional[ValidationState] = None

    @classmethod
    def from_json(cls, x: Any) -> 'Finding':
        if isinstance(x, dict):
            return cls(
                check_id=RuleId.from_json(x['check_id']) if 'check_id' in x else _atd_missing_json_field('Finding', 'check_id'),
                path=Fpath.from_json(x['path']) if 'path' in x else _atd_missing_json_field('Finding', 'path'),
                line=_atd_read_int(x['line']) if 'line' in x else _atd_missing_json_field('Finding', 'line'),
                column=_atd_read_int(x['column']) if 'column' in x else _atd_missing_json_field('Finding', 'column'),
                end_line=_atd_read_int(x['end_line']) if 'end_line' in x else _atd_missing_json_field('Finding', 'end_line'),
                end_column=_atd_read_int(x['end_column']) if 'end_column' in x else _atd_missing_json_field('Finding', 'end_column'),
                message=_atd_read_string(x['message']) if 'message' in x else _atd_missing_json_field('Finding', 'message'),
                severity=(lambda x: x)(x['severity']) if 'severity' in x else _atd_missing_json_field('Finding', 'severity'),
                index=_atd_read_int(x['index']) if 'index' in x else _atd_missing_json_field('Finding', 'index'),
                commit_date=_atd_read_string(x['commit_date']) if 'commit_date' in x else _atd_missing_json_field('Finding', 'commit_date'),
                syntactic_id=_atd_read_string(x['syntactic_id']) if 'syntactic_id' in x else _atd_missing_json_field('Finding', 'syntactic_id'),
                metadata=RawJson.from_json(x['metadata']) if 'metadata' in x else _atd_missing_json_field('Finding', 'metadata'),
                is_blocking=_atd_read_bool(x['is_blocking']) if 'is_blocking' in x else _atd_missing_json_field('Finding', 'is_blocking'),
                match_based_id=_atd_read_string(x['match_based_id']) if 'match_based_id' in x else None,
                hashes=FindingHashes.from_json(x['hashes']) if 'hashes' in x else None,
                fixed_lines=_atd_read_list(_atd_read_string)(x['fixed_lines']) if 'fixed_lines' in x else None,
                sca_info=ScaInfo.from_json(x['sca_info']) if 'sca_info' in x else None,
                dataflow_trace=MatchDataflowTrace.from_json(x['dataflow_trace']) if 'dataflow_trace' in x else None,
                validation_state=ValidationState.from_json(x['validation_state']) if 'validation_state' in x else None,
            )
        else:
            _atd_bad_json('Finding', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['check_id'] = (lambda x: x.to_json())(self.check_id)
        res['path'] = (lambda x: x.to_json())(self.path)
        res['line'] = _atd_write_int(self.line)
        res['column'] = _atd_write_int(self.column)
        res['end_line'] = _atd_write_int(self.end_line)
        res['end_column'] = _atd_write_int(self.end_column)
        res['message'] = _atd_write_string(self.message)
        res['severity'] = (lambda x: x)(self.severity)
        res['index'] = _atd_write_int(self.index)
        res['commit_date'] = _atd_write_string(self.commit_date)
        res['syntactic_id'] = _atd_write_string(self.syntactic_id)
        res['metadata'] = (lambda x: x.to_json())(self.metadata)
        res['is_blocking'] = _atd_write_bool(self.is_blocking)
        if self.match_based_id is not None:
            res['match_based_id'] = _atd_write_string(self.match_based_id)
        if self.hashes is not None:
            res['hashes'] = (lambda x: x.to_json())(self.hashes)
        if self.fixed_lines is not None:
            res['fixed_lines'] = _atd_write_list(_atd_write_string)(self.fixed_lines)
        if self.sca_info is not None:
            res['sca_info'] = (lambda x: x.to_json())(self.sca_info)
        if self.dataflow_trace is not None:
            res['dataflow_trace'] = (lambda x: x.to_json())(self.dataflow_trace)
        if self.validation_state is not None:
            res['validation_state'] = (lambda x: x.to_json())(self.validation_state)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'Finding':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class ErrorSpan:
    """Original type: error_span = { ... }"""

    file: Fpath
    start: Position
    end: Position
    source_hash: Optional[str] = None
    config_start: Optional[Optional[Position]] = None
    config_end: Optional[Optional[Position]] = None
    config_path: Optional[Optional[List[str]]] = None
    context_start: Optional[Optional[Position]] = None
    context_end: Optional[Optional[Position]] = None

    @classmethod
    def from_json(cls, x: Any) -> 'ErrorSpan':
        if isinstance(x, dict):
            return cls(
                file=Fpath.from_json(x['file']) if 'file' in x else _atd_missing_json_field('ErrorSpan', 'file'),
                start=Position.from_json(x['start']) if 'start' in x else _atd_missing_json_field('ErrorSpan', 'start'),
                end=Position.from_json(x['end']) if 'end' in x else _atd_missing_json_field('ErrorSpan', 'end'),
                source_hash=_atd_read_string(x['source_hash']) if 'source_hash' in x else None,
                config_start=_atd_read_nullable(Position.from_json)(x['config_start']) if 'config_start' in x else None,
                config_end=_atd_read_nullable(Position.from_json)(x['config_end']) if 'config_end' in x else None,
                config_path=_atd_read_nullable(_atd_read_list(_atd_read_string))(x['config_path']) if 'config_path' in x else None,
                context_start=_atd_read_nullable(Position.from_json)(x['context_start']) if 'context_start' in x else None,
                context_end=_atd_read_nullable(Position.from_json)(x['context_end']) if 'context_end' in x else None,
            )
        else:
            _atd_bad_json('ErrorSpan', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['file'] = (lambda x: x.to_json())(self.file)
        res['start'] = (lambda x: x.to_json())(self.start)
        res['end'] = (lambda x: x.to_json())(self.end)
        if self.source_hash is not None:
            res['source_hash'] = _atd_write_string(self.source_hash)
        if self.config_start is not None:
            res['config_start'] = _atd_write_nullable((lambda x: x.to_json()))(self.config_start)
        if self.config_end is not None:
            res['config_end'] = _atd_write_nullable((lambda x: x.to_json()))(self.config_end)
        if self.config_path is not None:
            res['config_path'] = _atd_write_nullable(_atd_write_list(_atd_write_string))(self.config_path)
        if self.context_start is not None:
            res['context_start'] = _atd_write_nullable((lambda x: x.to_json()))(self.context_start)
        if self.context_end is not None:
            res['context_end'] = _atd_write_nullable((lambda x: x.to_json()))(self.context_end)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'ErrorSpan':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class DependencyParserError:
    """Original type: dependency_parser_error = { ... }"""

    path: str
    parser: ScaParserName
    reason: str
    line: Optional[int] = None
    col: Optional[int] = None
    text: Optional[str] = None

    @classmethod
    def from_json(cls, x: Any) -> 'DependencyParserError':
        if isinstance(x, dict):
            return cls(
                path=_atd_read_string(x['path']) if 'path' in x else _atd_missing_json_field('DependencyParserError', 'path'),
                parser=ScaParserName.from_json(x['parser']) if 'parser' in x else _atd_missing_json_field('DependencyParserError', 'parser'),
                reason=_atd_read_string(x['reason']) if 'reason' in x else _atd_missing_json_field('DependencyParserError', 'reason'),
                line=_atd_read_int(x['line']) if 'line' in x else None,
                col=_atd_read_int(x['col']) if 'col' in x else None,
                text=_atd_read_string(x['text']) if 'text' in x else None,
            )
        else:
            _atd_bad_json('DependencyParserError', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['path'] = _atd_write_string(self.path)
        res['parser'] = (lambda x: x.to_json())(self.parser)
        res['reason'] = _atd_write_string(self.reason)
        if self.line is not None:
            res['line'] = _atd_write_int(self.line)
        if self.col is not None:
            res['col'] = _atd_write_int(self.col)
        if self.text is not None:
            res['text'] = _atd_write_string(self.text)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'DependencyParserError':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Datetime:
    """Original type: datetime"""

    value: str

    @classmethod
    def from_json(cls, x: Any) -> 'Datetime':
        return cls(_atd_read_string(x))

    def to_json(self) -> Any:
        return _atd_write_string(self.value)

    @classmethod
    def from_json_string(cls, x: str) -> 'Datetime':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Error:
    """Original type: core_severity = [ ... | Error | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Error'

    @staticmethod
    def to_json() -> Any:
        return 'error'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Warning:
    """Original type: core_severity = [ ... | Warning | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Warning'

    @staticmethod
    def to_json() -> Any:
        return 'warning'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class Info:
    """Original type: core_severity = [ ... | Info | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Info'

    @staticmethod
    def to_json() -> Any:
        return 'info'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class CoreSeverity:
    """Original type: core_severity = [ ... ]"""

    value: Union[Error, Warning, Info]

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return self.value.kind

    @classmethod
    def from_json(cls, x: Any) -> 'CoreSeverity':
        if isinstance(x, str):
            if x == 'error':
                return cls(Error())
            if x == 'warning':
                return cls(Warning())
            if x == 'info':
                return cls(Info())
            _atd_bad_json('CoreSeverity', x)
        _atd_bad_json('CoreSeverity', x)

    def to_json(self) -> Any:
        return self.value.to_json()

    @classmethod
    def from_json_string(cls, x: str) -> 'CoreSeverity':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class LexicalError:
    """Original type: core_error_kind = [ ... | LexicalError | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'LexicalError'

    @staticmethod
    def to_json() -> Any:
        return 'Lexical error'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class ParseError:
    """Original type: core_error_kind = [ ... | ParseError | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'ParseError'

    @staticmethod
    def to_json() -> Any:
        return 'Syntax error'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class SpecifiedParseError:
    """Original type: core_error_kind = [ ... | SpecifiedParseError | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'SpecifiedParseError'

    @staticmethod
    def to_json() -> Any:
        return 'Other syntax error'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class AstBuilderError:
    """Original type: core_error_kind = [ ... | AstBuilderError | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'AstBuilderError'

    @staticmethod
    def to_json() -> Any:
        return 'AST builder error'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class RuleParseError:
    """Original type: core_error_kind = [ ... | RuleParseError | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'RuleParseError'

    @staticmethod
    def to_json() -> Any:
        return 'Rule parse error'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class PatternParseError:
    """Original type: core_error_kind = [ ... | PatternParseError of ... | ... ]"""

    value: List[str]

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'PatternParseError'

    def to_json(self) -> Any:
        return ['Pattern parse error', _atd_write_list(_atd_write_string)(self.value)]

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class InvalidYaml:
    """Original type: core_error_kind = [ ... | InvalidYaml | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'InvalidYaml'

    @staticmethod
    def to_json() -> Any:
        return 'Invalid YAML'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class MatchingError:
    """Original type: core_error_kind = [ ... | MatchingError | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'MatchingError'

    @staticmethod
    def to_json() -> Any:
        return 'Internal matching error'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class SemgrepMatchFound:
    """Original type: core_error_kind = [ ... | SemgrepMatchFound | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'SemgrepMatchFound'

    @staticmethod
    def to_json() -> Any:
        return 'Semgrep match found'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class TooManyMatches_:
    """Original type: core_error_kind = [ ... | TooManyMatches | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'TooManyMatches_'

    @staticmethod
    def to_json() -> Any:
        return 'Too many matches'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class FatalError:
    """Original type: core_error_kind = [ ... | FatalError | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'FatalError'

    @staticmethod
    def to_json() -> Any:
        return 'Fatal error'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class Timeout:
    """Original type: core_error_kind = [ ... | Timeout | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'Timeout'

    @staticmethod
    def to_json() -> Any:
        return 'Timeout'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class OutOfMemory:
    """Original type: core_error_kind = [ ... | OutOfMemory | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'OutOfMemory'

    @staticmethod
    def to_json() -> Any:
        return 'Out of memory'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class TimeoutDuringInterfile:
    """Original type: core_error_kind = [ ... | TimeoutDuringInterfile | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'TimeoutDuringInterfile'

    @staticmethod
    def to_json() -> Any:
        return 'Timeout during interfile analysis'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class OutOfMemoryDuringInterfile:
    """Original type: core_error_kind = [ ... | OutOfMemoryDuringInterfile | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'OutOfMemoryDuringInterfile'

    @staticmethod
    def to_json() -> Any:
        return 'OOM during interfile analysis'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class PartialParsing:
    """Original type: core_error_kind = [ ... | PartialParsing of ... | ... ]"""

    value: List[Location]

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'PartialParsing'

    def to_json(self) -> Any:
        return ['PartialParsing', _atd_write_list((lambda x: x.to_json()))(self.value)]

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class IncompatibleRule_:
    """Original type: core_error_kind = [ ... | IncompatibleRule of ... | ... ]"""

    value: IncompatibleRule

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'IncompatibleRule_'

    def to_json(self) -> Any:
        return ['IncompatibleRule', (lambda x: x.to_json())(self.value)]

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class MissingPlugin:
    """Original type: core_error_kind = [ ... | MissingPlugin | ... ]"""

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return 'MissingPlugin'

    @staticmethod
    def to_json() -> Any:
        return 'MissingPlugin'

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True, order=True)
class CoreErrorKind:
    """Original type: core_error_kind = [ ... ]"""

    value: Union[LexicalError, ParseError, SpecifiedParseError, AstBuilderError, RuleParseError, PatternParseError, InvalidYaml, MatchingError, SemgrepMatchFound, TooManyMatches_, FatalError, Timeout, OutOfMemory, TimeoutDuringInterfile, OutOfMemoryDuringInterfile, PartialParsing, IncompatibleRule_, MissingPlugin]

    @property
    def kind(self) -> str:
        """Name of the class representing this variant."""
        return self.value.kind

    @classmethod
    def from_json(cls, x: Any) -> 'CoreErrorKind':
        if isinstance(x, str):
            if x == 'Lexical error':
                return cls(LexicalError())
            if x == 'Syntax error':
                return cls(ParseError())
            if x == 'Other syntax error':
                return cls(SpecifiedParseError())
            if x == 'AST builder error':
                return cls(AstBuilderError())
            if x == 'Rule parse error':
                return cls(RuleParseError())
            if x == 'Invalid YAML':
                return cls(InvalidYaml())
            if x == 'Internal matching error':
                return cls(MatchingError())
            if x == 'Semgrep match found':
                return cls(SemgrepMatchFound())
            if x == 'Too many matches':
                return cls(TooManyMatches_())
            if x == 'Fatal error':
                return cls(FatalError())
            if x == 'Timeout':
                return cls(Timeout())
            if x == 'Out of memory':
                return cls(OutOfMemory())
            if x == 'Timeout during interfile analysis':
                return cls(TimeoutDuringInterfile())
            if x == 'OOM during interfile analysis':
                return cls(OutOfMemoryDuringInterfile())
            if x == 'MissingPlugin':
                return cls(MissingPlugin())
            _atd_bad_json('CoreErrorKind', x)
        if isinstance(x, List) and len(x) == 2:
            cons = x[0]
            if cons == 'Pattern parse error':
                return cls(PatternParseError(_atd_read_list(_atd_read_string)(x[1])))
            if cons == 'PartialParsing':
                return cls(PartialParsing(_atd_read_list(Location.from_json)(x[1])))
            if cons == 'IncompatibleRule':
                return cls(IncompatibleRule_(IncompatibleRule.from_json(x[1])))
            _atd_bad_json('CoreErrorKind', x)
        _atd_bad_json('CoreErrorKind', x)

    def to_json(self) -> Any:
        return self.value.to_json()

    @classmethod
    def from_json_string(cls, x: str) -> 'CoreErrorKind':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass(frozen=True)
class CoreError:
    """Original type: core_error = { ... }"""

    error_type: CoreErrorKind
    severity: CoreSeverity
    location: Location
    message: str
    rule_id: Optional[RuleId] = None
    details: Optional[str] = None

    @classmethod
    def from_json(cls, x: Any) -> 'CoreError':
        if isinstance(x, dict):
            return cls(
                error_type=CoreErrorKind.from_json(x['error_type']) if 'error_type' in x else _atd_missing_json_field('CoreError', 'error_type'),
                severity=CoreSeverity.from_json(x['severity']) if 'severity' in x else _atd_missing_json_field('CoreError', 'severity'),
                location=Location.from_json(x['location']) if 'location' in x else _atd_missing_json_field('CoreError', 'location'),
                message=_atd_read_string(x['message']) if 'message' in x else _atd_missing_json_field('CoreError', 'message'),
                rule_id=RuleId.from_json(x['rule_id']) if 'rule_id' in x else None,
                details=_atd_read_string(x['details']) if 'details' in x else None,
            )
        else:
            _atd_bad_json('CoreError', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['error_type'] = (lambda x: x.to_json())(self.error_type)
        res['severity'] = (lambda x: x.to_json())(self.severity)
        res['location'] = (lambda x: x.to_json())(self.location)
        res['message'] = _atd_write_string(self.message)
        if self.rule_id is not None:
            res['rule_id'] = (lambda x: x.to_json())(self.rule_id)
        if self.details is not None:
            res['details'] = _atd_write_string(self.details)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'CoreError':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class CoreOutput:
    """Original type: core_output = { ... }"""

    results: List[CoreMatch]
    errors: List[CoreError]
    paths: ScannedAndSkipped
    version: Optional[Version] = None
    time: Optional[Profile] = None
    explanations: Optional[List[MatchingExplanation]] = None
    rules_by_engine: Optional[List[RuleIdAndEngineKind]] = None
    engine_requested: Optional[EngineKind] = None
    skipped_rules: List[SkippedRule] = field(default_factory=lambda: [])

    @classmethod
    def from_json(cls, x: Any) -> 'CoreOutput':
        if isinstance(x, dict):
            return cls(
                results=_atd_read_list(CoreMatch.from_json)(x['results']) if 'results' in x else _atd_missing_json_field('CoreOutput', 'results'),
                errors=_atd_read_list(CoreError.from_json)(x['errors']) if 'errors' in x else _atd_missing_json_field('CoreOutput', 'errors'),
                paths=ScannedAndSkipped.from_json(x['paths']) if 'paths' in x else _atd_missing_json_field('CoreOutput', 'paths'),
                version=Version.from_json(x['version']) if 'version' in x else None,
                time=Profile.from_json(x['time']) if 'time' in x else None,
                explanations=_atd_read_list(MatchingExplanation.from_json)(x['explanations']) if 'explanations' in x else None,
                rules_by_engine=_atd_read_list(RuleIdAndEngineKind.from_json)(x['rules_by_engine']) if 'rules_by_engine' in x else None,
                engine_requested=EngineKind.from_json(x['engine_requested']) if 'engine_requested' in x else None,
                skipped_rules=_atd_read_list(SkippedRule.from_json)(x['skipped_rules']) if 'skipped_rules' in x else [],
            )
        else:
            _atd_bad_json('CoreOutput', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['results'] = _atd_write_list((lambda x: x.to_json()))(self.results)
        res['errors'] = _atd_write_list((lambda x: x.to_json()))(self.errors)
        res['paths'] = (lambda x: x.to_json())(self.paths)
        if self.version is not None:
            res['version'] = (lambda x: x.to_json())(self.version)
        if self.time is not None:
            res['time'] = (lambda x: x.to_json())(self.time)
        if self.explanations is not None:
            res['explanations'] = _atd_write_list((lambda x: x.to_json()))(self.explanations)
        if self.rules_by_engine is not None:
            res['rules_by_engine'] = _atd_write_list((lambda x: x.to_json()))(self.rules_by_engine)
        if self.engine_requested is not None:
            res['engine_requested'] = (lambda x: x.to_json())(self.engine_requested)
        res['skipped_rules'] = _atd_write_list((lambda x: x.to_json()))(self.skipped_rules)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'CoreOutput':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Contributor:
    """Original type: contributor = { ... }"""

    commit_author_name: str
    commit_author_email: str

    @classmethod
    def from_json(cls, x: Any) -> 'Contributor':
        if isinstance(x, dict):
            return cls(
                commit_author_name=_atd_read_string(x['commit_author_name']) if 'commit_author_name' in x else _atd_missing_json_field('Contributor', 'commit_author_name'),
                commit_author_email=_atd_read_string(x['commit_author_email']) if 'commit_author_email' in x else _atd_missing_json_field('Contributor', 'commit_author_email'),
            )
        else:
            _atd_bad_json('Contributor', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['commit_author_name'] = _atd_write_string(self.commit_author_name)
        res['commit_author_email'] = _atd_write_string(self.commit_author_email)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'Contributor':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Contribution:
    """Original type: contribution = { ... }"""

    commit_hash: str
    commit_timestamp: str
    contributor: Contributor

    @classmethod
    def from_json(cls, x: Any) -> 'Contribution':
        if isinstance(x, dict):
            return cls(
                commit_hash=_atd_read_string(x['commit_hash']) if 'commit_hash' in x else _atd_missing_json_field('Contribution', 'commit_hash'),
                commit_timestamp=_atd_read_string(x['commit_timestamp']) if 'commit_timestamp' in x else _atd_missing_json_field('Contribution', 'commit_timestamp'),
                contributor=Contributor.from_json(x['contributor']) if 'contributor' in x else _atd_missing_json_field('Contribution', 'contributor'),
            )
        else:
            _atd_bad_json('Contribution', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['commit_hash'] = _atd_write_string(self.commit_hash)
        res['commit_timestamp'] = _atd_write_string(self.commit_timestamp)
        res['contributor'] = (lambda x: x.to_json())(self.contributor)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'Contribution':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class Contributions:
    """Original type: contributions"""

    value: List[Contribution]

    @classmethod
    def from_json(cls, x: Any) -> 'Contributions':
        return cls(_atd_read_list(Contribution.from_json)(x))

    def to_json(self) -> Any:
        return _atd_write_list((lambda x: x.to_json()))(self.value)

    @classmethod
    def from_json_string(cls, x: str) -> 'Contributions':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class CliOutputExtra:
    """Original type: cli_output_extra = { ... }"""

    paths: ScannedAndSkipped
    time: Optional[Profile] = None
    explanations: Optional[List[MatchingExplanation]] = None
    rules_by_engine: Optional[List[RuleIdAndEngineKind]] = None
    engine_requested: Optional[EngineKind] = None
    skipped_rules: List[SkippedRule] = field(default_factory=lambda: [])

    @classmethod
    def from_json(cls, x: Any) -> 'CliOutputExtra':
        if isinstance(x, dict):
            return cls(
                paths=ScannedAndSkipped.from_json(x['paths']) if 'paths' in x else _atd_missing_json_field('CliOutputExtra', 'paths'),
                time=Profile.from_json(x['time']) if 'time' in x else None,
                explanations=_atd_read_list(MatchingExplanation.from_json)(x['explanations']) if 'explanations' in x else None,
                rules_by_engine=_atd_read_list(RuleIdAndEngineKind.from_json)(x['rules_by_engine']) if 'rules_by_engine' in x else None,
                engine_requested=EngineKind.from_json(x['engine_requested']) if 'engine_requested' in x else None,
                skipped_rules=_atd_read_list(SkippedRule.from_json)(x['skipped_rules']) if 'skipped_rules' in x else [],
            )
        else:
            _atd_bad_json('CliOutputExtra', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['paths'] = (lambda x: x.to_json())(self.paths)
        if self.time is not None:
            res['time'] = (lambda x: x.to_json())(self.time)
        if self.explanations is not None:
            res['explanations'] = _atd_write_list((lambda x: x.to_json()))(self.explanations)
        if self.rules_by_engine is not None:
            res['rules_by_engine'] = _atd_write_list((lambda x: x.to_json()))(self.rules_by_engine)
        if self.engine_requested is not None:
            res['engine_requested'] = (lambda x: x.to_json())(self.engine_requested)
        res['skipped_rules'] = _atd_write_list((lambda x: x.to_json()))(self.skipped_rules)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'CliOutputExtra':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class CliMatchExtra:
    """Original type: cli_match_extra = { ... }"""

    fingerprint: str
    lines: str
    message: str
    metadata: RawJson
    severity: str
    metavars: Optional[Metavars] = None
    fix: Optional[str] = None
    fix_regex: Optional[FixRegex] = None
    is_ignored: Optional[bool] = None
    sca_info: Optional[ScaInfo] = None
    fixed_lines: Optional[List[str]] = None
    dataflow_trace: Optional[MatchDataflowTrace] = None
    engine_kind: Optional[EngineKind] = None
    validation_state: Optional[ValidationState] = None
    extra_extra: Optional[RawJson] = None

    @classmethod
    def from_json(cls, x: Any) -> 'CliMatchExtra':
        if isinstance(x, dict):
            return cls(
                fingerprint=_atd_read_string(x['fingerprint']) if 'fingerprint' in x else _atd_missing_json_field('CliMatchExtra', 'fingerprint'),
                lines=_atd_read_string(x['lines']) if 'lines' in x else _atd_missing_json_field('CliMatchExtra', 'lines'),
                message=_atd_read_string(x['message']) if 'message' in x else _atd_missing_json_field('CliMatchExtra', 'message'),
                metadata=RawJson.from_json(x['metadata']) if 'metadata' in x else _atd_missing_json_field('CliMatchExtra', 'metadata'),
                severity=_atd_read_string(x['severity']) if 'severity' in x else _atd_missing_json_field('CliMatchExtra', 'severity'),
                metavars=Metavars.from_json(x['metavars']) if 'metavars' in x else None,
                fix=_atd_read_string(x['fix']) if 'fix' in x else None,
                fix_regex=FixRegex.from_json(x['fix_regex']) if 'fix_regex' in x else None,
                is_ignored=_atd_read_bool(x['is_ignored']) if 'is_ignored' in x else None,
                sca_info=ScaInfo.from_json(x['sca_info']) if 'sca_info' in x else None,
                fixed_lines=_atd_read_list(_atd_read_string)(x['fixed_lines']) if 'fixed_lines' in x else None,
                dataflow_trace=MatchDataflowTrace.from_json(x['dataflow_trace']) if 'dataflow_trace' in x else None,
                engine_kind=EngineKind.from_json(x['engine_kind']) if 'engine_kind' in x else None,
                validation_state=ValidationState.from_json(x['validation_state']) if 'validation_state' in x else None,
                extra_extra=RawJson.from_json(x['extra_extra']) if 'extra_extra' in x else None,
            )
        else:
            _atd_bad_json('CliMatchExtra', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['fingerprint'] = _atd_write_string(self.fingerprint)
        res['lines'] = _atd_write_string(self.lines)
        res['message'] = _atd_write_string(self.message)
        res['metadata'] = (lambda x: x.to_json())(self.metadata)
        res['severity'] = _atd_write_string(self.severity)
        if self.metavars is not None:
            res['metavars'] = (lambda x: x.to_json())(self.metavars)
        if self.fix is not None:
            res['fix'] = _atd_write_string(self.fix)
        if self.fix_regex is not None:
            res['fix_regex'] = (lambda x: x.to_json())(self.fix_regex)
        if self.is_ignored is not None:
            res['is_ignored'] = _atd_write_bool(self.is_ignored)
        if self.sca_info is not None:
            res['sca_info'] = (lambda x: x.to_json())(self.sca_info)
        if self.fixed_lines is not None:
            res['fixed_lines'] = _atd_write_list(_atd_write_string)(self.fixed_lines)
        if self.dataflow_trace is not None:
            res['dataflow_trace'] = (lambda x: x.to_json())(self.dataflow_trace)
        if self.engine_kind is not None:
            res['engine_kind'] = (lambda x: x.to_json())(self.engine_kind)
        if self.validation_state is not None:
            res['validation_state'] = (lambda x: x.to_json())(self.validation_state)
        if self.extra_extra is not None:
            res['extra_extra'] = (lambda x: x.to_json())(self.extra_extra)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'CliMatchExtra':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class CliMatch:
    """Original type: cli_match = { ... }"""

    check_id: RuleId
    path: Fpath
    start: Position
    end: Position
    extra: CliMatchExtra

    @classmethod
    def from_json(cls, x: Any) -> 'CliMatch':
        if isinstance(x, dict):
            return cls(
                check_id=RuleId.from_json(x['check_id']) if 'check_id' in x else _atd_missing_json_field('CliMatch', 'check_id'),
                path=Fpath.from_json(x['path']) if 'path' in x else _atd_missing_json_field('CliMatch', 'path'),
                start=Position.from_json(x['start']) if 'start' in x else _atd_missing_json_field('CliMatch', 'start'),
                end=Position.from_json(x['end']) if 'end' in x else _atd_missing_json_field('CliMatch', 'end'),
                extra=CliMatchExtra.from_json(x['extra']) if 'extra' in x else _atd_missing_json_field('CliMatch', 'extra'),
            )
        else:
            _atd_bad_json('CliMatch', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['check_id'] = (lambda x: x.to_json())(self.check_id)
        res['path'] = (lambda x: x.to_json())(self.path)
        res['start'] = (lambda x: x.to_json())(self.start)
        res['end'] = (lambda x: x.to_json())(self.end)
        res['extra'] = (lambda x: x.to_json())(self.extra)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'CliMatch':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class CliError:
    """Original type: cli_error = { ... }"""

    code: int
    level: str
    type_: str
    rule_id: Optional[RuleId] = None
    message: Optional[str] = None
    path: Optional[Fpath] = None
    long_msg: Optional[str] = None
    short_msg: Optional[str] = None
    spans: Optional[List[ErrorSpan]] = None
    help: Optional[str] = None

    @classmethod
    def from_json(cls, x: Any) -> 'CliError':
        if isinstance(x, dict):
            return cls(
                code=_atd_read_int(x['code']) if 'code' in x else _atd_missing_json_field('CliError', 'code'),
                level=_atd_read_string(x['level']) if 'level' in x else _atd_missing_json_field('CliError', 'level'),
                type_=_atd_read_string(x['type']) if 'type' in x else _atd_missing_json_field('CliError', 'type'),
                rule_id=RuleId.from_json(x['rule_id']) if 'rule_id' in x else None,
                message=_atd_read_string(x['message']) if 'message' in x else None,
                path=Fpath.from_json(x['path']) if 'path' in x else None,
                long_msg=_atd_read_string(x['long_msg']) if 'long_msg' in x else None,
                short_msg=_atd_read_string(x['short_msg']) if 'short_msg' in x else None,
                spans=_atd_read_list(ErrorSpan.from_json)(x['spans']) if 'spans' in x else None,
                help=_atd_read_string(x['help']) if 'help' in x else None,
            )
        else:
            _atd_bad_json('CliError', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['code'] = _atd_write_int(self.code)
        res['level'] = _atd_write_string(self.level)
        res['type'] = _atd_write_string(self.type_)
        if self.rule_id is not None:
            res['rule_id'] = (lambda x: x.to_json())(self.rule_id)
        if self.message is not None:
            res['message'] = _atd_write_string(self.message)
        if self.path is not None:
            res['path'] = (lambda x: x.to_json())(self.path)
        if self.long_msg is not None:
            res['long_msg'] = _atd_write_string(self.long_msg)
        if self.short_msg is not None:
            res['short_msg'] = _atd_write_string(self.short_msg)
        if self.spans is not None:
            res['spans'] = _atd_write_list((lambda x: x.to_json()))(self.spans)
        if self.help is not None:
            res['help'] = _atd_write_string(self.help)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'CliError':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class CliOutput:
    """Original type: cli_output = { ... }"""

    errors: List[CliError]
    results: List[CliMatch]
    paths: ScannedAndSkipped
    version: Optional[Version] = None
    time: Optional[Profile] = None
    explanations: Optional[List[MatchingExplanation]] = None
    rules_by_engine: Optional[List[RuleIdAndEngineKind]] = None
    engine_requested: Optional[EngineKind] = None
    skipped_rules: List[SkippedRule] = field(default_factory=lambda: [])

    @classmethod
    def from_json(cls, x: Any) -> 'CliOutput':
        if isinstance(x, dict):
            return cls(
                errors=_atd_read_list(CliError.from_json)(x['errors']) if 'errors' in x else _atd_missing_json_field('CliOutput', 'errors'),
                results=_atd_read_list(CliMatch.from_json)(x['results']) if 'results' in x else _atd_missing_json_field('CliOutput', 'results'),
                paths=ScannedAndSkipped.from_json(x['paths']) if 'paths' in x else _atd_missing_json_field('CliOutput', 'paths'),
                version=Version.from_json(x['version']) if 'version' in x else None,
                time=Profile.from_json(x['time']) if 'time' in x else None,
                explanations=_atd_read_list(MatchingExplanation.from_json)(x['explanations']) if 'explanations' in x else None,
                rules_by_engine=_atd_read_list(RuleIdAndEngineKind.from_json)(x['rules_by_engine']) if 'rules_by_engine' in x else None,
                engine_requested=EngineKind.from_json(x['engine_requested']) if 'engine_requested' in x else None,
                skipped_rules=_atd_read_list(SkippedRule.from_json)(x['skipped_rules']) if 'skipped_rules' in x else [],
            )
        else:
            _atd_bad_json('CliOutput', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['errors'] = _atd_write_list((lambda x: x.to_json()))(self.errors)
        res['results'] = _atd_write_list((lambda x: x.to_json()))(self.results)
        res['paths'] = (lambda x: x.to_json())(self.paths)
        if self.version is not None:
            res['version'] = (lambda x: x.to_json())(self.version)
        if self.time is not None:
            res['time'] = (lambda x: x.to_json())(self.time)
        if self.explanations is not None:
            res['explanations'] = _atd_write_list((lambda x: x.to_json()))(self.explanations)
        if self.rules_by_engine is not None:
            res['rules_by_engine'] = _atd_write_list((lambda x: x.to_json()))(self.rules_by_engine)
        if self.engine_requested is not None:
            res['engine_requested'] = (lambda x: x.to_json())(self.engine_requested)
        res['skipped_rules'] = _atd_write_list((lambda x: x.to_json()))(self.skipped_rules)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'CliOutput':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class CiScanDependencies:
    """Original type: ci_scan_dependencies"""

    value: Dict[str, List[FoundDependency]]

    @classmethod
    def from_json(cls, x: Any) -> 'CiScanDependencies':
        return cls(_atd_read_assoc_object_into_dict(_atd_read_list(FoundDependency.from_json))(x))

    def to_json(self) -> Any:
        return _atd_write_assoc_dict_to_object(_atd_write_list((lambda x: x.to_json())))(self.value)

    @classmethod
    def from_json_string(cls, x: str) -> 'CiScanDependencies':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class CiScanResults:
    """Original type: ci_scan_results = { ... }"""

    findings: List[Finding]
    ignores: List[Finding]
    token: Optional[str]
    searched_paths: List[str]
    renamed_paths: List[str]
    rule_ids: List[RuleId]
    contributions: Optional[Contributions] = None
    dependencies: Optional[CiScanDependencies] = None

    @classmethod
    def from_json(cls, x: Any) -> 'CiScanResults':
        if isinstance(x, dict):
            return cls(
                findings=_atd_read_list(Finding.from_json)(x['findings']) if 'findings' in x else _atd_missing_json_field('CiScanResults', 'findings'),
                ignores=_atd_read_list(Finding.from_json)(x['ignores']) if 'ignores' in x else _atd_missing_json_field('CiScanResults', 'ignores'),
                token=_atd_read_nullable(_atd_read_string)(x['token']) if 'token' in x else _atd_missing_json_field('CiScanResults', 'token'),
                searched_paths=_atd_read_list(_atd_read_string)(x['searched_paths']) if 'searched_paths' in x else _atd_missing_json_field('CiScanResults', 'searched_paths'),
                renamed_paths=_atd_read_list(_atd_read_string)(x['renamed_paths']) if 'renamed_paths' in x else _atd_missing_json_field('CiScanResults', 'renamed_paths'),
                rule_ids=_atd_read_list(RuleId.from_json)(x['rule_ids']) if 'rule_ids' in x else _atd_missing_json_field('CiScanResults', 'rule_ids'),
                contributions=Contributions.from_json(x['contributions']) if 'contributions' in x else None,
                dependencies=CiScanDependencies.from_json(x['dependencies']) if 'dependencies' in x else None,
            )
        else:
            _atd_bad_json('CiScanResults', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['findings'] = _atd_write_list((lambda x: x.to_json()))(self.findings)
        res['ignores'] = _atd_write_list((lambda x: x.to_json()))(self.ignores)
        res['token'] = _atd_write_nullable(_atd_write_string)(self.token)
        res['searched_paths'] = _atd_write_list(_atd_write_string)(self.searched_paths)
        res['renamed_paths'] = _atd_write_list(_atd_write_string)(self.renamed_paths)
        res['rule_ids'] = _atd_write_list((lambda x: x.to_json()))(self.rule_ids)
        if self.contributions is not None:
            res['contributions'] = (lambda x: x.to_json())(self.contributions)
        if self.dependencies is not None:
            res['dependencies'] = (lambda x: x.to_json())(self.dependencies)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'CiScanResults':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class CiScanCompleteStats:
    """Original type: ci_scan_complete_stats = { ... }"""

    findings: int
    errors: List[CliError]
    total_time: float
    unsupported_exts: Dict[str, int]
    lockfile_scan_info: Dict[str, int]
    parse_rate: Dict[str, ParsingStats]
    engine_requested: Optional[str] = None

    @classmethod
    def from_json(cls, x: Any) -> 'CiScanCompleteStats':
        if isinstance(x, dict):
            return cls(
                findings=_atd_read_int(x['findings']) if 'findings' in x else _atd_missing_json_field('CiScanCompleteStats', 'findings'),
                errors=_atd_read_list(CliError.from_json)(x['errors']) if 'errors' in x else _atd_missing_json_field('CiScanCompleteStats', 'errors'),
                total_time=_atd_read_float(x['total_time']) if 'total_time' in x else _atd_missing_json_field('CiScanCompleteStats', 'total_time'),
                unsupported_exts=_atd_read_assoc_object_into_dict(_atd_read_int)(x['unsupported_exts']) if 'unsupported_exts' in x else _atd_missing_json_field('CiScanCompleteStats', 'unsupported_exts'),
                lockfile_scan_info=_atd_read_assoc_object_into_dict(_atd_read_int)(x['lockfile_scan_info']) if 'lockfile_scan_info' in x else _atd_missing_json_field('CiScanCompleteStats', 'lockfile_scan_info'),
                parse_rate=_atd_read_assoc_object_into_dict(ParsingStats.from_json)(x['parse_rate']) if 'parse_rate' in x else _atd_missing_json_field('CiScanCompleteStats', 'parse_rate'),
                engine_requested=_atd_read_string(x['engine_requested']) if 'engine_requested' in x else None,
            )
        else:
            _atd_bad_json('CiScanCompleteStats', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['findings'] = _atd_write_int(self.findings)
        res['errors'] = _atd_write_list((lambda x: x.to_json()))(self.errors)
        res['total_time'] = _atd_write_float(self.total_time)
        res['unsupported_exts'] = _atd_write_assoc_dict_to_object(_atd_write_int)(self.unsupported_exts)
        res['lockfile_scan_info'] = _atd_write_assoc_dict_to_object(_atd_write_int)(self.lockfile_scan_info)
        res['parse_rate'] = _atd_write_assoc_dict_to_object((lambda x: x.to_json()))(self.parse_rate)
        if self.engine_requested is not None:
            res['engine_requested'] = _atd_write_string(self.engine_requested)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'CiScanCompleteStats':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)


@dataclass
class CiScanCompleteResponse:
    """Original type: ci_scan_complete_response = { ... }"""

    exit_code: int
    stats: CiScanCompleteStats
    dependencies: Optional[CiScanDependencies] = None
    dependency_parser_errors: Optional[List[DependencyParserError]] = None
    task_id: Optional[str] = None

    @classmethod
    def from_json(cls, x: Any) -> 'CiScanCompleteResponse':
        if isinstance(x, dict):
            return cls(
                exit_code=_atd_read_int(x['exit_code']) if 'exit_code' in x else _atd_missing_json_field('CiScanCompleteResponse', 'exit_code'),
                stats=CiScanCompleteStats.from_json(x['stats']) if 'stats' in x else _atd_missing_json_field('CiScanCompleteResponse', 'stats'),
                dependencies=CiScanDependencies.from_json(x['dependencies']) if 'dependencies' in x else None,
                dependency_parser_errors=_atd_read_list(DependencyParserError.from_json)(x['dependency_parser_errors']) if 'dependency_parser_errors' in x else None,
                task_id=_atd_read_string(x['task_id']) if 'task_id' in x else None,
            )
        else:
            _atd_bad_json('CiScanCompleteResponse', x)

    def to_json(self) -> Any:
        res: Dict[str, Any] = {}
        res['exit_code'] = _atd_write_int(self.exit_code)
        res['stats'] = (lambda x: x.to_json())(self.stats)
        if self.dependencies is not None:
            res['dependencies'] = (lambda x: x.to_json())(self.dependencies)
        if self.dependency_parser_errors is not None:
            res['dependency_parser_errors'] = _atd_write_list((lambda x: x.to_json()))(self.dependency_parser_errors)
        if self.task_id is not None:
            res['task_id'] = _atd_write_string(self.task_id)
        return res

    @classmethod
    def from_json_string(cls, x: str) -> 'CiScanCompleteResponse':
        return cls.from_json(json.loads(x))

    def to_json_string(self, **kw: Any) -> str:
        return json.dumps(self.to_json(), **kw)
