mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-10-10 21:54:47 +08:00
Some native functions don't have names in their toString, so now we use the identifier the user typed in as a fallback. Change-Id: I79ad4e630a39ff23a109485ea5afded9d660d54e Reviewed-on: https://chromium-review.googlesource.com/1063037 Reviewed-by: Andrey Lushnikov <lushnikov@chromium.org> Commit-Queue: Joel Einbinder <einbinder@chromium.org> Cr-Original-Commit-Position: refs/heads/master@{#559392} Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: 8c78c1f97014e7e249a522342890f0b9fbc2efba
388 lines
11 KiB
JavaScript
388 lines
11 KiB
JavaScript
// Copyright 2016 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.
|
|
/**
|
|
* @unrestricted
|
|
*/
|
|
Formatter.FormatterWorkerPool = class {
|
|
constructor() {
|
|
this._taskQueue = [];
|
|
/** @type {!Map<!Common.Worker, ?Formatter.FormatterWorkerPool.Task>} */
|
|
this._workerTasks = new Map();
|
|
}
|
|
|
|
/**
|
|
* @return {!Common.Worker}
|
|
*/
|
|
_createWorker() {
|
|
const worker = new Common.Worker('formatter_worker');
|
|
worker.onmessage = this._onWorkerMessage.bind(this, worker);
|
|
worker.onerror = this._onWorkerError.bind(this, worker);
|
|
return worker;
|
|
}
|
|
|
|
_processNextTask() {
|
|
if (!this._taskQueue.length)
|
|
return;
|
|
|
|
let freeWorker = this._workerTasks.keysArray().find(worker => !this._workerTasks.get(worker));
|
|
if (!freeWorker && this._workerTasks.size < Formatter.FormatterWorkerPool.MaxWorkers)
|
|
freeWorker = this._createWorker();
|
|
if (!freeWorker)
|
|
return;
|
|
|
|
const task = this._taskQueue.shift();
|
|
this._workerTasks.set(freeWorker, task);
|
|
freeWorker.postMessage({method: task.method, params: task.params});
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Worker} worker
|
|
* @param {!MessageEvent} event
|
|
*/
|
|
_onWorkerMessage(worker, event) {
|
|
const task = this._workerTasks.get(worker);
|
|
if (task.isChunked && event.data && !event.data['isLastChunk']) {
|
|
task.callback(event.data);
|
|
return;
|
|
}
|
|
|
|
this._workerTasks.set(worker, null);
|
|
this._processNextTask();
|
|
task.callback(event.data ? event.data : null);
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Worker} worker
|
|
* @param {!Event} event
|
|
*/
|
|
_onWorkerError(worker, event) {
|
|
console.error(event);
|
|
const task = this._workerTasks.get(worker);
|
|
worker.terminate();
|
|
this._workerTasks.delete(worker);
|
|
|
|
const newWorker = this._createWorker();
|
|
this._workerTasks.set(newWorker, null);
|
|
this._processNextTask();
|
|
task.callback(null);
|
|
}
|
|
|
|
/**
|
|
* @param {string} methodName
|
|
* @param {!Object<string, string>} params
|
|
* @param {function(boolean, *)} callback
|
|
*/
|
|
_runChunkedTask(methodName, params, callback) {
|
|
const task = new Formatter.FormatterWorkerPool.Task(methodName, params, onData, true);
|
|
this._taskQueue.push(task);
|
|
this._processNextTask();
|
|
|
|
/**
|
|
* @param {?Object} data
|
|
*/
|
|
function onData(data) {
|
|
if (!data) {
|
|
callback(true, null);
|
|
return;
|
|
}
|
|
const isLastChunk = !!data['isLastChunk'];
|
|
const chunk = data['chunk'];
|
|
callback(isLastChunk, chunk);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {string} methodName
|
|
* @param {!Object<string, string>} params
|
|
* @return {!Promise<*>}
|
|
*/
|
|
_runTask(methodName, params) {
|
|
let callback;
|
|
const promise = new Promise(fulfill => callback = fulfill);
|
|
const task = new Formatter.FormatterWorkerPool.Task(methodName, params, callback, false);
|
|
this._taskQueue.push(task);
|
|
this._processNextTask();
|
|
return promise;
|
|
}
|
|
|
|
/**
|
|
* @param {string} content
|
|
* @return {!Promise<*>}
|
|
*/
|
|
parseJSONRelaxed(content) {
|
|
return this._runTask('parseJSONRelaxed', {content: content});
|
|
}
|
|
|
|
/**
|
|
* @param {string} content
|
|
* @return {!Promise<!Array<!Formatter.FormatterWorkerPool.SCSSRule>>}
|
|
*/
|
|
parseSCSS(content) {
|
|
return this._runTask('parseSCSS', {content: content}).then(rules => rules || []);
|
|
}
|
|
|
|
/**
|
|
* @param {string} mimeType
|
|
* @param {string} content
|
|
* @param {string} indentString
|
|
* @return {!Promise<!Formatter.FormatterWorkerPool.FormatResult>}
|
|
*/
|
|
format(mimeType, content, indentString) {
|
|
const parameters = {mimeType: mimeType, content: content, indentString: indentString};
|
|
return /** @type {!Promise<!Formatter.FormatterWorkerPool.FormatResult>} */ (this._runTask('format', parameters));
|
|
}
|
|
|
|
/**
|
|
* @param {string} content
|
|
* @return {!Promise<!Array<!{name: string, offset: number}>>}
|
|
*/
|
|
javaScriptIdentifiers(content) {
|
|
return this._runTask('javaScriptIdentifiers', {content: content}).then(ids => ids || []);
|
|
}
|
|
|
|
/**
|
|
* @param {string} content
|
|
* @return {!Promise<string>}
|
|
*/
|
|
evaluatableJavaScriptSubstring(content) {
|
|
return this._runTask('evaluatableJavaScriptSubstring', {content: content}).then(text => text || '');
|
|
}
|
|
|
|
/**
|
|
* @param {string} content
|
|
* @return {!Promise<string>}
|
|
*/
|
|
preprocessTopLevelAwaitExpressions(content) {
|
|
return this._runTask('preprocessTopLevelAwaitExpressions', {content: content}).then(text => text || '');
|
|
}
|
|
|
|
/**
|
|
* @param {string} content
|
|
* @param {function(boolean, !Array<!Formatter.FormatterWorkerPool.CSSRule>)} callback
|
|
*/
|
|
parseCSS(content, callback) {
|
|
this._runChunkedTask('parseCSS', {content: content}, onDataChunk);
|
|
|
|
/**
|
|
* @param {boolean} isLastChunk
|
|
* @param {*} data
|
|
*/
|
|
function onDataChunk(isLastChunk, data) {
|
|
const rules = /** @type {!Array<!Formatter.FormatterWorkerPool.CSSRule>} */ (data || []);
|
|
callback(isLastChunk, rules);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {string} content
|
|
* @param {function(boolean, !Array<!Formatter.FormatterWorkerPool.JSOutlineItem>)} callback
|
|
*/
|
|
javaScriptOutline(content, callback) {
|
|
this._runChunkedTask('javaScriptOutline', {content: content}, onDataChunk);
|
|
|
|
/**
|
|
* @param {boolean} isLastChunk
|
|
* @param {*} data
|
|
*/
|
|
function onDataChunk(isLastChunk, data) {
|
|
const items = /** @type {!Array.<!Formatter.FormatterWorkerPool.JSOutlineItem>} */ (data || []);
|
|
callback(isLastChunk, items);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {string} content
|
|
* @param {string} mimeType
|
|
* @param {function(boolean, !Array<!Formatter.FormatterWorkerPool.OutlineItem>)} callback
|
|
* @return {boolean}
|
|
*/
|
|
outlineForMimetype(content, mimeType, callback) {
|
|
switch (mimeType) {
|
|
case 'text/html':
|
|
case 'text/javascript':
|
|
this.javaScriptOutline(content, javaScriptCallback);
|
|
return true;
|
|
case 'text/css':
|
|
this.parseCSS(content, cssCallback);
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
/**
|
|
* @param {boolean} isLastChunk
|
|
* @param {!Array<!Formatter.FormatterWorkerPool.JSOutlineItem>} items
|
|
*/
|
|
function javaScriptCallback(isLastChunk, items) {
|
|
callback(
|
|
isLastChunk,
|
|
items.map(item => ({line: item.line, column: item.column, title: item.name, subtitle: item.arguments})));
|
|
}
|
|
|
|
/**
|
|
* @param {boolean} isLastChunk
|
|
* @param {!Array<!Formatter.FormatterWorkerPool.CSSRule>} rules
|
|
*/
|
|
function cssCallback(isLastChunk, rules) {
|
|
callback(
|
|
isLastChunk,
|
|
rules.map(
|
|
rule => ({line: rule.lineNumber, column: rule.columnNumber, title: rule.selectorText || rule.atRule})));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {string} content
|
|
* @return {!Promise<?{baseExpression: string, possibleSideEffects:boolean}>}
|
|
*/
|
|
findLastExpression(content) {
|
|
return /** @type {!Promise<?{baseExpression: string, possibleSideEffects:boolean}>} */ (
|
|
this._runTask('findLastExpression', {content}));
|
|
}
|
|
|
|
/**
|
|
* @param {string} content
|
|
* @return {!Promise<?{baseExpression: string, possibleSideEffects:boolean, receiver: string, argumentIndex: number, functionName: string}>}
|
|
*/
|
|
findLastFunctionCall(content) {
|
|
return /** @type {!Promise<?{baseExpression: string, possibleSideEffects:boolean, receiver: string, argumentIndex: number, functionName: string}>} */ (
|
|
this._runTask('findLastFunctionCall', {content}));
|
|
}
|
|
|
|
/**
|
|
* @param {string} content
|
|
* @return {!Promise<!Array<string>>}
|
|
*/
|
|
argumentsList(content) {
|
|
return /** @type {!Promise<!Array<string>>} */ (this._runTask('argumentsList', {content}));
|
|
}
|
|
};
|
|
|
|
Formatter.FormatterWorkerPool.MaxWorkers = 2;
|
|
|
|
/**
|
|
* @unrestricted
|
|
*/
|
|
Formatter.FormatterWorkerPool.Task = class {
|
|
/**
|
|
* @param {string} method
|
|
* @param {!Object<string, string>} params
|
|
* @param {function(?MessageEvent)} callback
|
|
* @param {boolean=} isChunked
|
|
*/
|
|
constructor(method, params, callback, isChunked) {
|
|
this.method = method;
|
|
this.params = params;
|
|
this.callback = callback;
|
|
this.isChunked = isChunked;
|
|
}
|
|
};
|
|
|
|
Formatter.FormatterWorkerPool.FormatResult = class {
|
|
constructor() {
|
|
/** @type {string} */
|
|
this.content;
|
|
/** @type {!Formatter.FormatterWorkerPool.FormatMapping} */
|
|
this.mapping;
|
|
}
|
|
};
|
|
|
|
/** @typedef {{original: !Array<number>, formatted: !Array<number>}} */
|
|
Formatter.FormatterWorkerPool.FormatMapping;
|
|
|
|
/** @typedef {{line: number, column: number, title: string, subtitle: (string|undefined) }} */
|
|
Formatter.FormatterWorkerPool.OutlineItem;
|
|
|
|
Formatter.FormatterWorkerPool.JSOutlineItem = class {
|
|
constructor() {
|
|
/** @type {string} */
|
|
this.name;
|
|
/** @type {(string|undefined)} */
|
|
this.arguments;
|
|
/** @type {number} */
|
|
this.line;
|
|
/** @type {number} */
|
|
this.column;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @typedef {{startLine: number, startColumn: number, endLine: number, endColumn: number}}
|
|
*/
|
|
Formatter.FormatterWorkerPool.TextRange;
|
|
|
|
Formatter.FormatterWorkerPool.CSSProperty = class {
|
|
constructor() {
|
|
/** @type {string} */
|
|
this.name;
|
|
/** @type {!Formatter.FormatterWorkerPool.TextRange} */
|
|
this.nameRange;
|
|
/** @type {string} */
|
|
this.value;
|
|
/** @type {!Formatter.FormatterWorkerPool.TextRange} */
|
|
this.valueRange;
|
|
/** @type {!Formatter.FormatterWorkerPool.TextRange} */
|
|
this.range;
|
|
/** @type {(boolean|undefined)} */
|
|
this.disabled;
|
|
}
|
|
};
|
|
|
|
Formatter.FormatterWorkerPool.CSSStyleRule = class {
|
|
constructor() {
|
|
/** @type {string} */
|
|
this.selectorText;
|
|
/** @type {!Formatter.FormatterWorkerPool.TextRange} */
|
|
this.styleRange;
|
|
/** @type {number} */
|
|
this.lineNumber;
|
|
/** @type {number} */
|
|
this.columnNumber;
|
|
/** @type {!Array.<!Formatter.FormatterWorkerPool.CSSProperty>} */
|
|
this.properties;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @typedef {{atRule: string, lineNumber: number, columnNumber: number}}
|
|
*/
|
|
Formatter.FormatterWorkerPool.CSSAtRule;
|
|
|
|
/**
|
|
* @typedef {(Formatter.FormatterWorkerPool.CSSStyleRule|Formatter.FormatterWorkerPool.CSSAtRule)}
|
|
*/
|
|
Formatter.FormatterWorkerPool.CSSRule;
|
|
|
|
Formatter.FormatterWorkerPool.SCSSProperty = class {
|
|
constructor() {
|
|
/** @type {!Formatter.FormatterWorkerPool.TextRange} */
|
|
this.range;
|
|
/** @type {!Formatter.FormatterWorkerPool.TextRange} */
|
|
this.name;
|
|
/** @type {!Formatter.FormatterWorkerPool.TextRange} */
|
|
this.value;
|
|
/** @type {boolean} */
|
|
this.disabled;
|
|
}
|
|
};
|
|
|
|
Formatter.FormatterWorkerPool.SCSSRule = class {
|
|
constructor() {
|
|
/** @type {!Array<!Formatter.FormatterWorkerPool.TextRange>} */
|
|
this.selectors;
|
|
/** @type {!Array<!Formatter.FormatterWorkerPool.SCSSProperty>} */
|
|
this.properties;
|
|
/** @type {!Formatter.FormatterWorkerPool.TextRange} */
|
|
this.styleRange;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @return {!Formatter.FormatterWorkerPool}
|
|
*/
|
|
Formatter.formatterWorkerPool = function() {
|
|
if (!Formatter._formatterWorkerPool)
|
|
Formatter._formatterWorkerPool = new Formatter.FormatterWorkerPool();
|
|
return Formatter._formatterWorkerPool;
|
|
};
|