# DO NOT EDIT THIS FILE!
#
# This file is generated from the CDP specification. If you need to make
# changes, edit the generator and regenerate all of the modules.
#
# CDP domain: Audits (experimental)
from __future__ import annotations
from .util import event_class, T_JSON_DICT
from dataclasses import dataclass
import enum
import typing
from . import dom
from . import network
from . import page
from . import runtime


@dataclass
class AffectedCookie:
    '''
    Information about a cookie that is affected by an inspector issue.
    '''
    #: The following three properties uniquely identify a cookie
    name: str

    path: str

    domain: str

    def to_json(self):
        json = dict()
        json['name'] = self.name
        json['path'] = self.path
        json['domain'] = self.domain
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            name=str(json['name']),
            path=str(json['path']),
            domain=str(json['domain']),
        )


@dataclass
class AffectedRequest:
    '''
    Information about a request that is affected by an inspector issue.
    '''
    #: The unique request id.
    request_id: network.RequestId

    url: typing.Optional[str] = None

    def to_json(self):
        json = dict()
        json['requestId'] = self.request_id.to_json()
        if self.url is not None:
            json['url'] = self.url
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            request_id=network.RequestId.from_json(json['requestId']),
            url=str(json['url']) if 'url' in json else None,
        )


@dataclass
class AffectedFrame:
    '''
    Information about the frame affected by an inspector issue.
    '''
    frame_id: page.FrameId

    def to_json(self):
        json = dict()
        json['frameId'] = self.frame_id.to_json()
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            frame_id=page.FrameId.from_json(json['frameId']),
        )


class CookieExclusionReason(enum.Enum):
    EXCLUDE_SAME_SITE_UNSPECIFIED_TREATED_AS_LAX = "ExcludeSameSiteUnspecifiedTreatedAsLax"
    EXCLUDE_SAME_SITE_NONE_INSECURE = "ExcludeSameSiteNoneInsecure"
    EXCLUDE_SAME_SITE_LAX = "ExcludeSameSiteLax"
    EXCLUDE_SAME_SITE_STRICT = "ExcludeSameSiteStrict"
    EXCLUDE_INVALID_SAME_PARTY = "ExcludeInvalidSameParty"
    EXCLUDE_SAME_PARTY_CROSS_PARTY_CONTEXT = "ExcludeSamePartyCrossPartyContext"
    EXCLUDE_DOMAIN_NON_ASCII = "ExcludeDomainNonASCII"
    EXCLUDE_THIRD_PARTY_COOKIE_BLOCKED_IN_FIRST_PARTY_SET = "ExcludeThirdPartyCookieBlockedInFirstPartySet"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        return cls(json)


class CookieWarningReason(enum.Enum):
    WARN_SAME_SITE_UNSPECIFIED_CROSS_SITE_CONTEXT = "WarnSameSiteUnspecifiedCrossSiteContext"
    WARN_SAME_SITE_NONE_INSECURE = "WarnSameSiteNoneInsecure"
    WARN_SAME_SITE_UNSPECIFIED_LAX_ALLOW_UNSAFE = "WarnSameSiteUnspecifiedLaxAllowUnsafe"
    WARN_SAME_SITE_STRICT_LAX_DOWNGRADE_STRICT = "WarnSameSiteStrictLaxDowngradeStrict"
    WARN_SAME_SITE_STRICT_CROSS_DOWNGRADE_STRICT = "WarnSameSiteStrictCrossDowngradeStrict"
    WARN_SAME_SITE_STRICT_CROSS_DOWNGRADE_LAX = "WarnSameSiteStrictCrossDowngradeLax"
    WARN_SAME_SITE_LAX_CROSS_DOWNGRADE_STRICT = "WarnSameSiteLaxCrossDowngradeStrict"
    WARN_SAME_SITE_LAX_CROSS_DOWNGRADE_LAX = "WarnSameSiteLaxCrossDowngradeLax"
    WARN_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE = "WarnAttributeValueExceedsMaxSize"
    WARN_DOMAIN_NON_ASCII = "WarnDomainNonASCII"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        return cls(json)


class CookieOperation(enum.Enum):
    SET_COOKIE = "SetCookie"
    READ_COOKIE = "ReadCookie"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        return cls(json)


@dataclass
class CookieIssueDetails:
    '''
    This information is currently necessary, as the front-end has a difficult
    time finding a specific cookie. With this, we can convey specific error
    information without the cookie.
    '''
    cookie_warning_reasons: typing.List[CookieWarningReason]

    cookie_exclusion_reasons: typing.List[CookieExclusionReason]

    #: Optionally identifies the site-for-cookies and the cookie url, which
    #: may be used by the front-end as additional context.
    operation: CookieOperation

    #: If AffectedCookie is not set then rawCookieLine contains the raw
    #: Set-Cookie header string. This hints at a problem where the
    #: cookie line is syntactically or semantically malformed in a way
    #: that no valid cookie could be created.
    cookie: typing.Optional[AffectedCookie] = None

    raw_cookie_line: typing.Optional[str] = None

    site_for_cookies: typing.Optional[str] = None

    cookie_url: typing.Optional[str] = None

    request: typing.Optional[AffectedRequest] = None

    def to_json(self):
        json = dict()
        json['cookieWarningReasons'] = [i.to_json() for i in self.cookie_warning_reasons]
        json['cookieExclusionReasons'] = [i.to_json() for i in self.cookie_exclusion_reasons]
        json['operation'] = self.operation.to_json()
        if self.cookie is not None:
            json['cookie'] = self.cookie.to_json()
        if self.raw_cookie_line is not None:
            json['rawCookieLine'] = self.raw_cookie_line
        if self.site_for_cookies is not None:
            json['siteForCookies'] = self.site_for_cookies
        if self.cookie_url is not None:
            json['cookieUrl'] = self.cookie_url
        if self.request is not None:
            json['request'] = self.request.to_json()
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            cookie_warning_reasons=[CookieWarningReason.from_json(i) for i in json['cookieWarningReasons']],
            cookie_exclusion_reasons=[CookieExclusionReason.from_json(i) for i in json['cookieExclusionReasons']],
            operation=CookieOperation.from_json(json['operation']),
            cookie=AffectedCookie.from_json(json['cookie']) if 'cookie' in json else None,
            raw_cookie_line=str(json['rawCookieLine']) if 'rawCookieLine' in json else None,
            site_for_cookies=str(json['siteForCookies']) if 'siteForCookies' in json else None,
            cookie_url=str(json['cookieUrl']) if 'cookieUrl' in json else None,
            request=AffectedRequest.from_json(json['request']) if 'request' in json else None,
        )


