(
function (factory) {
typeof define ===
'function' && define.amd ? define(factory) :
factory();
})((
function () {
'use strict';
(
function() {
const env = {
"NODE_ENV":
"production"};
try {
if (process) {
process.env = Object.assign({}, process.env);
Object.assign(process.env, env);
return;
}
}
catch (e) {}
// avoid ReferenceError: process is not defined
globalThis.process = { env:env };
})();
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
function isNode() {
try {
return process.release.name ==
"node";
}
catch (e) {
return false;
}
}
function isNodeTest() {
return isNode() && process.env.NODE_ENV !=
"production";
}
let
assert;
// TODO: try to enable these assertions on mochitest by also enabling it on:
// import flags from "devtools/shared/flags";
// if (flags.testing)
// Unfortunately it throws a lot on mochitests...
if (isNodeTest()) {
assert =
function (condition, message) {
if (!condition) {
throw new Error(`Assertion failure: ${message}`);
}
};
}
else {
assert =
function () {};
}
var assert$1 =
assert;
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
function escapeRegExp(str) {
const reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
return str.replace(reRegExpChar,
"\\$&");
}
/**
* Ignore doing outline matches for less than 3 whitespaces
*
* @memberof utils/source-search
* @static
*/
function ignoreWhiteSpace(str) {
return /^\s{0,2}$/.test(str) ?
"(?!\\s*.*)" : str;
}
function wholeMatch(query, wholeWord) {
if (query ===
"" || !wholeWord) {
return query;
}
return `\\b${query}\\b`;
}
function buildFlags(caseSensitive, isGlobal) {
if (caseSensitive && isGlobal) {
return "g";
}
if (!caseSensitive && isGlobal) {
return "gi";
}
if (!caseSensitive && !isGlobal) {
return "i";
}
return null;
}
function buildQuery(
originalQuery,
modifiers,
{ isGlobal =
false, ignoreSpaces =
false }
) {
const { caseSensitive, regexMatch, wholeWord } = modifiers;
if (originalQuery ===
"") {
return new RegExp(originalQuery);
}
// Remove the backslashes at the end of the query as it
// breaks the RegExp
let query = originalQuery.replace(/\\$/,
"");
// If we don't want to do a regexMatch, we need to escape all regex related characters
// so they would actually match.
if (!regexMatch) {
query = escapeRegExp(query);
}
// ignoreWhiteSpace might return a negative lookbehind, and in such case, we want it
// to be consumed as a RegExp part by the callsite, so this needs to be called after
// the regexp is escaped.
if (ignoreSpaces) {
query = ignoreWhiteSpace(query);
}
query = wholeMatch(query, wholeWord);
const flags = buildFlags(caseSensitive, isGlobal);
if (flags) {
return new RegExp(query, flags);
}
return new RegExp(query);
}
function getMatches(query, text, options) {
if (!query || !text || !options) {
return [];
}
const regexQuery = buildQuery(query, options, {
isGlobal:
true,
});
const matchedLocations = [];
const lines = text.split(
"\n");
for (let i = 0; i < lines.length; i++) {
let singleMatch;
const line = lines[i];
while ((singleMatch = regexQuery.exec(line)) !==
null) {
// Flow doesn't understand the test above.
if (!singleMatch) {
throw new Error(
"no singleMatch");
}
matchedLocations.push({
line: i,
ch: singleMatch.index,
match: singleMatch[0],
});
// When the match is an empty string the regexQuery.lastIndex will not
// change resulting in an infinite loop so we need to check for this and
// increment it manually in that case. See issue #7023
if (singleMatch[0] ===
"") {
assert$1(
!regexQuery.unicode,
"lastIndex++ can cause issues in unicode mode"
);
regexQuery.lastIndex++;
}
}
}
return matchedLocations;
}
function findSourceMatches(content, queryText, options) {
if (queryText ==
"") {
return [];
}
const text = content.value;
const lines = text.split(
"\n");
return getMatches(queryText, text, options).map(({ line, ch, match }) => {
const { value, matchIndex } = truncateLine(lines[line], ch);
return {
line: line + 1,
column: ch,
matchIndex,
match,
value,
};
});
}
// This is used to find start of a word, so that cropped string look nice
const startRegex = /([ !@#$%^&*()_+\-=\[\]{};
':"\\|,.<>\/?])/g;
// Similarly, find
const endRegex =
new RegExp(
[
"([ !@#$%^&*()_+-=[]{};':\"\\|,.<>/?])
",
'[^ !@#$%^&*()_+-=[]{};\':
"\\|,.<>/?]*$"/
',
].join(
"")
);
// For texts over 100 characters this truncates the text (for display)
// around the context of the matched text.
function truncateLine(text, column) {
if (text.length < 100) {
return {
matchIndex: column,
value: text,
};
}
// Initially take 40 chars left to the match
const offset = Math.max(column - 40, 0);
// 400 characters should be enough to figure out the context of the match
const truncStr = text.slice(offset, column + 400);
let start = truncStr.search(startRegex);
let end = truncStr.search(endRegex);
if (start > column) {
// No word separator found before the match, so we take all characters
// before the match
start = -1;
}
if (end < column) {
end = truncStr.length;
}
const value = truncStr.slice(start + 1, end);
return {
matchIndex: column - start - offset - 1,
value,
};
}
var workerUtils = {exports: {}};
var hasRequiredWorkerUtils;
function requireWorkerUtils () {
if (hasRequiredWorkerUtils)
return workerUtils.exports;
hasRequiredWorkerUtils = 1;
(
function (module) {
class WorkerDispatcher {
#msgId = 1;
#worker =
null;
// Map of message ids -> promise resolution functions, for dispatching worker responses
#pendingCalls =
new Map();
#url =
"";
constructor(url) {
this.#url = url;
}
start() {
// When running in debugger jest test, we don't have access to ChromeWorker
if (
typeof ChromeWorker ==
"function") {
this.#worker =
new ChromeWorker(
this.#url);
}
else {
this.#worker =
new Worker(
this.#url);
}
this.#worker.onerror = err => {
console.error(`Error in worker ${
this.#url}`, err.message);
};
this.#worker.addEventListener(
"message",
this.#onMessage);
}
stop() {
if (!
this.#worker) {
return;
}
this.#worker.removeEventListener(
"message",
this.#onMessage);
this.#worker.terminate();
this.#worker =
null;
this.#pendingCalls.clear();
}
task(method, { queue =
false } = {}) {
const calls = [];
const push = args => {
return new Promise((resolve, reject) => {
if (queue && calls.length === 0) {
Promise.resolve().then(flush);
}
calls.push({ args, resolve, reject });
if (!queue) {
flush();
}
});
};
const flush = () => {
const items = calls.slice();
calls.length = 0;
if (!
this.#worker) {
this.start();
}
const id =
this.#msgId++;
this.#worker.postMessage({
id,
method,
calls: items.map(item => item.args),
});
this.#pendingCalls.set(id, items);
};
return (...args) => push(args);
}
invoke(method, ...args) {
return this.task(method)(...args);
}
#onMessage = ({ data: result }) => {
const items =
this.#pendingCalls.get(result.id);
this.#pendingCalls.
delete(result.id);
if (!items) {
return;
}
if (!
this.#worker) {
return;
}
result.results.forEach((resultData, i) => {
const { resolve, reject } = items[i];
if (resultData.error) {
const err =
new Error(resultData.message);
err.metadata = resultData.metadata;
reject(err);
}
else {
resolve(resultData.response);
}
});
};
}
function workerHandler(publicInterface) {
return function (msg) {
const { id, method, calls } = msg.data;
Promise.all(
calls.map(args => {
try {
const response = publicInterface[method].apply(undefined, args);
if (response
instanceof Promise) {
return response.then(
val => ({ response: val }),
err => asErrorMessage(err)
);
}
return { response };
}
catch (error) {
return asErrorMessage(error);
}
})
).then(results => {
globalThis.postMessage({ id, results });
});
};
}
function asErrorMessage(error) {
if (
typeof error ===
"object" && error &&
"message" in error) {
// Error can't be sent via postMessage, so be sure to convert to
// string.
return {
error:
true,
message:
error.message +
(error.stack ?
"\nStack in the worker:" + error.stack :
""),
metadata: error.metadata,
};
}
return {
error:
true,
message: error ==
null ? error : error.toString(),
metadata: undefined,
};
}
// Might be loaded within a worker thread where `module` isn't available.
{
module.exports = {
WorkerDispatcher,
workerHandler,
};
}
} (workerUtils));
return workerUtils.exports;
}
var workerUtilsExports = requireWorkerUtils();
self.onmessage = workerUtilsExports.workerHandler({ getMatches, findSourceMatches });
}));