devtools-tracing 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/README.md +4 -0
  2. package/generate.ts +32 -26
  3. package/index.ts +2 -1
  4. package/lib/extension-api/ExtensionAPI.d.ts +357 -0
  5. package/lib/front_end/models/bindings/CSSWorkspaceBinding.ts +318 -0
  6. package/lib/front_end/models/bindings/CompilerScriptMapping.ts +536 -0
  7. package/lib/front_end/models/bindings/ContentProviderBasedProject.ts +187 -0
  8. package/lib/front_end/models/bindings/DebuggerLanguagePlugins.ts +1197 -0
  9. package/lib/front_end/models/bindings/DebuggerWorkspaceBinding.ts +733 -0
  10. package/lib/front_end/models/bindings/DefaultScriptMapping.ts +141 -0
  11. package/lib/front_end/models/bindings/FileUtils.ts +228 -0
  12. package/lib/front_end/models/bindings/LiveLocation.ts +81 -0
  13. package/lib/front_end/models/bindings/NetworkProject.ts +157 -0
  14. package/lib/front_end/models/bindings/PresentationConsoleMessageHelper.ts +312 -0
  15. package/lib/front_end/models/bindings/ResourceMapping.ts +539 -0
  16. package/lib/front_end/models/bindings/ResourceScriptMapping.ts +491 -0
  17. package/lib/front_end/models/bindings/ResourceUtils.ts +103 -0
  18. package/lib/front_end/models/bindings/SASSSourceMapping.ts +222 -0
  19. package/lib/front_end/models/bindings/StylesSourceMapping.ts +316 -0
  20. package/lib/front_end/models/bindings/TempFile.ts +67 -0
  21. package/lib/front_end/models/bindings/bindings.ts +39 -0
  22. package/lib/front_end/models/source_map_scopes/NamesResolver.ts +765 -0
  23. package/lib/front_end/models/source_map_scopes/ScopeChainModel.ts +84 -0
  24. package/lib/front_end/models/source_map_scopes/source_map_scopes.ts +11 -0
  25. package/lib/front_end/models/stack_trace/StackTrace.ts +53 -0
  26. package/lib/front_end/models/stack_trace/StackTraceImpl.ts +85 -0
  27. package/lib/front_end/models/stack_trace/StackTraceModel.ts +128 -0
  28. package/lib/front_end/models/stack_trace/Trie.ts +163 -0
  29. package/lib/front_end/models/stack_trace/stack_trace.ts +9 -0
  30. package/lib/front_end/models/stack_trace/stack_trace_impl.ts +13 -0
  31. package/lib/front_end/models/trace_source_maps_resolver/SourceMapsResolver.ts +240 -0
  32. package/lib/front_end/models/trace_source_maps_resolver/trace_source_maps_resolver.ts +5 -0
  33. package/lib/front_end/models/workspace/FileManager.ts +97 -0
  34. package/lib/front_end/models/workspace/IgnoreListManager.ts +628 -0
  35. package/lib/front_end/models/workspace/SearchConfig.ts +149 -0
  36. package/lib/front_end/models/workspace/UISourceCode.ts +698 -0
  37. package/lib/front_end/models/workspace/WorkspaceImpl.ts +339 -0
  38. package/lib/front_end/models/workspace/workspace.ts +17 -0
  39. package/lib/front_end/panels/timeline/TimelineUIUtils.ts +1029 -0
  40. package/lib/front_end/panels/timeline/extensions/ExtensionUI.ts +49 -0
  41. package/lib/front_end/panels/timeline/extensions/extensions.ts +9 -0
  42. package/lib/front_end/third_party/codemirror.next/LICENSE +21 -0
  43. package/lib/front_end/third_party/codemirror.next/README.chromium +30 -0
  44. package/lib/front_end/third_party/codemirror.next/bundle-tsconfig.json +24 -0
  45. package/lib/front_end/third_party/codemirror.next/bundle.ts +135 -0
  46. package/lib/front_end/third_party/codemirror.next/chunk/angular.js +2 -0
  47. package/lib/front_end/third_party/codemirror.next/chunk/angular.js.map +1 -0
  48. package/lib/front_end/third_party/codemirror.next/chunk/codemirror.js +2 -0
  49. package/lib/front_end/third_party/codemirror.next/chunk/codemirror.js.map +1 -0
  50. package/lib/front_end/third_party/codemirror.next/chunk/cpp.js +2 -0
  51. package/lib/front_end/third_party/codemirror.next/chunk/cpp.js.map +1 -0
  52. package/lib/front_end/third_party/codemirror.next/chunk/css.js +2 -0
  53. package/lib/front_end/third_party/codemirror.next/chunk/html.js +4 -0
  54. package/lib/front_end/third_party/codemirror.next/chunk/java.js +2 -0
  55. package/lib/front_end/third_party/codemirror.next/chunk/java.js.map +1 -0
  56. package/lib/front_end/third_party/codemirror.next/chunk/javascript.js +2 -0
  57. package/lib/front_end/third_party/codemirror.next/chunk/legacy.js +2 -0
  58. package/lib/front_end/third_party/codemirror.next/chunk/legacy.js.map +1 -0
  59. package/lib/front_end/third_party/codemirror.next/chunk/less.js +2 -0
  60. package/lib/front_end/third_party/codemirror.next/chunk/less.js.map +1 -0
  61. package/lib/front_end/third_party/codemirror.next/chunk/markdown.js +2 -0
  62. package/lib/front_end/third_party/codemirror.next/chunk/markdown.js.map +1 -0
  63. package/lib/front_end/third_party/codemirror.next/chunk/php.js +2 -0
  64. package/lib/front_end/third_party/codemirror.next/chunk/php.js.map +1 -0
  65. package/lib/front_end/third_party/codemirror.next/chunk/python.js +2 -0
  66. package/lib/front_end/third_party/codemirror.next/chunk/python.js.map +1 -0
  67. package/lib/front_end/third_party/codemirror.next/chunk/sass.js +2 -0
  68. package/lib/front_end/third_party/codemirror.next/chunk/sass.js.map +1 -0
  69. package/lib/front_end/third_party/codemirror.next/chunk/svelte.js +2 -0
  70. package/lib/front_end/third_party/codemirror.next/chunk/svelte.js.map +1 -0
  71. package/lib/front_end/third_party/codemirror.next/chunk/vue.js +2 -0
  72. package/lib/front_end/third_party/codemirror.next/chunk/vue.js.map +1 -0
  73. package/lib/front_end/third_party/codemirror.next/chunk/wast.js +2 -0
  74. package/lib/front_end/third_party/codemirror.next/chunk/wast.js.map +1 -0
  75. package/lib/front_end/third_party/codemirror.next/chunk/xml.js +2 -0
  76. package/lib/front_end/third_party/codemirror.next/chunk/xml.js.map +1 -0
  77. package/lib/front_end/third_party/codemirror.next/codemirror.next.d.ts +8057 -0
  78. package/lib/front_end/third_party/codemirror.next/codemirror.next.js +2 -0
  79. package/lib/front_end/third_party/codemirror.next/codemirror.next.js.map +1 -0
  80. package/lib/front_end/third_party/codemirror.next/package.json +43 -0
  81. package/lib/front_end/third_party/codemirror.next/rebuild.sh +6 -0
  82. package/lib/front_end/third_party/codemirror.next/rollup.config.mjs +49 -0
  83. package/lib/front_end/third_party/source-map-scopes-codec/LICENSE +26 -0
  84. package/lib/front_end/third_party/source-map-scopes-codec/README.chromium +31 -0
  85. package/lib/front_end/third_party/source-map-scopes-codec/package/CONTRIBUTING.md +33 -0
  86. package/lib/front_end/third_party/source-map-scopes-codec/package/LICENSE +26 -0
  87. package/lib/front_end/third_party/source-map-scopes-codec/package/README.md +64 -0
  88. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts +62 -0
  89. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts.map +1 -0
  90. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts +37 -0
  91. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts.map +1 -0
  92. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts +29 -0
  93. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts.map +1 -0
  94. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts +8 -0
  95. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts.map +1 -0
  96. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts +6 -0
  97. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts.map +1 -0
  98. package/lib/front_end/third_party/source-map-scopes-codec/package/deno.json +21 -0
  99. package/lib/front_end/third_party/source-map-scopes-codec/package/package.json +14 -0
  100. package/lib/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js +196 -0
  101. package/lib/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js.map +1 -0
  102. package/lib/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.ts +262 -0
  103. package/lib/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js +235 -0
  104. package/lib/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js.map +1 -0
  105. package/lib/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.ts +359 -0
  106. package/lib/front_end/third_party/source-map-scopes-codec/package/src/codec.js +39 -0
  107. package/lib/front_end/third_party/source-map-scopes-codec/package/src/codec.js.map +1 -0
  108. package/lib/front_end/third_party/source-map-scopes-codec/package/src/codec.ts +53 -0
  109. package/lib/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js +438 -0
  110. package/lib/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js.map +1 -0
  111. package/lib/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.ts +539 -0
  112. package/lib/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js +23 -0
  113. package/lib/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js.map +1 -0
  114. package/lib/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.ts +35 -0
  115. package/lib/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js +257 -0
  116. package/lib/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js.map +1 -0
  117. package/lib/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.ts +348 -0
  118. package/lib/front_end/third_party/source-map-scopes-codec/package/src/mod.js +8 -0
  119. package/lib/front_end/third_party/source-map-scopes-codec/package/src/mod.js.map +1 -0
  120. package/lib/front_end/third_party/source-map-scopes-codec/package/src/mod.ts +20 -0
  121. package/lib/front_end/third_party/source-map-scopes-codec/package/src/scopes-tsconfig.json +8 -0
  122. package/lib/front_end/third_party/source-map-scopes-codec/package/src/scopes.d.ts +184 -0
  123. package/lib/front_end/third_party/source-map-scopes-codec/package/src/util.js +9 -0
  124. package/lib/front_end/third_party/source-map-scopes-codec/package/src/util.js.map +1 -0
  125. package/lib/front_end/third_party/source-map-scopes-codec/package/src/util.ts +12 -0
  126. package/lib/front_end/third_party/source-map-scopes-codec/package/src/vlq.js +82 -0
  127. package/lib/front_end/third_party/source-map-scopes-codec/package/src/vlq.js.map +1 -0
  128. package/lib/front_end/third_party/source-map-scopes-codec/package/src/vlq.ts +99 -0
  129. package/lib/front_end/third_party/source-map-scopes-codec/source-map-scopes-codec.ts +5 -0
  130. package/lib/front_end/ui/legacy/theme_support/ThemeSupport.ts +222 -0
  131. package/lib/front_end/ui/legacy/theme_support/theme_support.ts +5 -0
  132. package/package.json +11 -5
  133. package/patches/chrome-devtools-frontend+1.0.1533544.patch +1549 -20