class MixedContentResolutionStatus(enum.Enum):
    MIXED_CONTENT_BLOCKED = "MixedContentBlocked"
    MIXED_CONTENT_AUTOMATICALLY_UPGRADED = "MixedContentAutomaticallyUpgraded"
    MIXED_CONTENT_WARNING = "MixedContentWarning"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        return cls(json)


class MixedContentResourceType(enum.Enum):
    ATTRIBUTION_SRC = "AttributionSrc"
    AUDIO = "Audio"
    BEACON = "Beacon"
    CSP_REPORT = "CSPReport"
    DOWNLOAD = "Download"
    EVENT_SOURCE = "EventSource"
    FAVICON = "Favicon"
    FONT = "Font"
    FORM = "Form"
    FRAME = "Frame"
    IMAGE = "Image"
    IMPORT = "Import"
    MANIFEST = "Manifest"
    PING = "Ping"
    PLUGIN_DATA = "PluginData"
    PLUGIN_RESOURCE = "PluginResource"
    PREFETCH = "Prefetch"
    RESOURCE = "Resource"
    SCRIPT = "Script"
    SERVICE_WORKER = "ServiceWorker"
    SHARED_WORKER = "SharedWorker"
    STYLESHEET = "Stylesheet"
    TRACK = "Track"
    VIDEO = "Video"
    WORKER = "Worker"
    XML_HTTP_REQUEST = "XMLHttpRequest"
    XSLT = "XSLT"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        return cls(json)


@dataclass
class MixedContentIssueDetails:
    #: The way the mixed content issue is being resolved.
    resolution_status: MixedContentResolutionStatus

    #: The unsafe http url causing the mixed content issue.
    insecure_url: str

    #: The url responsible for the call to an unsafe url.
    main_resource_url: str

    #: The type of resource causing the mixed content issue (css, js, iframe,
    #: form,...). Marked as optional because it is mapped to from
    #: blink::mojom::RequestContextType, which will be replaced
    #: by network::mojom::RequestDestination
    resource_type: typing.Optional[MixedContentResourceType] = None

    #: The mixed content request.
    #: Does not always exist (e.g. for unsafe form submission urls).
    request: typing.Optional[AffectedRequest] = None

    #: Optional because not every mixed content issue is necessarily linked to a frame.
    frame: typing.Optional[AffectedFrame] = None

    def to_json(self):
        json = dict()
        json['resolutionStatus'] = self.resolution_status.to_json()
        json['insecureURL'] = self.insecure_url
        json['mainResourceURL'] = self.main_resource_url
        if self.resource_type is not None:
            json['resourceType'] = self.resource_type.to_json()
        if self.request is not None:
            json['request'] = self.request.to_json()
        if self.frame is not None:
            json['frame'] = self.frame.to_json()
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            resolution_status=MixedContentResolutionStatus.from_json(json['resolutionStatus']),
            insecure_url=str(json['insecureURL']),
            main_resource_url=str(json['mainResourceURL']),
            resource_type=MixedContentResourceType.from_json(json['resourceType']) if 'resourceType' in json else None,
            request=AffectedRequest.from_json(json['request']) if 'request' in json else None,
            frame=AffectedFrame.from_json(json['frame']) if 'frame' in json else None,
        )


class BlockedByResponseReason(enum.Enum):
    '''
    Enum indicating the reason a response has been blocked. These reasons are
    refinements of the net error BLOCKED_BY_RESPONSE.
    '''
    COEP_FRAME_RESOURCE_NEEDS_COEP_HEADER = "CoepFrameResourceNeedsCoepHeader"
    COOP_SANDBOXED_I_FRAME_CANNOT_NAVIGATE_TO_COOP_PAGE = "CoopSandboxedIFrameCannotNavigateToCoopPage"
    CORP_NOT_SAME_ORIGIN = "CorpNotSameOrigin"
    CORP_NOT_SAME_ORIGIN_AFTER_DEFAULTED_TO_SAME_ORIGIN_BY_COEP = "CorpNotSameOriginAfterDefaultedToSameOriginByCoep"
    CORP_NOT_SAME_SITE = "CorpNotSameSite"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        return cls(json)


@dataclass
class BlockedByResponseIssueDetails:
    '''
    Details for a request that has been blocked with the BLOCKED_BY_RESPONSE
    code. Currently only used for COEP/COOP, but may be extended to include
    some CSP errors in the future.
    '''
    request: AffectedRequest

    reason: BlockedByResponseReason

    parent_frame: typing.Optional[AffectedFrame] = None

    blocked_frame: typing.Optional[AffectedFrame] = None

    def to_json(self):
        json = dict()
        json['request'] = self.request.to_json()
        json['reason'] = self.reason.to_json()
        if self.parent_frame is not None:
            json['parentFrame'] = self.parent_frame.to_json()
        if self.blocked_frame is not None:
            json['blockedFrame'] = self.blocked_frame.to_json()
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            request=AffectedRequest.from_json(json['request']),
            reason=BlockedByResponseReason.from_json(json['reason']),
            parent_frame=AffectedFrame.from_json(json['parentFrame']) if 'parentFrame' in json else None,
            blocked_frame=AffectedFrame.from_json(json['blockedFrame']) if 'blockedFrame' in json else None,
        )


