[go: nahoru, domu]

blob: c6b4cca579d7a3ffc09735ac5aa12f99336c4b89 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as Common from '../../core/common/common.js';
import * as Host from '../../core/host/host.js';
import * as i18n from '../../core/i18n/i18n.js';
import type * as Platform from '../../core/platform/platform.js';
import type * as SDK from '../../core/sdk/sdk.js';
import type * as Protocol from '../../generated/protocol.js';
import {type MarkdownIssueDescription} from './MarkdownIssueDescription.js';
const UIStrings = {
/**
*@description The kind of an issue (plural) (Issues are categorized into kinds).
*/
improvements: 'Improvements',
/**
*@description The kind of an issue (plural) (Issues are categorized into kinds).
*/
pageErrors: 'Page Errors',
/**
*@description The kind of an issue (plural) (Issues are categorized into kinds).
*/
breakingChanges: 'Breaking Changes',
/**
*@description A description for a kind of issue we display in the issues tab.
*/
pageErrorIssue: 'A page error issue: the page is not working correctly',
/**
*@description A description for a kind of issue we display in the issues tab.
*/
breakingChangeIssue: 'A breaking change issue: the page may stop working in an upcoming version of Chrome',
/**
*@description A description for a kind of issue we display in the issues tab.
*/
improvementIssue: 'An improvement issue: there is an opportunity to improve the page',
};
const str_ = i18n.i18n.registerUIStrings('models/issues_manager/Issue.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
// eslint-disable-next-line rulesdir/const_enum
export enum IssueCategory {
CrossOriginEmbedderPolicy = 'CrossOriginEmbedderPolicy',
Generic = 'Generic',
MixedContent = 'MixedContent',
Cookie = 'Cookie',
HeavyAd = 'HeavyAd',
ContentSecurityPolicy = 'ContentSecurityPolicy',
LowTextContrast = 'LowTextContrast',
Cors = 'Cors',
AttributionReporting = 'AttributionReporting',
QuirksMode = 'QuirksMode',
Other = 'Other',
}
// eslint-disable-next-line rulesdir/const_enum
export enum IssueKind {
/**
* Something is not working in the page right now. Issues of this kind need
* usually be fixed right away. They usually indicate that a Web API is being
* used in a wrong way, or that a network request was misconfigured.
*/
PageError = 'PageError',
/**
* The page is using a Web API or relying on browser behavior that is going
* to change in the future. If possible, the message associated with issues
* of this kind should include a time when the behavior is going to change.
*/
BreakingChange = 'BreakingChange',
/**
* Anything that can be improved about the page, but isn't urgent and doesn't
* impair functionality in a major way.
*/
Improvement = 'Improvement',
}
export function getIssueKindName(issueKind: IssueKind): Common.UIString.LocalizedString {
switch (issueKind) {
case IssueKind.BreakingChange:
return i18nString(UIStrings.breakingChanges);
case IssueKind.Improvement:
return i18nString(UIStrings.improvements);
case IssueKind.PageError:
return i18nString(UIStrings.pageErrors);
}
}
export function getIssueKindDescription(issueKind: IssueKind): Common.UIString.LocalizedString {
switch (issueKind) {
case IssueKind.PageError:
return i18nString(UIStrings.pageErrorIssue);
case IssueKind.BreakingChange:
return i18nString(UIStrings.breakingChangeIssue);
case IssueKind.Improvement:
return i18nString(UIStrings.improvementIssue);
}
}
/**
* Union two issue kinds for issue aggregation. The idea is to show the most
* important kind on aggregated issues that union issues of different kinds.
*/
export function unionIssueKind(a: IssueKind, b: IssueKind): IssueKind {
if (a === IssueKind.PageError || b === IssueKind.PageError) {
return IssueKind.PageError;
}
if (a === IssueKind.BreakingChange || b === IssueKind.BreakingChange) {
return IssueKind.BreakingChange;
}
return IssueKind.Improvement;
}
export function getShowThirdPartyIssuesSetting(): Common.Settings.Setting<boolean> {
return Common.Settings.Settings.instance().createSetting('showThirdPartyIssues', false);
}
export interface AffectedElement {
backendNodeId: Protocol.DOM.BackendNodeId;
nodeName: string;
target: SDK.Target.Target|null;
}
export abstract class Issue<IssueCode extends string = string> {
#issueCode: IssueCode;
#issuesModel: SDK.IssuesModel.IssuesModel|null;
protected issueId: Protocol.Audits.IssueId|undefined = undefined;
#hidden: boolean;
constructor(
code: IssueCode|{code: IssueCode, umaCode: string}, issuesModel: SDK.IssuesModel.IssuesModel|null = null,
issueId?: Protocol.Audits.IssueId) {
this.#issueCode = typeof code === 'object' ? code.code : code;
this.#issuesModel = issuesModel;
this.issueId = issueId;
Host.userMetrics.issueCreated(typeof code === 'string' ? code : code.umaCode);
this.#hidden = false;
}
code(): IssueCode {
return this.#issueCode;
}
abstract primaryKey(): string;
abstract getDescription(): MarkdownIssueDescription|null;
abstract getCategory(): IssueCategory;
abstract getKind(): IssueKind;
getBlockedByResponseDetails(): Iterable<Protocol.Audits.BlockedByResponseIssueDetails> {
return [];
}
cookies(): Iterable<Protocol.Audits.AffectedCookie> {
return [];
}
rawCookieLines(): Iterable<string> {
return [];
}
elements(): Iterable<AffectedElement> {
return [];
}
requests(): Iterable<Protocol.Audits.AffectedRequest> {
return [];
}
sources(): Iterable<Protocol.Audits.SourceCodeLocation> {
return [];
}
trackingSites(): Iterable<string> {
return [];
}
isAssociatedWithRequestId(requestId: string): boolean {
for (const request of this.requests()) {
if (request.requestId === requestId) {
return true;
}
}
return false;
}
/**
* The model might be unavailable or belong to a target that has already been disposed.
*/
model(): SDK.IssuesModel.IssuesModel|null {
return this.#issuesModel;
}
isCausedByThirdParty(): boolean {
return false;
}
getIssueId(): Protocol.Audits.IssueId|undefined {
return this.issueId;
}
isHidden(): boolean {
return this.#hidden;
}
setHidden(hidden: boolean): void {
this.#hidden = hidden;
}
}
export function toZeroBasedLocation(location: Protocol.Audits.SourceCodeLocation|undefined): {
url: Platform.DevToolsPath.UrlString,
scriptId: Protocol.Runtime.ScriptId|undefined,
lineNumber: number,
columnNumber: number|undefined,
}|undefined {
if (!location) {
return undefined;
}
return {
url: location.url as Platform.DevToolsPath.UrlString,
scriptId: location.scriptId,
lineNumber: location.lineNumber,
columnNumber: location.columnNumber === 0 ? undefined : location.columnNumber - 1,
};
}