chrome-devtools-frontend
Version:
Chrome DevTools UI
46 lines (39 loc) • 1.83 kB
text/typescript
// Copyright 2023 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 Formatter from '../../models/formatter/formatter.js';
import * as TextUtils from '../../models/text_utils/text_utils.js';
import type {Script} from './Script.js';
type ScopeTreeNode = Formatter.FormatterWorkerPool.ScopeTreeNode;
type Text = TextUtils.Text.Text;
/** If a script failed to parse, we stash null in order to prevent unnecessary re-parsing */
const scopeTrees = new WeakMap<Script, Promise<{scopeTree: ScopeTreeNode, text: Text}|null>>();
/**
* Computes and caches the scope tree for `script`.
*
* We use {@link Script} as a key to uniquely identify scripts.
* {@link Script} boils down to "target" + "script ID". This
* duplicates work in case of identical script running on multiple targets
* (e.g. workers).
*
* We also return a {@link TextUtils.Text.Text} instance. The scope tree uses offsets
* and the text allows conversion from/to line/column numbers.
*/
export function scopeTreeForScript(script: Script): Promise<{scopeTree: ScopeTreeNode, text: Text}|null> {
let promise = scopeTrees.get(script);
if (promise === undefined) {
promise = script.requestContentData().then(content => {
if (TextUtils.ContentData.ContentData.isError(content)) {
return null;
}
const sourceType = script.isModule ? 'module' : 'script';
return Formatter.FormatterWorkerPool.formatterWorkerPool()
.javaScriptScopeTree(content.text, sourceType)
.then(scopeTree => scopeTree ? ({scopeTree, text: content.textObj}) : null)
.catch(() => null);
});
scopeTrees.set(script, promise);
}
// We intentionally return `null` here if the script already failed to parse once.
return promise;
}