class HeavyAdResolutionStatus(enum.Enum):
    HEAVY_AD_BLOCKED = "HeavyAdBlocked"
    HEAVY_AD_WARNING = "HeavyAdWarning"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        return cls(json)


class HeavyAdReason(enum.Enum):
    NETWORK_TOTAL_LIMIT = "NetworkTotalLimit"
    CPU_TOTAL_LIMIT = "CpuTotalLimit"
    CPU_PEAK_LIMIT = "CpuPeakLimit"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        return cls(json)


@dataclass
class HeavyAdIssueDetails:
    #: The resolution status, either blocking the content or warning.
    resolution: HeavyAdResolutionStatus

    #: The reason the ad was blocked, total network or cpu or peak cpu.
    reason: HeavyAdReason

    #: The frame that was blocked.
    frame: AffectedFrame

    def to_json(self):
        json = dict()
        json['resolution'] = self.resolution.to_json()
        json['reason'] = self.reason.to_json()
        json['frame'] = self.frame.to_json()
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            resolution=HeavyAdResolutionStatus.from_json(json['resolution']),
            reason=HeavyAdReason.from_json(json['reason']),
            frame=AffectedFrame.from_json(json['frame']),
        )


class ContentSecurityPolicyViolationType(enum.Enum):
    K_INLINE_VIOLATION = "kInlineViolation"
    K_EVAL_VIOLATION = "kEvalViolation"
    K_URL_VIOLATION = "kURLViolation"
    K_TRUSTED_TYPES_SINK_VIOLATION = "kTrustedTypesSinkViolation"
    K_TRUSTED_TYPES_POLICY_VIOLATION = "kTrustedTypesPolicyViolation"
    K_WASM_EVAL_VIOLATION = "kWasmEvalViolation"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        return cls(json)


@dataclass
class SourceCodeLocation:
    url: str

    line_number: int

    column_number: int

    script_id: typing.Optional[runtime.ScriptId] = None

    def to_json(self):
        json = dict()
        json['url'] = self.url
        json['lineNumber'] = self.line_number
        json['columnNumber'] = self.column_number
        if self.script_id is not None:
            json['scriptId'] = self.script_id.to_json()
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            url=str(json['url']),
            line_number=int(json['lineNumber']),
            column_number=int(json['columnNumber']),
            script_id=runtime.ScriptId.from_json(json['scriptId']) if 'scriptId' in json else None,
        )


@dataclass
class ContentSecurityPolicyIssueDetails:
    #: Specific directive that is violated, causing the CSP issue.
    violated_directive: str

    is_report_only: bool

    content_security_policy_violation_type: ContentSecurityPolicyViolationType

    #: The url not included in allowed sources.
    blocked_url: typing.Optional[str] = None

    frame_ancestor: typing.Optional[AffectedFrame] = None

    source_code_location: typing.Optional[SourceCodeLocation] = None

    violating_node_id: typing.Optional[dom.BackendNodeId] = None

    def to_json(self):
        json = dict()
        json['violatedDirective'] = self.violated_directive
        json['isReportOnly'] = self.is_report_only
        json['contentSecurityPolicyViolationType'] = self.content_security_policy_violation_type.to_json()
        if self.blocked_url is not None:
            json['blockedURL'] = self.blocked_url
        if self.frame_ancestor is not None:
            json['frameAncestor'] = self.frame_ancestor.to_json()
        if self.source_code_location is not None:
            json['sourceCodeLocation'] = self.source_code_location.to_json()
        if self.violating_node_id is not None:
            json['violatingNodeId'] = self.violating_node_id.to_json()
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            violated_directive=str(json['violatedDirective']),
            is_report_only=bool(json['isReportOnly']),
            content_security_policy_violation_type=ContentSecurityPolicyViolationType.from_json(json['contentSecurityPolicyViolationType']),
            blocked_url=str(json['blockedURL']) if 'blockedURL' in json else None,
            frame_ancestor=AffectedFrame.from_json(json['frameAncestor']) if 'frameAncestor' in json else None,
            source_code_location=SourceCodeLocation.from_json(json['sourceCodeLocation']) if 'sourceCodeLocation' in json else None,
            violating_node_id=dom.BackendNodeId.from_json(json['violatingNodeId']) if 'violatingNodeId' in json else None,
        )


class SharedArrayBufferIssueType(enum.Enum):
    TRANSFER_ISSUE = "TransferIssue"
    CREATION_ISSUE = "CreationIssue"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        return cls(json)


@dataclass
class SharedArrayBufferIssueDetails:
    '''
    Details for a issue arising from an SAB being instantiated in, or
    transferred to a context that is not cross-origin isolated.
    '''
    source_code_location: SourceCodeLocation

    is_warning: bool

    type_: SharedArrayBufferIssueType

    def to_json(self):
        json = dict()
        json['sourceCodeLocation'] = self.source_code_location.to_json()
        json['isWarning'] = self.is_warning
        json['type'] = self.type_.to_json()
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            source_code_location=SourceCodeLocation.from_json(json['sourceCodeLocation']),
            is_warning=bool(json['isWarning']),
            type_=SharedArrayBufferIssueType.from_json(json['type']),
        )


class TwaQualityEnforcementViolationType(enum.Enum):
    K_HTTP_ERROR = "kHttpError"
    K_UNAVAILABLE_OFFLINE = "kUnavailableOffline"
    K_DIGITAL_ASSET_LINKS = "kDigitalAssetLinks"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        return cls(json)


