UNPKG

@lvce-editor/file-search-worker

Version:

Web worker for file search backends in LVCE Editor.

1,271 lines (1,225 loc) 32.1 kB
const normalizeLine = line => { if (line.startsWith('Error: ')) { return line.slice('Error: '.length); } if (line.startsWith('VError: ')) { return line.slice('VError: '.length); } return line; }; const getCombinedMessage = (error, message) => { const stringifiedError = normalizeLine(`${error}`); if (message) { return `${message}: ${stringifiedError}`; } return stringifiedError; }; const NewLine$2 = '\n'; const getNewLineIndex$1 = (string, startIndex = undefined) => { return string.indexOf(NewLine$2, startIndex); }; const mergeStacks = (parent, child) => { if (!child) { return parent; } const parentNewLineIndex = getNewLineIndex$1(parent); const childNewLineIndex = getNewLineIndex$1(child); if (childNewLineIndex === -1) { return parent; } const parentFirstLine = parent.slice(0, parentNewLineIndex); const childRest = child.slice(childNewLineIndex); const childFirstLine = normalizeLine(child.slice(0, childNewLineIndex)); if (parentFirstLine.includes(childFirstLine)) { return parentFirstLine + childRest; } return child; }; class VError extends Error { constructor(error, message) { const combinedMessage = getCombinedMessage(error, message); super(combinedMessage); this.name = 'VError'; if (error instanceof Error) { this.stack = mergeStacks(this.stack, error.stack); } if (error.codeFrame) { // @ts-ignore this.codeFrame = error.codeFrame; } if (error.code) { // @ts-ignore this.code = error.code; } } } const isMessagePort = value => { return value && value instanceof MessagePort; }; const isMessagePortMain = value => { return value && value.constructor && value.constructor.name === 'MessagePortMain'; }; const isOffscreenCanvas = value => { return typeof OffscreenCanvas !== 'undefined' && value instanceof OffscreenCanvas; }; const isInstanceOf = (value, constructorName) => { return value?.constructor?.name === constructorName; }; const isSocket = value => { return isInstanceOf(value, 'Socket'); }; const transferrables = [isMessagePort, isMessagePortMain, isOffscreenCanvas, isSocket]; const isTransferrable = value => { for (const fn of transferrables) { if (fn(value)) { return true; } } return false; }; const walkValue = (value, transferrables, isTransferrable) => { if (!value) { return; } if (isTransferrable(value)) { transferrables.push(value); return; } if (Array.isArray(value)) { for (const item of value) { walkValue(item, transferrables, isTransferrable); } return; } if (typeof value === 'object') { for (const property of Object.values(value)) { walkValue(property, transferrables, isTransferrable); } } }; const getTransferrables = value => { const transferrables = []; walkValue(value, transferrables, isTransferrable); return transferrables; }; const attachEvents = that => { const handleMessage = (...args) => { const data = that.getData(...args); that.dispatchEvent(new MessageEvent('message', { data })); }; that.onMessage(handleMessage); const handleClose = event => { that.dispatchEvent(new Event('close')); }; that.onClose(handleClose); }; class Ipc extends EventTarget { constructor(rawIpc) { super(); this._rawIpc = rawIpc; attachEvents(this); } } const E_INCOMPATIBLE_NATIVE_MODULE = 'E_INCOMPATIBLE_NATIVE_MODULE'; const E_MODULES_NOT_SUPPORTED_IN_ELECTRON = 'E_MODULES_NOT_SUPPORTED_IN_ELECTRON'; const ERR_MODULE_NOT_FOUND = 'ERR_MODULE_NOT_FOUND'; const NewLine$1 = '\n'; const joinLines$1 = lines => { return lines.join(NewLine$1); }; const RE_AT = /^\s+at/; const RE_AT_PROMISE_INDEX = /^\s*at async Promise.all \(index \d+\)$/; const isNormalStackLine = line => { return RE_AT.test(line) && !RE_AT_PROMISE_INDEX.test(line); }; const getDetails = lines => { const index = lines.findIndex(isNormalStackLine); if (index === -1) { return { actualMessage: joinLines$1(lines), rest: [] }; } let lastIndex = index - 1; while (++lastIndex < lines.length) { if (!isNormalStackLine(lines[lastIndex])) { break; } } return { actualMessage: lines[index - 1], rest: lines.slice(index, lastIndex) }; }; const splitLines$2 = lines => { return lines.split(NewLine$1); }; const RE_MESSAGE_CODE_BLOCK_START = /^Error: The module '.*'$/; const RE_MESSAGE_CODE_BLOCK_END = /^\s* at/; const isMessageCodeBlockStartIndex = line => { return RE_MESSAGE_CODE_BLOCK_START.test(line); }; const isMessageCodeBlockEndIndex = line => { return RE_MESSAGE_CODE_BLOCK_END.test(line); }; const getMessageCodeBlock = stderr => { const lines = splitLines$2(stderr); const startIndex = lines.findIndex(isMessageCodeBlockStartIndex); const endIndex = startIndex + lines.slice(startIndex).findIndex(isMessageCodeBlockEndIndex, startIndex); const relevantLines = lines.slice(startIndex, endIndex); const relevantMessage = relevantLines.join(' ').slice('Error: '.length); return relevantMessage; }; const isModuleNotFoundMessage = line => { return line.includes('[ERR_MODULE_NOT_FOUND]'); }; const getModuleNotFoundError = stderr => { const lines = splitLines$2(stderr); const messageIndex = lines.findIndex(isModuleNotFoundMessage); const message = lines[messageIndex]; return { code: ERR_MODULE_NOT_FOUND, message }; }; const isModuleNotFoundError = stderr => { if (!stderr) { return false; } return stderr.includes('ERR_MODULE_NOT_FOUND'); }; const isModulesSyntaxError = stderr => { if (!stderr) { return false; } return stderr.includes('SyntaxError: Cannot use import statement outside a module'); }; const RE_NATIVE_MODULE_ERROR = /^innerError Error: Cannot find module '.*.node'/; const RE_NATIVE_MODULE_ERROR_2 = /was compiled against a different Node.js version/; const isUnhelpfulNativeModuleError = stderr => { return RE_NATIVE_MODULE_ERROR.test(stderr) && RE_NATIVE_MODULE_ERROR_2.test(stderr); }; const getNativeModuleErrorMessage = stderr => { const message = getMessageCodeBlock(stderr); return { code: E_INCOMPATIBLE_NATIVE_MODULE, message: `Incompatible native node module: ${message}` }; }; const getModuleSyntaxError = () => { return { code: E_MODULES_NOT_SUPPORTED_IN_ELECTRON, message: `ES Modules are not supported in electron` }; }; const getHelpfulChildProcessError = (stdout, stderr) => { if (isUnhelpfulNativeModuleError(stderr)) { return getNativeModuleErrorMessage(stderr); } if (isModulesSyntaxError(stderr)) { return getModuleSyntaxError(); } if (isModuleNotFoundError(stderr)) { return getModuleNotFoundError(stderr); } const lines = splitLines$2(stderr); const { actualMessage, rest } = getDetails(lines); return { code: '', message: actualMessage, stack: rest }; }; class IpcError extends VError { // @ts-ignore constructor(betterMessage, stdout = '', stderr = '') { if (stdout || stderr) { // @ts-ignore const { code, message, stack } = getHelpfulChildProcessError(stdout, stderr); const cause = new Error(message); // @ts-ignore cause.code = code; if (stack) { Object.defineProperty(cause, 'stack', { configurable: true, enumerable: false, value: stack, writable: true }); } super(cause, betterMessage); } else { super(betterMessage); } // @ts-ignore this.name = 'IpcError'; // @ts-ignore this.stdout = stdout; // @ts-ignore this.stderr = stderr; } } const readyMessage = 'ready'; const getData$2 = event => { return event.data; }; const listen$7 = () => { // @ts-ignore if (typeof WorkerGlobalScope === 'undefined') { throw new TypeError('module is not in web worker scope'); } return globalThis; }; const signal$8 = global => { global.postMessage(readyMessage); }; class IpcChildWithModuleWorker extends Ipc { getData(event) { return getData$2(event); } send(message) { // @ts-ignore this._rawIpc.postMessage(message); } sendAndTransfer(message) { const transfer = getTransferrables(message); // @ts-ignore this._rawIpc.postMessage(message, transfer); } dispose() { // ignore } onClose(callback) { // ignore } onMessage(callback) { this._rawIpc.addEventListener('message', callback); } } const wrap$f = global => { return new IpcChildWithModuleWorker(global); }; const waitForFirstMessage = async port => { const { promise, resolve } = Promise.withResolvers(); port.addEventListener('message', resolve, { once: true }); const event = await promise; // @ts-ignore return event.data; }; const listen$6 = async () => { const parentIpcRaw = listen$7(); signal$8(parentIpcRaw); const parentIpc = wrap$f(parentIpcRaw); const firstMessage = await waitForFirstMessage(parentIpc); if (firstMessage.method !== 'initialize') { throw new IpcError('unexpected first message'); } const type = firstMessage.params[0]; if (type === 'message-port') { parentIpc.send({ id: firstMessage.id, jsonrpc: '2.0', result: null }); parentIpc.dispose(); const port = firstMessage.params[1]; return port; } return globalThis; }; class IpcChildWithModuleWorkerAndMessagePort extends Ipc { getData(event) { return getData$2(event); } send(message) { this._rawIpc.postMessage(message); } sendAndTransfer(message) { const transfer = getTransferrables(message); this._rawIpc.postMessage(message, transfer); } dispose() { if (this._rawIpc.close) { this._rawIpc.close(); } } onClose(callback) { // ignore } onMessage(callback) { this._rawIpc.addEventListener('message', callback); this._rawIpc.start(); } } const wrap$e = port => { return new IpcChildWithModuleWorkerAndMessagePort(port); }; const IpcChildWithModuleWorkerAndMessagePort$1 = { __proto__: null, listen: listen$6, wrap: wrap$e }; const addListener = (emitter, type, callback) => { if ('addEventListener' in emitter) { emitter.addEventListener(type, callback); } else { emitter.on(type, callback); } }; const removeListener = (emitter, type, callback) => { if ('removeEventListener' in emitter) { emitter.removeEventListener(type, callback); } else { emitter.off(type, callback); } }; const getFirstEvent = (eventEmitter, eventMap) => { const { promise, resolve } = Promise.withResolvers(); const listenerMap = Object.create(null); const cleanup = value => { for (const event of Object.keys(eventMap)) { removeListener(eventEmitter, event, listenerMap[event]); } resolve(value); }; for (const [event, type] of Object.entries(eventMap)) { const listener = event => { cleanup({ event, type }); }; addListener(eventEmitter, event, listener); listenerMap[event] = listener; } return promise; }; const Message$1 = 3; const create$5$1 = async ({ isMessagePortOpen, messagePort }) => { if (!isMessagePort(messagePort)) { throw new IpcError('port must be of type MessagePort'); } if (isMessagePortOpen) { return messagePort; } const eventPromise = getFirstEvent(messagePort, { message: Message$1 }); messagePort.start(); const { event, type } = await eventPromise; if (type !== Message$1) { throw new IpcError('Failed to wait for ipc message'); } if (event.data !== readyMessage) { throw new IpcError('unexpected first message'); } return messagePort; }; const signal$1 = messagePort => { messagePort.start(); }; class IpcParentWithMessagePort extends Ipc { getData = getData$2; send(message) { this._rawIpc.postMessage(message); } sendAndTransfer(message) { const transfer = getTransferrables(message); this._rawIpc.postMessage(message, transfer); } dispose() { this._rawIpc.close(); } onMessage(callback) { this._rawIpc.addEventListener('message', callback); } onClose(callback) {} } const wrap$5 = messagePort => { return new IpcParentWithMessagePort(messagePort); }; const IpcParentWithMessagePort$1 = { __proto__: null, create: create$5$1, signal: signal$1, wrap: wrap$5 }; class CommandNotFoundError extends Error { constructor(command) { super(`Command not found ${command}`); this.name = 'CommandNotFoundError'; } } const commands = Object.create(null); const register$1 = commandMap => { Object.assign(commands, commandMap); }; const getCommand = key => { return commands[key]; }; const execute = (command, ...args) => { const fn = getCommand(command); if (!fn) { throw new CommandNotFoundError(command); } return fn(...args); }; const Two$1 = '2.0'; const callbacks = Object.create(null); const get$1 = id => { return callbacks[id]; }; const remove$1 = id => { delete callbacks[id]; }; class JsonRpcError extends Error { constructor(message) { super(message); this.name = 'JsonRpcError'; } } const NewLine = '\n'; const DomException = 'DOMException'; const ReferenceError$1 = 'ReferenceError'; const SyntaxError$1 = 'SyntaxError'; const TypeError$1 = 'TypeError'; const getErrorConstructor = (message, type) => { if (type) { switch (type) { case DomException: return DOMException; case ReferenceError$1: return ReferenceError; case SyntaxError$1: return SyntaxError; case TypeError$1: return TypeError; default: return Error; } } if (message.startsWith('TypeError: ')) { return TypeError; } if (message.startsWith('SyntaxError: ')) { return SyntaxError; } if (message.startsWith('ReferenceError: ')) { return ReferenceError; } return Error; }; const constructError = (message, type, name) => { const ErrorConstructor = getErrorConstructor(message, type); if (ErrorConstructor === DOMException && name) { return new ErrorConstructor(message, name); } if (ErrorConstructor === Error) { const error = new Error(message); if (name && name !== 'VError') { Object.defineProperty(error, 'name', { configurable: true, value: name }); } return error; } return new ErrorConstructor(message); }; const joinLines = lines => { return lines.join(NewLine); }; const splitLines$1 = lines => { return lines.split(NewLine); }; const getCurrentStack = () => { const stackLinesToSkip = 3; const currentStack = joinLines(splitLines$1(new Error().stack || '').slice(stackLinesToSkip)); return currentStack; }; const getNewLineIndex = (string, startIndex) => { { return string.indexOf(NewLine); } }; const getParentStack = error => { let parentStack = error.stack || error.data || error.message || ''; if (parentStack.startsWith(' at')) { parentStack = error.message + NewLine + parentStack; } return parentStack; }; const MethodNotFound = -32601; const Custom = -32001; const setStack = (error, stack) => { const descriptor = Object.getOwnPropertyDescriptor(error, 'stack'); if (descriptor) { if (!descriptor.configurable && !descriptor.writable) { return; } if (!descriptor.configurable && descriptor.writable) { error.stack = stack; return; } } Object.defineProperty(error, 'stack', { configurable: true, value: stack, writable: true }); }; const restoreExistingError = (error, currentStack) => { if (typeof error.stack === 'string') { setStack(error, `${error.stack}${NewLine}${currentStack}`); } return error; }; const restoreMethodNotFoundError = (error, currentStack) => { const restoredError = new JsonRpcError(error.message); const parentStack = getParentStack(error); setStack(restoredError, `${parentStack}${NewLine}${currentStack}`); return restoredError; }; const restoreStackFromData = (restoredError, error, currentStack) => { if (error.data.stack && error.data.type && error.message) { setStack(restoredError, `${error.data.type}: ${error.message}${NewLine}${error.data.stack}${NewLine}${currentStack}`); return; } if (error.data.stack) { setStack(restoredError, error.data.stack); } }; const applyDataProperties = (restoredError, error) => { restoreStackFromData(restoredError, error, getCurrentStack()); if (error.data.codeFrame) { // @ts-ignore restoredError.codeFrame = error.data.codeFrame; } if (error.data.code) { // @ts-ignore restoredError.code = error.data.code; } if (error.data.type) { // @ts-ignore restoredError.name = error.data.type; } }; const applyDirectProperties = (restoredError, error) => { if (error.stack) { const lowerStack = restoredError.stack || ''; const indexNewLine = getNewLineIndex(lowerStack); const parentStack = getParentStack(error); // @ts-ignore setStack(restoredError, `${parentStack}${lowerStack.slice(indexNewLine)}`); } if (error.codeFrame) { // @ts-ignore restoredError.codeFrame = error.codeFrame; } }; const restoreMessageError = (error, _currentStack) => { const restoredError = constructError(error.message, error.type, error.name); if (error.data) { applyDataProperties(restoredError, error); } else { applyDirectProperties(restoredError, error); } return restoredError; }; const restoreJsonRpcError = error => { const currentStack = getCurrentStack(); if (error && error instanceof Error) { return restoreExistingError(error, currentStack); } if (error && error.code && error.code === MethodNotFound) { return restoreMethodNotFoundError(error, currentStack); } if (error && error.message) { return restoreMessageError(error); } if (typeof error === 'string') { return new Error(`JsonRpc Error: ${error}`); } return new Error(`JsonRpc Error: ${error}`); }; const unwrapJsonRpcResult = responseMessage => { if ('error' in responseMessage) { const restoredError = restoreJsonRpcError(responseMessage.error); throw restoredError; } if ('result' in responseMessage) { return responseMessage.result; } throw new JsonRpcError('unexpected response message'); }; const warn = (...args) => { console.warn(...args); }; const resolve = (id, response) => { const fn = get$1(id); if (!fn) { console.log(response); warn(`callback ${id} may already be disposed`); return; } fn(response); remove$1(id); }; const E_COMMAND_NOT_FOUND = 'E_COMMAND_NOT_FOUND'; const getErrorType = prettyError => { if (prettyError && prettyError.type) { return prettyError.type; } if (prettyError && prettyError.constructor && prettyError.constructor.name) { return prettyError.constructor.name; } return undefined; }; const isAlreadyStack = line => { return line.trim().startsWith('at '); }; const getStack = prettyError => { const stackString = prettyError.stack || ''; const newLineIndex = stackString.indexOf('\n'); if (newLineIndex !== -1 && !isAlreadyStack(stackString.slice(0, newLineIndex))) { return stackString.slice(newLineIndex + 1); } return stackString; }; const getErrorProperty = (error, prettyError) => { if (error && error.code === E_COMMAND_NOT_FOUND) { return { code: MethodNotFound, data: error.stack, message: error.message }; } return { code: Custom, data: { code: prettyError.code, codeFrame: prettyError.codeFrame, name: prettyError.name, stack: getStack(prettyError), type: getErrorType(prettyError) }, message: prettyError.message }; }; const create$1$1 = (id, error) => { return { error, id, jsonrpc: Two$1 }; }; const getErrorResponse = (id, error, preparePrettyError, logError) => { const prettyError = preparePrettyError(error); logError(error, prettyError); const errorProperty = getErrorProperty(error, prettyError); return create$1$1(id, errorProperty); }; const create$8 = (message, result) => { return { id: message.id, jsonrpc: Two$1, result: result ?? null }; }; const getSuccessResponse = (message, result) => { const resultProperty = result ?? null; return create$8(message, resultProperty); }; const getErrorResponseSimple = (id, error) => { return { error: { code: Custom, data: error, // @ts-ignore message: error.message }, id, jsonrpc: Two$1 }; }; const getResponse = async (message, ipc, execute, preparePrettyError, logError, requiresSocket) => { try { const result = requiresSocket(message.method) ? await execute(message.method, ipc, ...message.params) : await execute(message.method, ...message.params); return getSuccessResponse(message, result); } catch (error) { if (ipc.canUseSimpleErrorResponse) { return getErrorResponseSimple(message.id, error); } return getErrorResponse(message.id, error, preparePrettyError, logError); } }; const defaultPreparePrettyError = error => { return error; }; const defaultLogError = () => { // ignore }; const defaultRequiresSocket = () => { return false; }; const defaultResolve = resolve; // TODO maybe remove this in v6 or v7, only accept options object to simplify the code const normalizeParams = args => { if (args.length === 1) { const options = args[0]; return { execute: options.execute, ipc: options.ipc, logError: options.logError || defaultLogError, message: options.message, preparePrettyError: options.preparePrettyError || defaultPreparePrettyError, requiresSocket: options.requiresSocket || defaultRequiresSocket, resolve: options.resolve || defaultResolve }; } return { execute: args[2], ipc: args[0], logError: args[5], message: args[1], preparePrettyError: args[4], requiresSocket: args[6], resolve: args[3] }; }; const handleJsonRpcMessage = async (...args) => { const options = normalizeParams(args); const { execute, ipc, logError, message, preparePrettyError, requiresSocket, resolve } = options; if ('id' in message) { if ('method' in message) { const response = await getResponse(message, ipc, execute, preparePrettyError, logError, requiresSocket); try { ipc.send(response); } catch (error) { const errorResponse = getErrorResponse(message.id, error, preparePrettyError, logError); ipc.send(errorResponse); } return; } resolve(message.id, message); return; } if ('method' in message) { await getResponse(message, ipc, execute, preparePrettyError, logError, requiresSocket); return; } throw new JsonRpcError('unexpected message'); }; const Two = '2.0'; const create$7 = (method, params) => { return { jsonrpc: Two, method, params }; }; const create$6 = (id, method, params) => { const message = { id, jsonrpc: Two, method, params }; return message; }; let id = 0; const create$5 = () => { return ++id; }; const registerPromise = map => { const id = create$5(); const { promise, resolve } = Promise.withResolvers(); map[id] = resolve; return { id, promise }; }; const invokeHelper = async (callbacks, ipc, method, params, useSendAndTransfer) => { const { id, promise } = registerPromise(callbacks); const message = create$6(id, method, params); if (useSendAndTransfer && ipc.sendAndTransfer) { ipc.sendAndTransfer(message); } else { ipc.send(message); } const responseMessage = await promise; return unwrapJsonRpcResult(responseMessage); }; const createRpc = ipc => { const callbacks = Object.create(null); ipc._resolve = (id, response) => { const fn = callbacks[id]; if (!fn) { console.warn(`callback ${id} may already be disposed`); return; } fn(response); delete callbacks[id]; }; const rpc = { async dispose() { await ipc?.dispose(); }, invoke(method, ...params) { return invokeHelper(callbacks, ipc, method, params, false); }, invokeAndTransfer(method, ...params) { return invokeHelper(callbacks, ipc, method, params, true); }, // @ts-ignore ipc, /** * @deprecated */ send(method, ...params) { const message = create$7(method, params); ipc.send(message); } }; return rpc; }; const requiresSocket = () => { return false; }; const preparePrettyError = error => { return error; }; const logError = () => { // handled by renderer worker }; const handleMessage = event => { const actualRequiresSocket = event?.target?.requiresSocket || requiresSocket; const actualExecute = event?.target?.execute || execute; return handleJsonRpcMessage(event.target, event.data, actualExecute, event.target._resolve, preparePrettyError, logError, actualRequiresSocket); }; const handleIpc = ipc => { if ('addEventListener' in ipc) { ipc.addEventListener('message', handleMessage); } else if ('on' in ipc) { // deprecated ipc.on('message', handleMessage); } }; const listen$1 = async (module, options) => { const rawIpc = await module.listen(options); if (module.signal) { module.signal(rawIpc); } const ipc = module.wrap(rawIpc); return ipc; }; const create$4 = async ({ commandMap, isMessagePortOpen = true, messagePort }) => { // TODO create a commandMap per rpc instance register$1(commandMap); const rawIpc = await IpcParentWithMessagePort$1.create({ isMessagePortOpen, messagePort }); const ipc = IpcParentWithMessagePort$1.wrap(rawIpc); handleIpc(ipc); const rpc = createRpc(ipc); messagePort.start(); return rpc; }; const create$3 = async ({ commandMap, isMessagePortOpen, send }) => { const { port1, port2 } = new MessageChannel(); await send(port1); return create$4({ commandMap, isMessagePortOpen, messagePort: port2 }); }; const createSharedLazyRpc = factory => { let rpcPromise; const getOrCreate = () => { if (!rpcPromise) { rpcPromise = factory(); } return rpcPromise; }; return { async dispose() { const rpc = await getOrCreate(); await rpc.dispose(); }, async invoke(method, ...params) { const rpc = await getOrCreate(); return rpc.invoke(method, ...params); }, async invokeAndTransfer(method, ...params) { const rpc = await getOrCreate(); return rpc.invokeAndTransfer(method, ...params); }, async send(method, ...params) { const rpc = await getOrCreate(); rpc.send(method, ...params); } }; }; const create$2 = async ({ commandMap, isMessagePortOpen, send }) => { return createSharedLazyRpc(() => { return create$3({ commandMap, isMessagePortOpen, send }); }); }; const create$1 = async ({ commandMap }) => { // TODO create a commandMap per rpc instance register$1(commandMap); const ipc = await listen$1(IpcChildWithModuleWorkerAndMessagePort$1); handleIpc(ipc); const rpc = createRpc(ipc); return rpc; }; const createMockRpc = ({ commandMap }) => { const invocations = []; const invoke = (method, ...params) => { invocations.push([method, ...params]); const command = commandMap[method]; if (!command) { throw new Error(`command ${method} not found`); } return command(...params); }; const mockRpc = { invocations, invoke, invokeAndTransfer: invoke }; return mockRpc; }; const commandMapRef = {}; const handleMessagePort = async port => { await create$4({ commandMap: commandMapRef, isMessagePortOpen: true, messagePort: port }); }; const RE_PROTOCOL = /^([a-z-]+):\/\//; const getProtocol = uri => { const protocolMatch = uri.match(RE_PROTOCOL); if (protocolMatch) { return protocolMatch[1]; } return ''; }; const state = Object.create(null); const register = modules => { Object.assign(state, modules); }; const getFn = protocol => { return state[protocol]; }; const searchFile$4 = async (path, value, prepare, assetDir) => { const protocol = getProtocol(path); const fn = getFn(protocol); if (!fn) { throw new Error(`No search handler registered for protocol: ${protocol}`); } const result = await fn(path, value, prepare, assetDir); return result; }; const commandMap = { 'FileSearch.handleMessagePort': handleMessagePort, 'FileSearch.searchFile': searchFile$4, 'SearchFile.searchFile': searchFile$4 }; const rpcs = Object.create(null); const set$2 = (id, rpc) => { rpcs[id] = rpc; }; const get = id => { return rpcs[id]; }; const remove = id => { delete rpcs[id]; }; /* eslint-disable @typescript-eslint/explicit-function-return-type */ const create = rpcId => { return { async dispose() { const rpc = get(rpcId); await rpc.dispose(); }, // @ts-ignore invoke(method, ...params) { const rpc = get(rpcId); // @ts-ignore return rpc.invoke(method, ...params); }, // @ts-ignore invokeAndTransfer(method, ...params) { const rpc = get(rpcId); // @ts-ignore return rpc.invokeAndTransfer(method, ...params); }, registerMockRpc(commandMap) { const mockRpc = createMockRpc({ commandMap }); set$2(rpcId, mockRpc); // @ts-ignore mockRpc[Symbol.dispose] = () => { remove(rpcId); }; // @ts-ignore return mockRpc; }, set(rpc) { set$2(rpcId, rpc); } }; }; const EditorWorker = 99; const RendererWorker = 1; const { set: set$1 } = create(EditorWorker); const { invoke: invoke$1, invokeAndTransfer, set } = create(RendererWorker); const sendMessagePortToEditorWorker = async (port, rpcId) => { const command = 'HandleMessagePort.handleMessagePort'; await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToEditorWorker', port, command, rpcId); }; const initializeEditorWorker = async () => { const rpc = await create$2({ commandMap: {}, async send(port) { await sendMessagePortToEditorWorker(port, 0); } }); set$1(rpc); }; const initializeRendererWorker = async () => { const rpc = await create$1({ commandMap: commandMap }); set(rpc); }; const Memfs = 'memfs'; const Html = 'html'; const Fetch = 'fetch'; const File = 'file'; const Default = ''; const searchFile$3 = async uri => { return invoke$1('ExtensionHost.searchFileWithMemory', uri); }; // TODO simplify code // 1. don't have playground prefix in fileMap json // 2. remove code here that removes the prefix const searchFile$2 = async path => { return invoke$1('ExtensionHost.searchFileWithFetch', path); }; const searchFile$1 = async uri => { return invoke$1('ExtensionHost.searchFileWithHtml', uri); }; const getFileSearchRipGrepArgs = () => { const ripGrepArgs = ['--files', '--sort-files', '--hidden', '--glob', '!.git', '--glob', '!elm-stuff']; return ripGrepArgs; }; const invoke = (method, ...params) => { return invoke$1('SearchProcess.invoke', method, ...params); }; const splitLines = lines => { if (!lines) { return []; } return lines.split('\n'); }; // TODO create direct connection from electron to file search worker using message ports const searchFile = async (path, value, prepare) => { const ripGrepArgs = getFileSearchRipGrepArgs(); const options = { limit: 9_999_999, ripGrepArgs, searchPath: path }; const stdout = await invoke('SearchFile.searchFile', options); const lines = splitLines(stdout); return lines; }; const searchModules = { [Default]: searchFile, [Fetch]: searchFile$2, [File]: searchFile, [Html]: searchFile$1, [Memfs]: searchFile$3 }; const listen = async () => { Object.assign(commandMapRef, commandMap); register(searchModules); await Promise.all([initializeRendererWorker(), initializeEditorWorker()]); }; const main = async () => { await listen(); }; main();