@@ -0,0 +1,698 @@
1
+ // Copyright 2011 The Chromium Authors
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ /* eslint-disable @typescript-eslint/no-explicit-any */
6
+
7
+ import * as Common from '../../core/common/common.js';
8
+ import * as i18n from '../../core/i18n/i18n.js';
9
+ import * as Platform from '../../core/platform/platform.js';
10
+ import * as TextUtils from '../text_utils/text_utils.js';
11
+
12
+ import {IgnoreListManager} from './IgnoreListManager.js';
13
+ import {Events as WorkspaceImplEvents, type Project} from './WorkspaceImpl.js';
14
+
15
+ const UIStrings = {
16
+ /**
17
+ * @description Text for the index of something
18
+ */
19
+ index: '(index)',
20
+ /**
21
+ * @description Text in UISource Code of the DevTools local workspace
22
+ */
23
+ thisFileWasChangedExternally: 'This file was changed externally. Would you like to reload it?',
24
+ } as const;
25
+ const str_ = i18n.i18n.registerUIStrings('models/workspace/UISourceCode.ts', UIStrings);
26
+ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
27
+
28
+ export class UISourceCode extends Common.ObjectWrapper.ObjectWrapper<EventTypes> implements
29
+ TextUtils.ContentProvider.ContentProvider {
30
+ readonly #origin: Platform.DevToolsPath.UrlString;
31
+ readonly #parentURL: Platform.DevToolsPath.UrlString;
32
+ #project: Project;
33
+ #url: Platform.DevToolsPath.UrlString;
34
+ #name: string;
35
+ #contentType: Common.ResourceType.ResourceType;
36
+ #requestContentPromise: Promise<TextUtils.ContentData.ContentDataOrError>|null = null;
37
+ #decorations = new Map<string, any>();
38
+ #hasCommits = false;
39
+ #messages: Set<Message>|null = null;
40
+ #content: TextUtils.ContentData.ContentDataOrError|null = null;
41
+ #forceLoadOnCheckContent = false;
42
+ #checkingContent = false;
43
+ #lastAcceptedContent: string|null = null;
44
+ #workingCopy: string|null = null;
45
+ #workingCopyGetter: (() => string)|null = null;
46
+ #disableEdit = false;
47
+ #contentEncoded: boolean|undefined;
48
+ #isKnownThirdParty = false;
49
+ #isUnconditionallyIgnoreListed = false;
50
+ #containsAiChanges = false;
51
+
52
+ constructor(project: Project, url: Platform.DevToolsPath.UrlString, contentType: Common.ResourceType.ResourceType) {
53
+ super();
54
+ this.#project = project;
55
+ this.#url = url;
56
+
57
+ const parsedURL = Common.ParsedURL.ParsedURL.fromString(url);
58
+ if (parsedURL) {
59
+ this.#origin = parsedURL.securityOrigin();
60
+ this.#parentURL = Common.ParsedURL.ParsedURL.concatenate(this.#origin, parsedURL.folderPathComponents);
61
+ if (parsedURL.queryParams && !(parsedURL.lastPathComponent && contentType.isFromSourceMap())) {
62
+ // If there is a query param, display it like a URL. Unless it is from a source map,
63
+ // in which case the query param is probably a hash that is best left hidden.
64
+ this.#name = parsedURL.lastPathComponent + '?' + parsedURL.queryParams;
65
+ } else {
66
+ // file name looks best decoded
67
+ try {
68
+ this.#name = decodeURIComponent(parsedURL.lastPathComponent);
69
+ } catch {
70
+ // Decoding might fail.
71
+ this.#name = parsedURL.lastPathComponent;
72
+ }
73
+ }
74
+ } else {
75
+ this.#origin = Platform.DevToolsPath.EmptyUrlString;
76
+ this.#parentURL = Platform.DevToolsPath.EmptyUrlString;
77
+ this.#name = url;
78
+ }
79
+
80
+ this.#contentType = contentType;
81
+ }
82
+
83
+ requestMetadata(): Promise<UISourceCodeMetadata|null> {
84
+ return this.#project.requestMetadata(this);
85
+ }
86
+
87
+ name(): string {
88
+ return this.#name;
89
+ }
90
+
91
+ mimeType(): string {
92
+ return this.#project.mimeType(this);
93
+ }
94
+
95
+ url(): Platform.DevToolsPath.UrlString {
96
+ return this.#url;
97
+ }
98
+
99
+ // Identifier used for deduplicating scripts that are considered by the
100
+ // DevTools UI to be the same script. For now this is just the url but this
101
+ // is likely to change in the future.
102
+ canonicalScriptId(): string {
103
+ return `${this.#contentType.name()},${this.#url}`;
104
+ }
105
+
106
+ parentURL(): Platform.DevToolsPath.UrlString {
107
+ return this.#parentURL;
108
+ }
109
+
110
+ origin(): Platform.DevToolsPath.UrlString {
111
+ return this.#origin;
112
+ }
113
+
114
+ fullDisplayName(): string {
115
+ return this.#project.fullDisplayName(this);
116
+ }
117
+
118
+ displayName(skipTrim?: boolean): string {
119
+ if (!this.#name) {
120
+ return i18nString(UIStrings.index);
121
+ }
122
+ const name = this.#name;
123
+ return skipTrim ? name : Platform.StringUtilities.trimEndWithMaxLength(name, 100);
124
+ }
125
+
126
+ canRename(): boolean {
127
+ return this.#project.canRename();
128
+ }
129
+
130
+ rename(newName: Platform.DevToolsPath.RawPathString): Promise<boolean> {
131
+ const {resolve, promise} = Promise.withResolvers<boolean>();
132
+ this.#project.rename(this, newName, innerCallback.bind(this));
133
+ return promise;
134
+
135
+ function innerCallback(
136
+ this: UISourceCode, success: boolean, newName?: string, newURL?: Platform.DevToolsPath.UrlString,
137
+ newContentType?: Common.ResourceType.ResourceType): void {
138
+ if (success) {
139
+ this.#updateName(
140
+ newName as Platform.DevToolsPath.RawPathString, newURL as Platform.DevToolsPath.UrlString,
141
+ newContentType as Common.ResourceType.ResourceType);
142
+ }
143
+ resolve(success);
144
+ }
145
+ }
146
+
147
+ remove(): void {
148
+ this.#project.deleteFile(this);
149
+ }
150
+
151
+ #updateName(
152
+ name: Platform.DevToolsPath.RawPathString, url: Platform.DevToolsPath.UrlString,
153
+ contentType?: Common.ResourceType.ResourceType): void {
154
+ const oldURL = this.#url;
155
+ this.#name = name;
156
+ if (url) {
157
+ this.#url = url;
158
+ } else {
159
+ this.#url = Common.ParsedURL.ParsedURL.relativePathToUrlString(name, oldURL);
160
+ }
161
+ if (contentType) {
162
+ this.#contentType = contentType;
163
+ }
164
+ this.dispatchEventToListeners(Events.TitleChanged, this);
165
+ this.project().workspace().dispatchEventToListeners(
166
+ WorkspaceImplEvents.UISourceCodeRenamed, {oldURL, uiSourceCode: this});
167
+ }
168
+
169
+ contentURL(): Platform.DevToolsPath.UrlString {
170
+ return this.url();
171
+ }
172
+
173
+ contentType(): Common.ResourceType.ResourceType {
174
+ return this.#contentType;
175
+ }
176
+
177
+ project(): Project {
178
+ return this.#project;
179
+ }
180
+
181
+ requestContentData({cachedWasmOnly}: {cachedWasmOnly?: boolean} = {}):
182
+ Promise<TextUtils.ContentData.ContentDataOrError> {
183
+ if (this.#requestContentPromise) {
184
+ return this.#requestContentPromise;
185
+ }
186
+
187
+ if (this.#content) {
188
+ return Promise.resolve(this.#content);
189
+ }
190
+
191
+ if (cachedWasmOnly && this.mimeType() === 'application/wasm') {
192
+ return Promise.resolve(new TextUtils.WasmDisassembly.WasmDisassembly([], [], []));
193
+ }
194
+
195
+ this.#requestContentPromise = this.#requestContent();
196
+ return this.#requestContentPromise;
197
+ }
198
+
199
+ async #requestContent(): Promise<TextUtils.ContentData.ContentDataOrError> {
200
+ if (this.#content) {
201
+ throw new Error('Called UISourceCode#requestContentImpl even though content is available for ' + this.#url);
202
+ }
203
+
204
+ try {
205
+ this.#content = await this.#project.requestFileContent(this);
206
+ } catch (err) {
207
+ this.#content = {error: err ? String(err) : ''};
208
+ }
209
+
210
+ return this.#content;
211
+ }
212
+
213
+ #decodeContent(content: TextUtils.ContentProvider.DeferredContent|null): string|null {
214
+ if (!content) {
215
+ return null;
216
+ }
217
+ return content.isEncoded && content.content ? window.atob(content.content) : content.content;
218
+ }
219
+
220
+ /** Only used to compare whether content changed */
221
+ #unsafeDecodeContentData(content: TextUtils.ContentData.ContentDataOrError|null): string|null {
222
+ if (!content || TextUtils.ContentData.ContentData.isError(content)) {
223
+ return null;
224
+ }
225
+ return content.createdFromBase64 ? window.atob(content.base64) : content.text;
226
+ }
227
+
228
+ async checkContentUpdated(): Promise<void> {
229
+ if (!this.#content && !this.#forceLoadOnCheckContent) {
230
+ return;
231
+ }
232
+
233
+ if (!this.#project.canSetFileContent() || this.#checkingContent) {
234
+ return;
235
+ }
236
+
237
+ this.#checkingContent = true;
238
+ const updatedContent =
239
+ TextUtils.ContentData.ContentData.asDeferredContent(await this.#project.requestFileContent(this));
240
+ if ('error' in updatedContent) {
241
+ return;
242
+ }
243
+ this.#checkingContent = false;
244
+ if (updatedContent.content === null) {
245
+ const workingCopy = this.workingCopy();
246
+ this.#contentCommitted('', false);
247
+ this.setWorkingCopy(workingCopy);
248
+ return;
249
+ }
250
+ if (this.#lastAcceptedContent === updatedContent.content) {
251
+ return;
252
+ }
253
+
254
+ if (this.#unsafeDecodeContentData(this.#content) === this.#decodeContent(updatedContent)) {
255
+ this.#lastAcceptedContent = null;
256
+ return;
257
+ }
258
+
259
+ if (!this.isDirty() || this.#workingCopy === updatedContent.content) {
260
+ this.#contentCommitted(updatedContent.content, false);
261
+ return;
262
+ }
263
+
264
+ await Common.Revealer.reveal(this);
265
+
266
+ // Make sure we are in the next frame before stopping the world with confirm
267
+ await new Promise(resolve => window.setTimeout(resolve, 0));
268
+
269
+ const shouldUpdate = window.confirm(i18nString(UIStrings.thisFileWasChangedExternally));
270
+ if (shouldUpdate) {
271
+ this.#contentCommitted(updatedContent.content, false);
272
+ } else {
273
+ this.#lastAcceptedContent = updatedContent.content;
274
+ }
275
+ }
276
+
277
+ forceLoadOnCheckContent(): void {
278
+ this.#forceLoadOnCheckContent = true;
279
+ }
280
+
281
+ #commitContent(content: string): void {
282
+ if (this.#project.canSetFileContent()) {
283
+ void this.#project.setFileContent(this, content, false);
284
+ }
285
+ this.#contentCommitted(content, true);
286
+ }
287
+
288
+ #contentCommitted(content: string, committedByUser: boolean): void {
289
+ this.#lastAcceptedContent = null;
290
+ this.#content = new TextUtils.ContentData.ContentData(content, Boolean(this.#contentEncoded), this.mimeType());
291
+ this.#requestContentPromise = null;
292
+
293
+ this.#hasCommits = true;
294
+
295
+ this.#resetWorkingCopy();
296
+ const data = {uiSourceCode: this, content, encoded: this.#contentEncoded};
297
+ this.dispatchEventToListeners(Events.WorkingCopyCommitted, data);
298
+ this.#project.workspace().dispatchEventToListeners(WorkspaceImplEvents.WorkingCopyCommitted, data);
299
+ if (committedByUser) {
300
+ this.#project.workspace().dispatchEventToListeners(WorkspaceImplEvents.WorkingCopyCommittedByUser, data);
301
+ }
302
+ }
303
+
304
+ addRevision(content: string): void {
305
+ this.#commitContent(content);
306
+ }
307
+
308
+ hasCommits(): boolean {
309
+ return this.#hasCommits;
310
+ }
311
+
312
+ workingCopy(): string {
313
+ return this.workingCopyContent().content || '';
314
+ }
315
+
316
+ workingCopyContent(): TextUtils.ContentProvider.DeferredContent {
317
+ return this.workingCopyContentData().asDeferedContent();
318
+ }
319
+
320
+ workingCopyContentData(): TextUtils.ContentData.ContentData {
321
+ if (this.#workingCopyGetter) {
322
+ this.#workingCopy = this.#workingCopyGetter();
323
+ this.#workingCopyGetter = null;
324
+ }
325
+ const contentData = this.#content ? TextUtils.ContentData.ContentData.contentDataOrEmpty(this.#content) :
326
+ TextUtils.ContentData.EMPTY_TEXT_CONTENT_DATA;
327
+ if (this.#workingCopy !== null) {
328
+ return new TextUtils.ContentData.ContentData(this.#workingCopy, /* isBase64 */ false, contentData.mimeType);
329
+ }
330
+ return contentData;
331
+ }
332
+
333
+ resetWorkingCopy(): void {
334
+ this.#resetWorkingCopy();
335
+ this.#workingCopyChanged();
336
+ }
337
+
338
+ #resetWorkingCopy(): void {
339
+ this.#workingCopy = null;
340
+ this.#workingCopyGetter = null;
341
+ this.setContainsAiChanges(false);
342
+ }
343
+
344
+ setWorkingCopy(newWorkingCopy: string): void {
345
+ this.#workingCopy = newWorkingCopy;
346
+ this.#workingCopyGetter = null;
347
+ this.#workingCopyChanged();
348
+ }
349
+
350
+ setContainsAiChanges(containsAiChanges: boolean): void {
351
+ this.#containsAiChanges = containsAiChanges;
352
+ }
353
+
354
+ containsAiChanges(): boolean {
355
+ return this.#containsAiChanges;
356
+ }
357
+
358
+ setContent(content: string, isBase64: boolean): void {
359
+ this.#contentEncoded = isBase64;
360
+ if (this.#project.canSetFileContent()) {
361
+ void this.#project.setFileContent(this, content, isBase64);
362
+ }
363
+ this.#contentCommitted(content, true);
364
+ }
365
+
366
+ setWorkingCopyGetter(workingCopyGetter: () => string): void {
367
+ this.#workingCopyGetter = workingCopyGetter;
368
+ this.#workingCopyChanged();
369
+ }
370
+
371
+ #workingCopyChanged(): void {
372
+ this.#removeAllMessages();
373
+ this.dispatchEventToListeners(Events.WorkingCopyChanged, this);
374
+ this.#project.workspace().dispatchEventToListeners(WorkspaceImplEvents.WorkingCopyChanged, {uiSourceCode: this});
375
+ }
376
+
377
+ removeWorkingCopyGetter(): void {
378
+ if (!this.#workingCopyGetter) {
379
+ return;
380
+ }
381
+ this.#workingCopy = this.#workingCopyGetter();
382
+ this.#workingCopyGetter = null;
383
+ }
384
+
385
+ commitWorkingCopy(): void {
386
+ if (this.isDirty()) {
387
+ this.#commitContent(this.workingCopy());
388
+ }
389
+ }
390
+
391
+ isDirty(): boolean {
392
+ return this.#workingCopy !== null || this.#workingCopyGetter !== null;
393
+ }
394
+
395
+ isKnownThirdParty(): boolean {
396
+ return this.#isKnownThirdParty;
397
+ }
398
+
399
+ markKnownThirdParty(): void {
400
+ this.#isKnownThirdParty = true;
401
+ }
402
+
403
+ /**
404
+ * {@link markAsUnconditionallyIgnoreListed}
405
+ */
406
+ isUnconditionallyIgnoreListed(): boolean {
407
+ return this.#isUnconditionallyIgnoreListed;
408
+ }
409
+
410
+ isFetchXHR(): boolean {
411
+ return [Common.ResourceType.resourceTypes.XHR, Common.ResourceType.resourceTypes.Fetch].includes(
412
+ this.contentType());
413
+ }
414
+
415
+ /**
416
+ * Unconditionally ignore list this UISourcecode, ignoring any user
417
+ * setting. We use this to mark breakpoint/logpoint condition scripts for now.
418
+ */
419
+ markAsUnconditionallyIgnoreListed(): void {
420
+ this.#isUnconditionallyIgnoreListed = true;
421
+ }
422
+
423
+ extension(): string {
424
+ return Common.ParsedURL.ParsedURL.extractExtension(this.#name);
425
+ }
426
+
427
+ content(): string {
428
+ if (!this.#content || 'error' in this.#content) {
429
+ return '';
430
+ }
431
+ return this.#content.text;
432
+ }
433
+
434
+ loadError(): string|null {
435
+ return (this.#content && 'error' in this.#content && this.#content.error) || null;
436
+ }
437
+
438
+ searchInContent(query: string, caseSensitive: boolean, isRegex: boolean):
439
+ Promise<TextUtils.ContentProvider.SearchMatch[]> {
440
+ if (!this.#content || 'error' in this.#content) {
441
+ return this.#project.searchInFileContent(this, query, caseSensitive, isRegex);
442
+ }
443
+ return Promise.resolve(
444
+ TextUtils.TextUtils.performSearchInContentData(this.#content, query, caseSensitive, isRegex));
445
+ }
446
+
447
+ contentLoaded(): boolean {
448
+ return Boolean(this.#content);
449
+ }
450
+
451
+ uiLocation(lineNumber: number, columnNumber?: number): UILocation {
452
+ return new UILocation(this, lineNumber, columnNumber);
453
+ }
454
+
455
+ messages(): Set<Message> {
456
+ return this.#messages ? new Set(this.#messages) : new Set();
457
+ }
458
+
459
+ addLineMessage(
460
+ level: Message.Level, text: string, lineNumber: number, columnNumber?: number,
461
+ clickHandler?: (() => void)): Message {
462
+ const range = TextUtils.TextRange.TextRange.createFromLocation(lineNumber, columnNumber || 0);
463
+ const message = new Message(level, text, clickHandler, range);
464
+ this.addMessage(message);
465
+ return message;
466
+ }
467
+
468
+ addMessage(message: Message): void {
469
+ if (!this.#messages) {
470
+ this.#messages = new Set();
471
+ }
472
+ this.#messages.add(message);
473
+ this.dispatchEventToListeners(Events.MessageAdded, message);
474
+ }
475
+
476
+ removeMessage(message: Message): void {
477
+ if (this.#messages?.delete(message)) {
478
+ this.dispatchEventToListeners(Events.MessageRemoved, message);
479
+ }
480
+ }
481
+
482
+ #removeAllMessages(): void {
483
+ if (!this.#messages) {
484
+ return;
485
+ }
486
+ for (const message of this.#messages) {
487
+ this.dispatchEventToListeners(Events.MessageRemoved, message);
488
+ }
489
+ this.#messages = null;
490
+ }
491
+
492
+ setDecorationData(type: string, data: any): void {
493
+ if (data !== this.#decorations.get(type)) {
494
+ this.#decorations.set(type, data);
495
+ this.dispatchEventToListeners(Events.DecorationChanged, type);
496
+ }
497
+ }
498
+
499
+ getDecorationData(type: string): any {
500
+ return this.#decorations.get(type);
501
+ }
502
+
503
+ disableEdit(): void {
504
+ this.#disableEdit = true;
505
+ }
506
+
507
+ editDisabled(): boolean {
508
+ return this.#disableEdit;
509
+ }
510
+
511
+ isIgnoreListed(): boolean {
512
+ return IgnoreListManager.instance().isUserOrSourceMapIgnoreListedUISourceCode(this);
513
+ }
514
+ }
515
+
516
+ export enum Events {
517
+ /* eslint-disable @typescript-eslint/naming-convention -- Used by web_tests. */
518
+ WorkingCopyChanged = 'WorkingCopyChanged',
519
+ WorkingCopyCommitted = 'WorkingCopyCommitted',
520
+ TitleChanged = 'TitleChanged',
521
+ MessageAdded = 'MessageAdded',
522
+ MessageRemoved = 'MessageRemoved',
523
+ DecorationChanged = 'DecorationChanged',
524
+ /* eslint-enable @typescript-eslint/naming-convention */
525
+ }
526
+
527
+ export interface WorkingCopyCommittedEvent {
528
+ uiSourceCode: UISourceCode;
529
+ content: string;
530
+ encoded: boolean|undefined;
531
+ }
532
+
533
+ export interface EventTypes {
534
+ [Events.WorkingCopyChanged]: UISourceCode;
535
+ [Events.WorkingCopyCommitted]: WorkingCopyCommittedEvent;
536
+ [Events.TitleChanged]: UISourceCode;
537
+ [Events.MessageAdded]: Message;
538
+ [Events.MessageRemoved]: Message;
539
+ [Events.DecorationChanged]: string;
540
+ }
541
+
542
+ export class UILocation {
543
+ uiSourceCode: UISourceCode;
544
+ lineNumber: number;
545
+ columnNumber: number|undefined;
546
+ constructor(uiSourceCode: UISourceCode, lineNumber: number, columnNumber?: number) {
547
+ this.uiSourceCode = uiSourceCode;
548
+ this.lineNumber = lineNumber;
549
+ this.columnNumber = columnNumber;
550
+ }
551
+
552
+ linkText(skipTrim = false, showColumnNumber = false): string {
553
+ const displayName = this.uiSourceCode.displayName(skipTrim);
554
+ const lineAndColumnText = this.lineAndColumnText(showColumnNumber);
555
+ let text = lineAndColumnText ? displayName + ':' + lineAndColumnText : displayName;
556
+ if (this.uiSourceCode.isDirty()) {
557
+ text = '*' + text;
558
+ }
559
+ return text;
560
+ }
561
+
562
+ lineAndColumnText(showColumnNumber = false): string|undefined {
563
+ let lineAndColumnText;
564
+ if (this.uiSourceCode.mimeType() === 'application/wasm') {
565
+ // For WebAssembly locations, we follow the conventions described in
566
+ // github.com/WebAssembly/design/blob/master/Web.md#developer-facing-display-conventions
567
+ if (typeof this.columnNumber === 'number') {
568
+ lineAndColumnText = `0x${this.columnNumber.toString(16)}`;
569
+ }
570
+ } else {
571
+ lineAndColumnText = `${this.lineNumber + 1}`;
572
+ if (showColumnNumber && typeof this.columnNumber === 'number') {
573
+ lineAndColumnText += ':' + (this.columnNumber + 1);
574
+ }
575
+ }
576
+ return lineAndColumnText;
577
+ }
578
+
579
+ id(): string {
580
+ if (typeof this.columnNumber === 'number') {
581
+ return this.uiSourceCode.project().id() + ':' + this.uiSourceCode.url() + ':' + this.lineNumber + ':' +
582
+ this.columnNumber;
583
+ }
584
+ return this.lineId();
585
+ }
586
+
587
+ lineId(): string {
588
+ return this.uiSourceCode.project().id() + ':' + this.uiSourceCode.url() + ':' + this.lineNumber;
589
+ }
590
+
591
+ static comparator(location1: UILocation, location2: UILocation): number {
592
+ return location1.compareTo(location2);
593
+ }
594
+
595
+ compareTo(other: UILocation): number {
596
+ if (this.uiSourceCode.url() !== other.uiSourceCode.url()) {
597
+ return this.uiSourceCode.url() > other.uiSourceCode.url() ? 1 : -1;
598
+ }
599
+ if (this.lineNumber !== other.lineNumber) {
600
+ return this.lineNumber - other.lineNumber;
601
+ }
602
+ // We consider `undefined` less than an actual column number, since
603
+ // UI location without a column number corresponds to the whole line.
604
+ if (this.columnNumber === other.columnNumber) {
605
+ return 0;
606
+ }
607
+ if (typeof this.columnNumber !== 'number') {
608
+ return -1;
609
+ }
610
+ if (typeof other.columnNumber !== 'number') {
611
+ return 1;
612
+ }
613
+ return this.columnNumber - other.columnNumber;
614
+ }
615
+
616
+ isIgnoreListed(): boolean {
617
+ return this.uiSourceCode.isIgnoreListed();
618
+ }
619
+ }
620
+
621
+ /**
622
+ * A text range inside a specific {@link UISourceCode}.
623
+ *
624
+ * We use a class instead of an interface so we can implement a revealer for it.
625
+ */
626
+ export class UILocationRange {
627
+ readonly uiSourceCode: UISourceCode;
628
+ readonly range: TextUtils.TextRange.TextRange;
629
+
630
+ constructor(uiSourceCode: UISourceCode, range: TextUtils.TextRange.TextRange) {
631
+ this.uiSourceCode = uiSourceCode;
632
+ this.range = range;
633
+ }
634
+ }
635
+
636
+ /**
637
+ * A message associated with a range in a `UISourceCode`. The range will be
638
+ * underlined starting at the range's start and ending at the line end (the
639
+ * end of the range is currently disregarded).
640
+ * An icon is going to appear at the end of the line according to the
641
+ * `level` of the Message. This is only the model; displaying is handled
642
+ * where UISourceCode displaying is handled.
643
+ */
644
+ export class Message {
645
+ readonly #level: Message.Level;
646
+ readonly #text: string;
647
+ range: TextUtils.TextRange.TextRange;
648
+ readonly #clickHandler?: (() => void);
649
+
650
+ constructor(level: Message.Level, text: string, clickHandler?: (() => void), range?: TextUtils.TextRange.TextRange) {
651
+ this.#level = level;
652
+ this.#text = text;
653
+ this.range = range ?? new TextUtils.TextRange.TextRange(0, 0, 0, 0);
654
+ this.#clickHandler = clickHandler;
655
+ }
656
+
657
+ level(): Message.Level {
658
+ return this.#level;
659
+ }
660
+
661
+ text(): string {
662
+ return this.#text;
663
+ }
664
+
665
+ clickHandler(): (() => void)|undefined {
666
+ return this.#clickHandler;
667
+ }
668
+
669
+ lineNumber(): number {
670
+ return this.range.startLine;
671
+ }
672
+
673
+ columnNumber(): number|undefined {
674
+ return this.range.startColumn;
675
+ }
676
+
677
+ isEqual(another: Message): boolean {
678
+ return this.text() === another.text() && this.level() === another.level() && this.range.equal(another.range);
679
+ }
680
+ }
681
+
682
+ export namespace Message {
683
+ export const enum Level {
684
+ ERROR = 'Error',
685
+ ISSUE = 'Issue',
686
+ WARNING = 'Warning',
687
+ }
688
+ }
689
+
690
+ export class UISourceCodeMetadata {
691
+ modificationTime: Date|null;
692
+ contentSize: number|null;
693
+
694
+ constructor(modificationTime: Date|null, contentSize: number|null) {
695
+ this.modificationTime = modificationTime;
696
+ this.contentSize = contentSize;
697
+ }
698
+ }