@dataclass
class TrustedWebActivityIssueDetails:
    #: The url that triggers the violation.
    url: str

    violation_type: TwaQualityEnforcementViolationType

    http_status_code: typing.Optional[int] = None

    #: The package name of the Trusted Web Activity client app. This field is
    #: only used when violation type is kDigitalAssetLinks.
    package_name: typing.Optional[str] = None

    #: The signature of the Trusted Web Activity client app. This field is only
    #: used when violation type is kDigitalAssetLinks.
    signature: typing.Optional[str] = None

    def to_json(self):
        json = dict()
        json['url'] = self.url
        json['violationType'] = self.violation_type.to_json()
        if self.http_status_code is not None:
            json['httpStatusCode'] = self.http_status_code
        if self.package_name is not None:
            json['packageName'] = self.package_name
        if self.signature is not None:
            json['signature'] = self.signature
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            url=str(json['url']),
            violation_type=TwaQualityEnforcementViolationType.from_json(json['violationType']),
            http_status_code=int(json['httpStatusCode']) if 'httpStatusCode' in json else None,
            package_name=str(json['packageName']) if 'packageName' in json else None,
            signature=str(json['signature']) if 'signature' in json else None,
        )


@dataclass
class LowTextContrastIssueDetails:
    violating_node_id: dom.BackendNodeId

    violating_node_selector: str

    contrast_ratio: float

    threshold_aa: float

    threshold_aaa: float

    font_size: str

    font_weight: str

    def to_json(self):
        json = dict()
        json['violatingNodeId'] = self.violating_node_id.to_json()
        json['violatingNodeSelector'] = self.violating_node_selector
        json['contrastRatio'] = self.contrast_ratio
        json['thresholdAA'] = self.threshold_aa
        json['thresholdAAA'] = self.threshold_aaa
        json['fontSize'] = self.font_size
        json['fontWeight'] = self.font_weight
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            violating_node_id=dom.BackendNodeId.from_json(json['violatingNodeId']),
            violating_node_selector=str(json['violatingNodeSelector']),
            contrast_ratio=float(json['contrastRatio']),
            threshold_aa=float(json['thresholdAA']),
            threshold_aaa=float(json['thresholdAAA']),
            font_size=str(json['fontSize']),
            font_weight=str(json['fontWeight']),
        )


@dataclass
class CorsIssueDetails:
    '''
    Details for a CORS related issue, e.g. a warning or error related to
    CORS RFC1918 enforcement.
    '''
    cors_error_status: network.CorsErrorStatus

    is_warning: bool

    request: AffectedRequest

    location: typing.Optional[SourceCodeLocation] = None

    initiator_origin: typing.Optional[str] = None

    resource_ip_address_space: typing.Optional[network.IPAddressSpace] = None

    client_security_state: typing.Optional[network.ClientSecurityState] = None

    def to_json(self):
        json = dict()
        json['corsErrorStatus'] = self.cors_error_status.to_json()
        json['isWarning'] = self.is_warning
        json['request'] = self.request.to_json()
        if self.location is not None:
            json['location'] = self.location.to_json()
        if self.initiator_origin is not None:
            json['initiatorOrigin'] = self.initiator_origin
        if self.resource_ip_address_space is not None:
            json['resourceIPAddressSpace'] = self.resource_ip_address_space.to_json()
        if self.client_security_state is not None:
            json['clientSecurityState'] = self.client_security_state.to_json()
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            cors_error_status=network.CorsErrorStatus.from_json(json['corsErrorStatus']),
            is_warning=bool(json['isWarning']),
            request=AffectedRequest.from_json(json['request']),
            location=SourceCodeLocation.from_json(json['location']) if 'location' in json else None,
            initiator_origin=str(json['initiatorOrigin']) if 'initiatorOrigin' in json else None,
            resource_ip_address_space=network.IPAddressSpace.from_json(json['resourceIPAddressSpace']) if 'resourceIPAddressSpace' in json else None,
            client_security_state=network.ClientSecurityState.from_json(json['clientSecurityState']) if 'clientSecurityState' in json else None,
        )


class AttributionReportingIssueType(enum.Enum):
    PERMISSION_POLICY_DISABLED = "PermissionPolicyDisabled"
    UNTRUSTWORTHY_REPORTING_ORIGIN = "UntrustworthyReportingOrigin"
    INSECURE_CONTEXT = "InsecureContext"
    INVALID_HEADER = "InvalidHeader"
    INVALID_REGISTER_TRIGGER_HEADER = "InvalidRegisterTriggerHeader"
    INVALID_ELIGIBLE_HEADER = "InvalidEligibleHeader"
    SOURCE_AND_TRIGGER_HEADERS = "SourceAndTriggerHeaders"
    SOURCE_IGNORED = "SourceIgnored"
    TRIGGER_IGNORED = "TriggerIgnored"
    OS_SOURCE_IGNORED = "OsSourceIgnored"
    OS_TRIGGER_IGNORED = "OsTriggerIgnored"
    INVALID_REGISTER_OS_SOURCE_HEADER = "InvalidRegisterOsSourceHeader"
    INVALID_REGISTER_OS_TRIGGER_HEADER = "InvalidRegisterOsTriggerHeader"
    WEB_AND_OS_HEADERS = "WebAndOsHeaders"
    NO_WEB_OR_OS_SUPPORT = "NoWebOrOsSupport"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        return cls(json)


@dataclass
class AttributionReportingIssueDetails:
    '''
    Details for issues around "Attribution Reporting API" usage.
    Explainer: https://github.com/WICG/attribution-reporting-api
    '''
    violation_type: AttributionReportingIssueType

    request: typing.Optional[AffectedRequest] = None

    violating_node_id: typing.Optional[dom.BackendNodeId] = None

    invalid_parameter: typing.Optional[str] = None

    def to_json(self):
        json = dict()
        json['violationType'] = self.violation_type.to_json()
        if self.request is not None:
            json['request'] = self.request.to_json()
        if self.violating_node_id is not None:
            json['violatingNodeId'] = self.violating_node_id.to_json()
        if self.invalid_parameter is not None:
            json['invalidParameter'] = self.invalid_parameter
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            violation_type=AttributionReportingIssueType.from_json(json['violationType']),
            request=AffectedRequest.from_json(json['request']) if 'request' in json else None,
            violating_node_id=dom.BackendNodeId.from_json(json['violatingNodeId']) if 'violatingNodeId' in json else None,
            invalid_parameter=str(json['invalidParameter']) if 'invalidParameter' in json else None,
        )


