| // Copyright 2014 The Chromium Authors |
| // 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 i18n from '../../core/i18n/i18n.js'; |
| import * as Platform from '../../core/platform/platform.js'; |
| import * as Root from '../../core/root/root.js'; |
| import * as SDK from '../../core/sdk/sdk.js'; |
| |
| import type {UISourceCode} from './UISourceCode.js'; |
| import {projectTypes} from './WorkspaceImpl.js'; |
| |
| const UIStrings = { |
| /** |
| * @description Text to stop preventing the debugger from stepping into library code |
| */ |
| removeFromIgnoreList: 'Remove from ignore list', |
| /** |
| * @description Text for scripts that should not be stepped into when debugging |
| */ |
| addScriptToIgnoreList: 'Add script to ignore list', |
| /** |
| * @description Text for directories whose scripts should not be stepped into when debugging |
| */ |
| addDirectoryToIgnoreList: 'Add directory to ignore list', |
| /** |
| * @description A context menu item in the Call Stack Sidebar Pane of the Sources panel |
| */ |
| addAllContentScriptsToIgnoreList: 'Add all extension scripts to ignore list', |
| /** |
| * @description A context menu item in the Call Stack Sidebar Pane of the Sources panel |
| */ |
| addAllThirdPartyScriptsToIgnoreList: 'Add all third-party scripts to ignore list', |
| /** |
| * @description A context menu item in the Call Stack Sidebar Pane of the Sources panel |
| */ |
| addAllAnonymousScriptsToIgnoreList: 'Add all anonymous scripts to ignore list', |
| } as const; |
| |
| const str_ = i18n.i18n.registerUIStrings('models/workspace/IgnoreListManager.ts', UIStrings); |
| const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); |
| |
| export interface IgnoreListGeneralRules { |
| isContentScript?: boolean; |
| isKnownThirdParty?: boolean; |
| isCurrentlyIgnoreListed?: boolean; |
| } |
| |
| export class IgnoreListManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes> implements |
| SDK.TargetManager.SDKModelObserver<SDK.DebuggerModel.DebuggerModel> { |
| readonly #settings: Common.Settings.Settings; |
| readonly #targetManager: SDK.TargetManager.TargetManager; |
| |
| readonly #listeners = new Set<() => void>(); |
| readonly #isIgnoreListedURLCache = new Map<string, boolean>(); |
| readonly #contentScriptExecutionContexts = new Set<string>(); |
| |
| constructor(settings: Common.Settings.Settings, targetManager: SDK.TargetManager.TargetManager) { |
| super(); |
| this.#settings = settings; |
| this.#targetManager = targetManager; |
| |
| this.#targetManager.addModelListener( |
| SDK.DebuggerModel.DebuggerModel, SDK.DebuggerModel.Events.GlobalObjectCleared, |
| this.clearCacheIfNeeded.bind(this), this); |
| this.#targetManager.addModelListener( |
| SDK.RuntimeModel.RuntimeModel, SDK.RuntimeModel.Events.ExecutionContextCreated, this.onExecutionContextCreated, |
| this, {scoped: true}); |
| this.#targetManager.addModelListener( |
| SDK.RuntimeModel.RuntimeModel, SDK.RuntimeModel.Events.ExecutionContextDestroyed, |
| this.onExecutionContextDestroyed, this, {scoped: true}); |
| this.#settings.moduleSetting('skip-stack-frames-pattern').addChangeListener(this.patternChanged.bind(this)); |
| this.#settings.moduleSetting('skip-content-scripts').addChangeListener(this.patternChanged.bind(this)); |
| this.#settings.moduleSetting('automatically-ignore-list-known-third-party-scripts') |
| .addChangeListener(this.patternChanged.bind(this)); |
| this.#settings.moduleSetting('enable-ignore-listing').addChangeListener(this.patternChanged.bind(this)); |
| this.#settings.moduleSetting('skip-anonymous-scripts').addChangeListener(this.patternChanged.bind(this)); |
| |
| this.#targetManager.observeModels(SDK.DebuggerModel.DebuggerModel, this); |
| } |
| |
| static instance(opts: { |
| forceNew: boolean|null, |
| settings?: Common.Settings.Settings, |
| targetManager?: SDK.TargetManager.TargetManager, |
| } = { |
| forceNew: null, |
| }): IgnoreListManager { |
| const {forceNew} = opts; |
| if (forceNew) { |
| Root.DevToolsContext.globalInstance().set( |
| IgnoreListManager, |
| new IgnoreListManager( |
| opts.settings ?? Common.Settings.Settings.instance(), |
| opts.targetManager ?? SDK.TargetManager.TargetManager.instance())); |
| } |
| |
| return Root.DevToolsContext.globalInstance().get(IgnoreListManager); |
| } |
| |
| static removeInstance(): void { |
| Root.DevToolsContext.globalInstance().delete(IgnoreListManager); |
| } |
| |
| addChangeListener(listener: () => void): void { |
| this.#listeners.add(listener); |
| } |
| |
| removeChangeListener(listener: () => void): void { |
| this.#listeners.delete(listener); |
| } |
| |
| modelAdded(debuggerModel: SDK.DebuggerModel.DebuggerModel): void { |
| void this.setIgnoreListPatterns(debuggerModel); |
| const sourceMapManager = debuggerModel.sourceMapManager(); |
| sourceMapManager.addEventListener(SDK.SourceMapManager.Events.SourceMapAttached, this.sourceMapAttached, this); |
| sourceMapManager.addEventListener(SDK.SourceMapManager.Events.SourceMapDetached, this.sourceMapDetached, this); |
| } |
| |
| modelRemoved(debuggerModel: SDK.DebuggerModel.DebuggerModel): void { |
| this.clearCacheIfNeeded(); |
| const sourceMapManager = debuggerModel.sourceMapManager(); |
| sourceMapManager.removeEventListener(SDK.SourceMapManager.Events.SourceMapAttached, this.sourceMapAttached, this); |
| sourceMapManager.removeEventListener(SDK.SourceMapManager.Events.SourceMapDetached, this.sourceMapDetached, this); |
| } |
| |
| private isContentScript(executionContext: SDK.RuntimeModel.ExecutionContext): boolean { |
| return !executionContext.isDefault; |
| } |
| |
| private onExecutionContextCreated(event: Common.EventTarget.EventTargetEvent<SDK.RuntimeModel.ExecutionContext>): |
| void { |
| if (this.isContentScript(event.data)) { |
| this.#contentScriptExecutionContexts.add(event.data.uniqueId); |
| if (this.skipContentScripts) { |
| for (const debuggerModel of this.#targetManager.models(SDK.DebuggerModel.DebuggerModel)) { |
| void this.updateIgnoredExecutionContexts(debuggerModel); |
| } |
| } |
| } |
| } |
| |
| private onExecutionContextDestroyed(event: Common.EventTarget.EventTargetEvent<SDK.RuntimeModel.ExecutionContext>): |
| void { |
| if (this.isContentScript(event.data)) { |
| this.#contentScriptExecutionContexts.delete(event.data.uniqueId); |
| if (this.skipContentScripts) { |
| for (const debuggerModel of this.#targetManager.models(SDK.DebuggerModel.DebuggerModel)) { |
| void this.updateIgnoredExecutionContexts(debuggerModel); |
| } |
| } |
| } |
| } |
| |
| private clearCacheIfNeeded(): void { |
| if (this.#isIgnoreListedURLCache.size > 1024) { |
| this.#isIgnoreListedURLCache.clear(); |
| } |
| } |
| |
| private getSkipStackFramesPatternSetting(): Common.Settings.RegExpSetting { |
| return this.#settings.moduleSetting('skip-stack-frames-pattern') as Common.Settings.RegExpSetting; |
| } |
| |
| private setIgnoreListPatterns(debuggerModel: SDK.DebuggerModel.DebuggerModel): Promise<boolean> { |
| const regexPatterns = this.enableIgnoreListing ? this.getSkipStackFramesPatternSetting().getAsArray() : []; |
| const patterns = ([] as string[]); |
| for (const item of regexPatterns) { |
| if (!item.disabled && item.pattern) { |
| patterns.push(item.pattern); |
| } |
| } |
| return debuggerModel.setBlackboxPatterns(patterns, this.skipAnonymousScripts); |
| } |
| |
| private updateIgnoredExecutionContexts(debuggerModel: SDK.DebuggerModel.DebuggerModel): Promise<boolean> { |
| return debuggerModel.setBlackboxExecutionContexts( |
| this.skipContentScripts ? Array.from(this.#contentScriptExecutionContexts) : []); |
| } |
| |
| private getGeneralRulesForUISourceCode(uiSourceCode: UISourceCode): IgnoreListGeneralRules { |
| const projectType = uiSourceCode.project().type(); |
| const isContentScript = projectType === projectTypes.ContentScripts; |
| const isKnownThirdParty = uiSourceCode.isKnownThirdParty(); |
| return {isContentScript, isKnownThirdParty}; |
| } |
| |
| isUserOrSourceMapIgnoreListedUISourceCode(uiSourceCode: UISourceCode): boolean { |
| if (uiSourceCode.isUnconditionallyIgnoreListed()) { |
| return true; |
| } |
| const url = this.uiSourceCodeURL(uiSourceCode); |
| return this.isUserIgnoreListedURL(url, this.getGeneralRulesForUISourceCode(uiSourceCode)); |
| } |
| |
| isUserIgnoreListedURL(url: Platform.DevToolsPath.UrlString|null, options?: IgnoreListGeneralRules): boolean { |
| if (!this.enableIgnoreListing) { |
| return false; |
| } |
| if (options?.isContentScript && this.skipContentScripts) { |
| return true; |
| } |
| if (options?.isKnownThirdParty && this.automaticallyIgnoreListKnownThirdPartyScripts) { |
| return true; |
| } |
| if (!url) { |
| return this.skipAnonymousScripts; |
| } |
| if (this.#isIgnoreListedURLCache.has(url)) { |
| return Boolean(this.#isIgnoreListedURLCache.get(url)); |
| } |
| |
| const isIgnoreListed = this.getFirstMatchedRegex(url) !== null; |
| this.#isIgnoreListedURLCache.set(url, isIgnoreListed); |
| return isIgnoreListed; |
| } |
| |
| getFirstMatchedRegex(url: Platform.DevToolsPath.UrlString): RegExp|null { |
| if (!url) { |
| return null; |
| } |
| const regexPatterns = this.getSkipStackFramesPatternSetting().getAsArray(); |
| const regexValue = this.urlToRegExpString(url); |
| if (!regexValue) { |
| return null; |
| } |
| |
| for (let i = 0; i < regexPatterns.length; ++i) { |
| const item = regexPatterns[i]; |
| if (item.disabled || item.disabledForUrl === url) { |
| continue; |
| } |
| const regex = new RegExp(item.pattern); |
| if (regex.test(url)) { |
| return regex; |
| } |
| } |
| return null; |
| } |
| |
| private sourceMapAttached( |
| event: Common.EventTarget.EventTargetEvent<{client: SDK.Script.Script, sourceMap: SDK.SourceMap.SourceMap}>): |
| void { |
| const script = event.data.client; |
| const sourceMap = event.data.sourceMap; |
| void this.updateScriptRanges(script, sourceMap); |
| } |
| |
| private sourceMapDetached( |
| event: Common.EventTarget.EventTargetEvent<{client: SDK.Script.Script, sourceMap: SDK.SourceMap.SourceMap}>): |
| void { |
| const script = event.data.client; |
| void this.updateScriptRanges(script, undefined); |
| } |
| |
| private async updateScriptRanges(script: SDK.Script.Script, sourceMap: SDK.SourceMap.SourceMap|undefined): |
| Promise<void> { |
| let hasIgnoreListedMappings = false; |
| if (!this.isUserIgnoreListedURL(script.sourceURL, {isContentScript: script.isContentScript()})) { |
| hasIgnoreListedMappings = |
| sourceMap?.sourceURLs().some( |
| url => this.isUserIgnoreListedURL(url, {isKnownThirdParty: sourceMap.hasIgnoreListHint(url)})) ?? |
| false; |
| } |
| if (!hasIgnoreListedMappings) { |
| if (scriptToRange.get(script) && await script.setBlackboxedRanges([])) { |
| scriptToRange.delete(script); |
| } |
| this.dispatchEventToListeners(Events.IGNORED_SCRIPT_RANGES_UPDATED, script); |
| return; |
| } |
| |
| if (!sourceMap) { |
| return; |
| } |
| |
| const newRanges = |
| sourceMap |
| .findRanges( |
| srcURL => this.isUserIgnoreListedURL(srcURL, {isKnownThirdParty: sourceMap.hasIgnoreListHint(srcURL)}), |
| {isStartMatching: true}) |
| .flatMap(range => [range.start, range.end]); |
| |
| const oldRanges = scriptToRange.get(script) || []; |
| if (!isEqual(oldRanges, newRanges) && await script.setBlackboxedRanges(newRanges)) { |
| scriptToRange.set(script, newRanges); |
| } |
| this.dispatchEventToListeners(Events.IGNORED_SCRIPT_RANGES_UPDATED, script); |
| |
| function isEqual(rangesA: SourceRange[], rangesB: SourceRange[]): boolean { |
| if (rangesA.length !== rangesB.length) { |
| return false; |
| } |
| for (let i = 0; i < rangesA.length; ++i) { |
| if (rangesA[i].lineNumber !== rangesB[i].lineNumber || rangesA[i].columnNumber !== rangesB[i].columnNumber) { |
| return false; |
| } |
| } |
| return true; |
| } |
| } |
| |
| private uiSourceCodeURL(uiSourceCode: UISourceCode): Platform.DevToolsPath.UrlString|null { |
| return uiSourceCode.project().type() === projectTypes.Debugger ? null : uiSourceCode.url(); |
| } |
| |
| canIgnoreListUISourceCode(uiSourceCode: UISourceCode): boolean { |
| const url = this.uiSourceCodeURL(uiSourceCode); |
| return url ? Boolean(this.urlToRegExpString(url)) : false; |
| } |
| |
| ignoreListUISourceCode(uiSourceCode: UISourceCode): void { |
| const url = this.uiSourceCodeURL(uiSourceCode); |
| if (url) { |
| this.ignoreListURL(url); |
| } |
| } |
| |
| unIgnoreListUISourceCode(uiSourceCode: UISourceCode): void { |
| this.unIgnoreListURL(this.uiSourceCodeURL(uiSourceCode), this.getGeneralRulesForUISourceCode(uiSourceCode)); |
| } |
| |
| get enableIgnoreListing(): boolean { |
| return this.#settings.moduleSetting('enable-ignore-listing').get(); |
| } |
| |
| set enableIgnoreListing(value: boolean) { |
| this.#settings.moduleSetting('enable-ignore-listing').set(value); |
| } |
| |
| get skipContentScripts(): boolean { |
| return this.enableIgnoreListing && this.#settings.moduleSetting('skip-content-scripts').get(); |
| } |
| |
| get skipAnonymousScripts(): boolean { |
| return this.enableIgnoreListing && this.#settings.moduleSetting('skip-anonymous-scripts').get(); |
| } |
| |
| get automaticallyIgnoreListKnownThirdPartyScripts(): boolean { |
| return this.enableIgnoreListing && |
| this.#settings.moduleSetting('automatically-ignore-list-known-third-party-scripts').get(); |
| } |
| |
| ignoreListContentScripts(): void { |
| if (!this.enableIgnoreListing) { |
| this.enableIgnoreListing = true; |
| } |
| this.#settings.moduleSetting('skip-content-scripts').set(true); |
| } |
| |
| unIgnoreListContentScripts(): void { |
| this.#settings.moduleSetting('skip-content-scripts').set(false); |
| } |
| |
| ignoreListAnonymousScripts(): void { |
| if (!this.enableIgnoreListing) { |
| this.enableIgnoreListing = true; |
| } |
| this.#settings.moduleSetting('skip-anonymous-scripts').set(true); |
| } |
| |
| unIgnoreListAnonymousScripts(): void { |
| this.#settings.moduleSetting('skip-anonymous-scripts').set(false); |
| } |
| |
| ignoreListThirdParty(): void { |
| if (!this.enableIgnoreListing) { |
| this.enableIgnoreListing = true; |
| } |
| this.#settings.moduleSetting('automatically-ignore-list-known-third-party-scripts').set(true); |
| } |
| |
| unIgnoreListThirdParty(): void { |
| this.#settings.moduleSetting('automatically-ignore-list-known-third-party-scripts').set(false); |
| } |
| |
| ignoreListURL(url: Platform.DevToolsPath.UrlString): void { |
| const regexValue = this.urlToRegExpString(url); |
| if (!regexValue) { |
| return; |
| } |
| this.addRegexToIgnoreList(regexValue, url); |
| } |
| |
| addRegexToIgnoreList(regexValue: string, disabledForUrl?: Platform.DevToolsPath.UrlString): void { |
| const regexPatterns = this.getSkipStackFramesPatternSetting().getAsArray(); |
| |
| let found = false; |
| for (let i = 0; i < regexPatterns.length; ++i) { |
| const item = regexPatterns[i]; |
| if (item.pattern === regexValue || (disabledForUrl && item.disabledForUrl === disabledForUrl)) { |
| item.disabled = false; |
| item.disabledForUrl = undefined; |
| found = true; |
| } |
| } |
| if (!found) { |
| regexPatterns.push({pattern: regexValue, disabled: false}); |
| } |
| if (!this.enableIgnoreListing) { |
| this.enableIgnoreListing = true; |
| } |
| this.getSkipStackFramesPatternSetting().setAsArray(regexPatterns); |
| } |
| |
| unIgnoreListURL(url: Platform.DevToolsPath.UrlString|null, options?: IgnoreListGeneralRules): void { |
| if (options?.isContentScript) { |
| this.unIgnoreListContentScripts(); |
| } |
| |
| if (options?.isKnownThirdParty) { |
| this.unIgnoreListThirdParty(); |
| } |
| |
| if (!url) { |
| this.unIgnoreListAnonymousScripts(); |
| return; |
| } |
| |
| let regexPatterns = this.getSkipStackFramesPatternSetting().getAsArray(); |
| const regexValue = IgnoreListManager.instance().urlToRegExpString(url); |
| if (!regexValue) { |
| return; |
| } |
| |
| regexPatterns = regexPatterns.filter(function(item) { |
| return item.pattern !== regexValue; |
| }); |
| for (let i = 0; i < regexPatterns.length; ++i) { |
| const item = regexPatterns[i]; |
| if (item.disabled) { |
| continue; |
| } |
| try { |
| const regex = new RegExp(item.pattern); |
| if (regex.test(url)) { |
| item.disabled = true; |
| item.disabledForUrl = url; |
| } |
| } catch { |
| } |
| } |
| this.getSkipStackFramesPatternSetting().setAsArray(regexPatterns); |
| } |
| |
| private removeIgnoreListPattern(regexValue: string): void { |
| let regexPatterns = this.getSkipStackFramesPatternSetting().getAsArray(); |
| regexPatterns = regexPatterns.filter(function(item) { |
| return item.pattern !== regexValue; |
| }); |
| this.getSkipStackFramesPatternSetting().setAsArray(regexPatterns); |
| } |
| |
| private ignoreListHasPattern(regexValue: string, enabledOnly: boolean): boolean { |
| const regexPatterns = this.getSkipStackFramesPatternSetting().getAsArray(); |
| return regexPatterns.some(item => !(enabledOnly && item.disabled) && item.pattern === regexValue); |
| } |
| |
| private async patternChanged(): Promise<void> { |
| this.#isIgnoreListedURLCache.clear(); |
| |
| const promises: Array<Promise<unknown>> = []; |
| for (const debuggerModel of this.#targetManager.models(SDK.DebuggerModel.DebuggerModel)) { |
| promises.push(this.setIgnoreListPatterns(debuggerModel)); |
| const sourceMapManager = debuggerModel.sourceMapManager(); |
| for (const script of debuggerModel.scripts()) { |
| promises.push(this.updateScriptRanges(script, sourceMapManager.sourceMapForClient(script))); |
| } |
| promises.push(this.updateIgnoredExecutionContexts(debuggerModel)); |
| } |
| await Promise.all(promises); |
| const listeners = Array.from(this.#listeners); |
| for (const listener of listeners) { |
| listener(); |
| } |
| this.patternChangeFinishedForTests(); |
| } |
| |
| private patternChangeFinishedForTests(): void { |
| // This method is sniffed in tests. |
| } |
| |
| private urlToRegExpString(url: Platform.DevToolsPath.UrlString): string { |
| const parsedURL = new Common.ParsedURL.ParsedURL(url); |
| if (parsedURL.isAboutBlank() || parsedURL.isDataURL()) { |
| return ''; |
| } |
| if (!parsedURL.isValid) { |
| return '^' + Platform.StringUtilities.escapeForRegExp(url) + '$'; |
| } |
| let name: string = parsedURL.lastPathComponent; |
| if (name) { |
| name = '/' + name; |
| } else if (parsedURL.folderPathComponents) { |
| name = parsedURL.folderPathComponents + '/'; |
| } |
| if (!name) { |
| name = parsedURL.host; |
| } |
| if (!name) { |
| return ''; |
| } |
| const scheme = parsedURL.scheme; |
| let prefix = ''; |
| if (scheme && scheme !== 'http' && scheme !== 'https') { |
| prefix = '^' + scheme + '://'; |
| if (scheme === 'chrome-extension') { |
| prefix += parsedURL.host + '\\b'; |
| } |
| prefix += '.*'; |
| } |
| return prefix + Platform.StringUtilities.escapeForRegExp(name) + (url.endsWith(name) ? '$' : '\\b'); |
| } |
| |
| getIgnoreListURLContextMenuItems(uiSourceCode: UISourceCode): |
| Array<{text: string, callback: () => void, jslogContext: string}> { |
| if (uiSourceCode.project().type() === projectTypes.FileSystem) { |
| return []; |
| } |
| |
| const menuItems: Array<{text: string, callback: () => void, jslogContext: string}> = []; |
| const canIgnoreList = this.canIgnoreListUISourceCode(uiSourceCode); |
| const isIgnoreListed = this.isUserOrSourceMapIgnoreListedUISourceCode(uiSourceCode); |
| const isAnonymous = !this.uiSourceCodeURL(uiSourceCode); |
| const {isContentScript, isKnownThirdParty} = this.getGeneralRulesForUISourceCode(uiSourceCode); |
| |
| if (isIgnoreListed) { |
| if (canIgnoreList || isContentScript || isKnownThirdParty || isAnonymous) { |
| menuItems.push({ |
| text: i18nString(UIStrings.removeFromIgnoreList), |
| callback: this.unIgnoreListUISourceCode.bind(this, uiSourceCode), |
| jslogContext: 'remove-script-from-ignorelist', |
| }); |
| } |
| } else { |
| if (canIgnoreList) { |
| menuItems.push({ |
| text: i18nString(UIStrings.addScriptToIgnoreList), |
| callback: this.ignoreListUISourceCode.bind(this, uiSourceCode), |
| jslogContext: 'add-script-to-ignorelist', |
| }); |
| } else if (isAnonymous) { |
| menuItems.push({ |
| text: i18nString(UIStrings.addAllAnonymousScriptsToIgnoreList), |
| callback: this.ignoreListAnonymousScripts.bind(this), |
| jslogContext: 'add-anonymous-scripts-to-ignorelist', |
| }); |
| } |
| menuItems.push(...this.getIgnoreListGeneralContextMenuItems({isContentScript, isKnownThirdParty})); |
| } |
| |
| return menuItems; |
| } |
| |
| private getIgnoreListGeneralContextMenuItems(options?: IgnoreListGeneralRules): |
| Array<{text: string, callback: () => void, jslogContext: string}> { |
| const menuItems: Array<{text: string, callback: () => void, jslogContext: string}> = []; |
| if (options?.isContentScript) { |
| menuItems.push({ |
| text: i18nString(UIStrings.addAllContentScriptsToIgnoreList), |
| callback: this.ignoreListContentScripts.bind(this), |
| jslogContext: 'add-content-scripts-to-ignorelist', |
| }); |
| } |
| if (options?.isKnownThirdParty) { |
| menuItems.push({ |
| text: i18nString(UIStrings.addAllThirdPartyScriptsToIgnoreList), |
| callback: this.ignoreListThirdParty.bind(this), |
| jslogContext: 'add-3p-scripts-to-ignorelist', |
| }); |
| } |
| return menuItems; |
| } |
| |
| getIgnoreListFolderContextMenuItems(url: Platform.DevToolsPath.UrlString, options?: IgnoreListGeneralRules): |
| Array<{text: string, callback: () => void, jslogContext: string}> { |
| const menuItems: Array<{text: string, callback: () => void, jslogContext: string}> = []; |
| |
| const regexValue = '^' + Platform.StringUtilities.escapeForRegExp(url) + '/'; |
| if (this.ignoreListHasPattern(regexValue, true)) { |
| menuItems.push({ |
| text: i18nString(UIStrings.removeFromIgnoreList), |
| callback: this.removeIgnoreListPattern.bind(this, regexValue), |
| jslogContext: 'remove-from-ignore-list', |
| }); |
| } else if (this.isUserIgnoreListedURL(url, options)) { |
| // This specific url isn't on the ignore list, but there are rules that match it. |
| menuItems.push({ |
| text: i18nString(UIStrings.removeFromIgnoreList), |
| callback: this.unIgnoreListURL.bind(this, url, options), |
| jslogContext: 'remove-from-ignore-list', |
| }); |
| } else if (!options?.isCurrentlyIgnoreListed) { |
| // Provide options to add to ignore list, unless folder currently displays |
| // as entirely ignored. |
| menuItems.push({ |
| text: i18nString(UIStrings.addDirectoryToIgnoreList), |
| callback: this.addRegexToIgnoreList.bind(this, regexValue), |
| jslogContext: 'add-directory-to-ignore-list', |
| }); |
| menuItems.push(...this.getIgnoreListGeneralContextMenuItems(options)); |
| } |
| |
| return menuItems; |
| } |
| } |
| |
| export interface SourceRange { |
| lineNumber: number; |
| columnNumber: number; |
| } |
| |
| const scriptToRange = new WeakMap<SDK.Script.Script, SourceRange[]>(); |
| |
| export const enum Events { |
| IGNORED_SCRIPT_RANGES_UPDATED = 'IGNORED_SCRIPT_RANGES_UPDATED', |
| } |
| |
| export interface EventTypes { |
| [Events.IGNORED_SCRIPT_RANGES_UPDATED]: SDK.Script.Script; |
| } |