@dataclass
class QuirksModeIssueDetails:
    '''
    Details for issues about documents in Quirks Mode
    or Limited Quirks Mode that affects page layouting.
    '''
    #: If false, it means the document's mode is "quirks"
    #: instead of "limited-quirks".
    is_limited_quirks_mode: bool

    document_node_id: dom.BackendNodeId

    url: str

    frame_id: page.FrameId

    loader_id: network.LoaderId

    def to_json(self):
        json = dict()
        json['isLimitedQuirksMode'] = self.is_limited_quirks_mode
        json['documentNodeId'] = self.document_node_id.to_json()
        json['url'] = self.url
        json['frameId'] = self.frame_id.to_json()
        json['loaderId'] = self.loader_id.to_json()
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            is_limited_quirks_mode=bool(json['isLimitedQuirksMode']),
            document_node_id=dom.BackendNodeId.from_json(json['documentNodeId']),
            url=str(json['url']),
            frame_id=page.FrameId.from_json(json['frameId']),
            loader_id=network.LoaderId.from_json(json['loaderId']),
        )


@dataclass
class NavigatorUserAgentIssueDetails:
    url: str

    location: typing.Optional[SourceCodeLocation] = None

    def to_json(self):
        json = dict()
        json['url'] = self.url
        if self.location is not None:
            json['location'] = self.location.to_json()
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            url=str(json['url']),
            location=SourceCodeLocation.from_json(json['location']) if 'location' in json else None,
        )


class GenericIssueErrorType(enum.Enum):
    CROSS_ORIGIN_PORTAL_POST_MESSAGE_ERROR = "CrossOriginPortalPostMessageError"
    FORM_LABEL_FOR_NAME_ERROR = "FormLabelForNameError"
    FORM_DUPLICATE_ID_FOR_INPUT_ERROR = "FormDuplicateIdForInputError"
    FORM_INPUT_WITH_NO_LABEL_ERROR = "FormInputWithNoLabelError"
    FORM_AUTOCOMPLETE_ATTRIBUTE_EMPTY_ERROR = "FormAutocompleteAttributeEmptyError"
    FORM_EMPTY_ID_AND_NAME_ATTRIBUTES_FOR_INPUT_ERROR = "FormEmptyIdAndNameAttributesForInputError"
    FORM_ARIA_LABELLED_BY_TO_NON_EXISTING_ID = "FormAriaLabelledByToNonExistingId"
    FORM_INPUT_ASSIGNED_AUTOCOMPLETE_VALUE_TO_ID_OR_NAME_ATTRIBUTE_ERROR = "FormInputAssignedAutocompleteValueToIdOrNameAttributeError"
    FORM_LABEL_HAS_NEITHER_FOR_NOR_NESTED_INPUT = "FormLabelHasNeitherForNorNestedInput"
    FORM_LABEL_FOR_MATCHES_NON_EXISTING_ID_ERROR = "FormLabelForMatchesNonExistingIdError"
    FORM_INPUT_HAS_WRONG_BUT_WELL_INTENDED_AUTOCOMPLETE_VALUE_ERROR = "FormInputHasWrongButWellIntendedAutocompleteValueError"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        return cls(json)


@dataclass
class GenericIssueDetails:
    '''
    Depending on the concrete errorType, different properties are set.
    '''
    #: Issues with the same errorType are aggregated in the frontend.
    error_type: GenericIssueErrorType

    frame_id: typing.Optional[page.FrameId] = None

    violating_node_id: typing.Optional[dom.BackendNodeId] = None

    violating_node_attribute: typing.Optional[str] = None

    def to_json(self):
        json = dict()
        json['errorType'] = self.error_type.to_json()
        if self.frame_id is not None:
            json['frameId'] = self.frame_id.to_json()
        if self.violating_node_id is not None:
            json['violatingNodeId'] = self.violating_node_id.to_json()
        if self.violating_node_attribute is not None:
            json['violatingNodeAttribute'] = self.violating_node_attribute
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            error_type=GenericIssueErrorType.from_json(json['errorType']),
            frame_id=page.FrameId.from_json(json['frameId']) if 'frameId' in json else None,
            violating_node_id=dom.BackendNodeId.from_json(json['violatingNodeId']) if 'violatingNodeId' in json else None,
            violating_node_attribute=str(json['violatingNodeAttribute']) if 'violatingNodeAttribute' in json else None,
        )


@dataclass
class DeprecationIssueDetails:
    '''
    This issue tracks information needed to print a deprecation message.
    https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/frame/third_party/blink/renderer/core/frame/deprecation/README.md
    '''
    source_code_location: SourceCodeLocation

    #: One of the deprecation names from third_party/blink/renderer/core/frame/deprecation/deprecation.json5
    type_: str

    affected_frame: typing.Optional[AffectedFrame] = None

    def to_json(self):
        json = dict()
        json['sourceCodeLocation'] = self.source_code_location.to_json()
        json['type'] = self.type_
        if self.affected_frame is not None:
            json['affectedFrame'] = self.affected_frame.to_json()
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            source_code_location=SourceCodeLocation.from_json(json['sourceCodeLocation']),
            type_=str(json['type']),
            affected_frame=AffectedFrame.from_json(json['affectedFrame']) if 'affectedFrame' in json else None,
        )


@dataclass
class BounceTrackingIssueDetails:
    '''
    This issue warns about sites in the redirect chain of a finished navigation
    that may be flagged as trackers and have their state cleared if they don't
    receive a user interaction. Note that in this context 'site' means eTLD+1.
    For example, if the URL ``https://example.test:80/bounce`` was in the
    redirect chain, the site reported would be ``example.test``.
    '''
    tracking_sites: typing.List[str]

    def to_json(self):
        json = dict()
        json['trackingSites'] = [i for i in self.tracking_sites]
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            tracking_sites=[str(i) for i in json['trackingSites']],
        )


class ClientHintIssueReason(enum.Enum):
    META_TAG_ALLOW_LIST_INVALID_ORIGIN = "MetaTagAllowListInvalidOrigin"
    META_TAG_MODIFIED_HTML = "MetaTagModifiedHTML"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        return cls(json)


@dataclass
class FederatedAuthRequestIssueDetails:
    federated_auth_request_issue_reason: FederatedAuthRequestIssueReason

    def to_json(self):
        json = dict()
        json['federatedAuthRequestIssueReason'] = self.federated_auth_request_issue_reason.to_json()
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            federated_auth_request_issue_reason=FederatedAuthRequestIssueReason.from_json(json['federatedAuthRequestIssueReason']),
        )


class FederatedAuthRequestIssueReason(enum.Enum):
    '''
    Represents the failure reason when a federated authentication reason fails.
    Should be updated alongside RequestIdTokenStatus in
    third_party/blink/public/mojom/devtools/inspector_issue.mojom to include
    all cases except for success.
    '''
    SHOULD_EMBARGO = "ShouldEmbargo"
    TOO_MANY_REQUESTS = "TooManyRequests"
    WELL_KNOWN_HTTP_NOT_FOUND = "WellKnownHttpNotFound"
    WELL_KNOWN_NO_RESPONSE = "WellKnownNoResponse"
    WELL_KNOWN_INVALID_RESPONSE = "WellKnownInvalidResponse"
    WELL_KNOWN_LIST_EMPTY = "WellKnownListEmpty"
    WELL_KNOWN_INVALID_CONTENT_TYPE = "WellKnownInvalidContentType"
    CONFIG_NOT_IN_WELL_KNOWN = "ConfigNotInWellKnown"
    WELL_KNOWN_TOO_BIG = "WellKnownTooBig"
    CONFIG_HTTP_NOT_FOUND = "ConfigHttpNotFound"
    CONFIG_NO_RESPONSE = "ConfigNoResponse"
    CONFIG_INVALID_RESPONSE = "ConfigInvalidResponse"
    CONFIG_INVALID_CONTENT_TYPE = "ConfigInvalidContentType"
    CLIENT_METADATA_HTTP_NOT_FOUND = "ClientMetadataHttpNotFound"
    CLIENT_METADATA_NO_RESPONSE = "ClientMetadataNoResponse"
    CLIENT_METADATA_INVALID_RESPONSE = "ClientMetadataInvalidResponse"
    CLIENT_METADATA_INVALID_CONTENT_TYPE = "ClientMetadataInvalidContentType"
    DISABLED_IN_SETTINGS = "DisabledInSettings"
    ERROR_FETCHING_SIGNIN = "ErrorFetchingSignin"
    INVALID_SIGNIN_RESPONSE = "InvalidSigninResponse"
    ACCOUNTS_HTTP_NOT_FOUND = "AccountsHttpNotFound"
    ACCOUNTS_NO_RESPONSE = "AccountsNoResponse"
    ACCOUNTS_INVALID_RESPONSE = "AccountsInvalidResponse"
    ACCOUNTS_LIST_EMPTY = "AccountsListEmpty"
    ACCOUNTS_INVALID_CONTENT_TYPE = "AccountsInvalidContentType"
    ID_TOKEN_HTTP_NOT_FOUND = "IdTokenHttpNotFound"
    ID_TOKEN_NO_RESPONSE = "IdTokenNoResponse"
    ID_TOKEN_INVALID_RESPONSE = "IdTokenInvalidResponse"
    ID_TOKEN_INVALID_REQUEST = "IdTokenInvalidRequest"
    ID_TOKEN_INVALID_CONTENT_TYPE = "IdTokenInvalidContentType"
    ERROR_ID_TOKEN = "ErrorIdToken"
    CANCELED = "Canceled"
    RP_PAGE_NOT_VISIBLE = "RpPageNotVisible"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        return cls(json)


@dataclass
class ClientHintIssueDetails:
    '''
    This issue tracks client hints related issues. It's used to deprecate old
    features, encourage the use of new ones, and provide general guidance.
    '''
    source_code_location: SourceCodeLocation

    client_hint_issue_reason: ClientHintIssueReason

    def to_json(self):
        json = dict()
        json['sourceCodeLocation'] = self.source_code_location.to_json()
        json['clientHintIssueReason'] = self.client_hint_issue_reason.to_json()
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            source_code_location=SourceCodeLocation.from_json(json['sourceCodeLocation']),
            client_hint_issue_reason=ClientHintIssueReason.from_json(json['clientHintIssueReason']),
        )


class InspectorIssueCode(enum.Enum):
    '''
    A unique identifier for the type of issue. Each type may use one of the
    optional fields in InspectorIssueDetails to convey more specific
    information about the kind of issue.
    '''
    COOKIE_ISSUE = "CookieIssue"
    MIXED_CONTENT_ISSUE = "MixedContentIssue"
    BLOCKED_BY_RESPONSE_ISSUE = "BlockedByResponseIssue"
    HEAVY_AD_ISSUE = "HeavyAdIssue"
    CONTENT_SECURITY_POLICY_ISSUE = "ContentSecurityPolicyIssue"
    SHARED_ARRAY_BUFFER_ISSUE = "SharedArrayBufferIssue"
    TRUSTED_WEB_ACTIVITY_ISSUE = "TrustedWebActivityIssue"
    LOW_TEXT_CONTRAST_ISSUE = "LowTextContrastIssue"
    CORS_ISSUE = "CorsIssue"
    ATTRIBUTION_REPORTING_ISSUE = "AttributionReportingIssue"
    QUIRKS_MODE_ISSUE = "QuirksModeIssue"
    NAVIGATOR_USER_AGENT_ISSUE = "NavigatorUserAgentIssue"
    GENERIC_ISSUE = "GenericIssue"
    DEPRECATION_ISSUE = "DeprecationIssue"
    CLIENT_HINT_ISSUE = "ClientHintIssue"
    FEDERATED_AUTH_REQUEST_ISSUE = "FederatedAuthRequestIssue"
    BOUNCE_TRACKING_ISSUE = "BounceTrackingIssue"

    def to_json(self):
        return self.value

    @classmethod
    def from_json(cls, json):
        return cls(json)


@dataclass
class InspectorIssueDetails:
    '''
    This struct holds a list of optional fields with additional information
    specific to the kind of issue. When adding a new issue code, please also
    add a new optional field to this type.
    '''
    cookie_issue_details: typing.Optional[CookieIssueDetails] = None

    mixed_content_issue_details: typing.Optional[MixedContentIssueDetails] = None

    blocked_by_response_issue_details: typing.Optional[BlockedByResponseIssueDetails] = None

    heavy_ad_issue_details: typing.Optional[HeavyAdIssueDetails] = None

    content_security_policy_issue_details: typing.Optional[ContentSecurityPolicyIssueDetails] = None

    shared_array_buffer_issue_details: typing.Optional[SharedArrayBufferIssueDetails] = None

    twa_quality_enforcement_details: typing.Optional[TrustedWebActivityIssueDetails] = None

    low_text_contrast_issue_details: typing.Optional[LowTextContrastIssueDetails] = None

    cors_issue_details: typing.Optional[CorsIssueDetails] = None

    attribution_reporting_issue_details: typing.Optional[AttributionReportingIssueDetails] = None

    quirks_mode_issue_details: typing.Optional[QuirksModeIssueDetails] = None

    navigator_user_agent_issue_details: typing.Optional[NavigatorUserAgentIssueDetails] = None

    generic_issue_details: typing.Optional[GenericIssueDetails] = None

    deprecation_issue_details: typing.Optional[DeprecationIssueDetails] = None

    client_hint_issue_details: typing.Optional[ClientHintIssueDetails] = None

    federated_auth_request_issue_details: typing.Optional[FederatedAuthRequestIssueDetails] = None

    bounce_tracking_issue_details: typing.Optional[BounceTrackingIssueDetails] = None

    def to_json(self):
        json = dict()
        if self.cookie_issue_details is not None:
            json['cookieIssueDetails'] = self.cookie_issue_details.to_json()
        if self.mixed_content_issue_details is not None:
            json['mixedContentIssueDetails'] = self.mixed_content_issue_details.to_json()
        if self.blocked_by_response_issue_details is not None:
            json['blockedByResponseIssueDetails'] = self.blocked_by_response_issue_details.to_json()
        if self.heavy_ad_issue_details is not None:
            json['heavyAdIssueDetails'] = self.heavy_ad_issue_details.to_json()
        if self.content_security_policy_issue_details is not None:
            json['contentSecurityPolicyIssueDetails'] = self.content_security_policy_issue_details.to_json()
        if self.shared_array_buffer_issue_details is not None:
            json['sharedArrayBufferIssueDetails'] = self.shared_array_buffer_issue_details.to_json()
        if self.twa_quality_enforcement_details is not None:
            json['twaQualityEnforcementDetails'] = self.twa_quality_enforcement_details.to_json()
        if self.low_text_contrast_issue_details is not None:
            json['lowTextContrastIssueDetails'] = self.low_text_contrast_issue_details.to_json()
        if self.cors_issue_details is not None:
            json['corsIssueDetails'] = self.cors_issue_details.to_json()
        if self.attribution_reporting_issue_details is not None:
            json['attributionReportingIssueDetails'] = self.attribution_reporting_issue_details.to_json()
        if self.quirks_mode_issue_details is not None:
            json['quirksModeIssueDetails'] = self.quirks_mode_issue_details.to_json()
        if self.navigator_user_agent_issue_details is not None:
            json['navigatorUserAgentIssueDetails'] = self.navigator_user_agent_issue_details.to_json()
        if self.generic_issue_details is not None:
            json['genericIssueDetails'] = self.generic_issue_details.to_json()
        if self.deprecation_issue_details is not None:
            json['deprecationIssueDetails'] = self.deprecation_issue_details.to_json()
        if self.client_hint_issue_details is not None:
            json['clientHintIssueDetails'] = self.client_hint_issue_details.to_json()
        if self.federated_auth_request_issue_details is not None:
            json['federatedAuthRequestIssueDetails'] = self.federated_auth_request_issue_details.to_json()
        if self.bounce_tracking_issue_details is not None:
            json['bounceTrackingIssueDetails'] = self.bounce_tracking_issue_details.to_json()
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            cookie_issue_details=CookieIssueDetails.from_json(json['cookieIssueDetails']) if 'cookieIssueDetails' in json else None,
            mixed_content_issue_details=MixedContentIssueDetails.from_json(json['mixedContentIssueDetails']) if 'mixedContentIssueDetails' in json else None,
            blocked_by_response_issue_details=BlockedByResponseIssueDetails.from_json(json['blockedByResponseIssueDetails']) if 'blockedByResponseIssueDetails' in json else None,
            heavy_ad_issue_details=HeavyAdIssueDetails.from_json(json['heavyAdIssueDetails']) if 'heavyAdIssueDetails' in json else None,
            content_security_policy_issue_details=ContentSecurityPolicyIssueDetails.from_json(json['contentSecurityPolicyIssueDetails']) if 'contentSecurityPolicyIssueDetails' in json else None,
            shared_array_buffer_issue_details=SharedArrayBufferIssueDetails.from_json(json['sharedArrayBufferIssueDetails']) if 'sharedArrayBufferIssueDetails' in json else None,
            twa_quality_enforcement_details=TrustedWebActivityIssueDetails.from_json(json['twaQualityEnforcementDetails']) if 'twaQualityEnforcementDetails' in json else None,
            low_text_contrast_issue_details=LowTextContrastIssueDetails.from_json(json['lowTextContrastIssueDetails']) if 'lowTextContrastIssueDetails' in json else None,
            cors_issue_details=CorsIssueDetails.from_json(json['corsIssueDetails']) if 'corsIssueDetails' in json else None,
            attribution_reporting_issue_details=AttributionReportingIssueDetails.from_json(json['attributionReportingIssueDetails']) if 'attributionReportingIssueDetails' in json else None,
            quirks_mode_issue_details=QuirksModeIssueDetails.from_json(json['quirksModeIssueDetails']) if 'quirksModeIssueDetails' in json else None,
            navigator_user_agent_issue_details=NavigatorUserAgentIssueDetails.from_json(json['navigatorUserAgentIssueDetails']) if 'navigatorUserAgentIssueDetails' in json else None,
            generic_issue_details=GenericIssueDetails.from_json(json['genericIssueDetails']) if 'genericIssueDetails' in json else None,
            deprecation_issue_details=DeprecationIssueDetails.from_json(json['deprecationIssueDetails']) if 'deprecationIssueDetails' in json else None,
            client_hint_issue_details=ClientHintIssueDetails.from_json(json['clientHintIssueDetails']) if 'clientHintIssueDetails' in json else None,
            federated_auth_request_issue_details=FederatedAuthRequestIssueDetails.from_json(json['federatedAuthRequestIssueDetails']) if 'federatedAuthRequestIssueDetails' in json else None,
            bounce_tracking_issue_details=BounceTrackingIssueDetails.from_json(json['bounceTrackingIssueDetails']) if 'bounceTrackingIssueDetails' in json else None,
        )


class IssueId(str):
    '''
    A unique id for a DevTools inspector issue. Allows other entities (e.g.
    exceptions, CDP message, console messages, etc.) to reference an issue.
    '''
    def to_json(self) -> str:
        return self

    @classmethod
    def from_json(cls, json: str) -> IssueId:
        return cls(json)

    def __repr__(self):
        return 'IssueId({})'.format(super().__repr__())


@dataclass
class InspectorIssue:
    '''
    An inspector issue reported from the back-end.
    '''
    code: InspectorIssueCode

    details: InspectorIssueDetails

    #: A unique id for this issue. May be omitted if no other entity (e.g.
    #: exception, CDP message, etc.) is referencing this issue.
    issue_id: typing.Optional[IssueId] = None

    def to_json(self):
        json = dict()
        json['code'] = self.code.to_json()
        json['details'] = self.details.to_json()
        if self.issue_id is not None:
            json['issueId'] = self.issue_id.to_json()
        return json

    @classmethod
    def from_json(cls, json):
        return cls(
            code=InspectorIssueCode.from_json(json['code']),
            details=InspectorIssueDetails.from_json(json['details']),
            issue_id=IssueId.from_json(json['issueId']) if 'issueId' in json else None,
        )


def get_encoded_response(
        request_id: network.RequestId,
        encoding: str,
        quality: typing.Optional[float] = None,
        size_only: typing.Optional[bool] = None
    ) -> typing.Generator[T_JSON_DICT,T_JSON_DICT,typing.Tuple[typing.Optional[str], int, int]]:
    '''
    Returns the response body and size if it were re-encoded with the specified settings. Only
    applies to images.

    :param request_id: Identifier of the network request to get content for.
    :param encoding: The encoding to use.
    :param quality: *(Optional)* The quality of the encoding (0-1). (defaults to 1)
    :param size_only: *(Optional)* Whether to only return the size information (defaults to false).
    :returns: A tuple with the following items:

        0. **body** - *(Optional)* The encoded body as a base64 string. Omitted if sizeOnly is true.
        1. **originalSize** - Size before re-encoding.
        2. **encodedSize** - Size after re-encoding.
    '''
    params: T_JSON_DICT = dict()
    params['requestId'] = request_id.to_json()
    params['encoding'] = encoding
    if quality is not None:
        params['quality'] = quality
    if size_only is not None:
        params['sizeOnly'] = size_only
    cmd_dict: T_JSON_DICT = {
        'method': 'Audits.getEncodedResponse',
        'params': params,
    }
    json = yield cmd_dict
    return (
        str(json['body']) if 'body' in json else None,
        int(json['originalSize']),
        int(json['encodedSize'])
    )


def disable() -> typing.Generator[T_JSON_DICT,T_JSON_DICT,None]:
    '''
    Disables issues domain, prevents further issues from being reported to the client.
    '''
    cmd_dict: T_JSON_DICT = {
        'method': 'Audits.disable',
    }
    json = yield cmd_dict


def enable() -> typing.Generator[T_JSON_DICT,T_JSON_DICT,None]:
    '''
    Enables issues domain, sends the issues collected so far to the client by means of the
    ``issueAdded`` event.
    '''
    cmd_dict: T_JSON_DICT = {
        'method': 'Audits.enable',
    }
    json = yield cmd_dict


def check_contrast(
        report_aaa: typing.Optional[bool] = None
    ) -> typing.Generator[T_JSON_DICT,T_JSON_DICT,None]:
    '''
    Runs the contrast check for the target page. Found issues are reported
    using Audits.issueAdded event.

    :param report_aaa: *(Optional)* Whether to report WCAG AAA level issues. Default is false.
    '''
    params: T_JSON_DICT = dict()
    if report_aaa is not None:
        params['reportAAA'] = report_aaa
    cmd_dict: T_JSON_DICT = {
        'method': 'Audits.checkContrast',
        'params': params,
    }
    json = yield cmd_dict


@event_class('Audits.issueAdded')
@dataclass
class IssueAdded:
    issue: InspectorIssue

    @classmethod
    def from_json(cls, json: T_JSON_DICT) -> IssueAdded:
        return cls(
            issue=InspectorIssue.from_json(json['issue'])
        )
