import StackFrame from './react-error-overlay/utils/stack-frame'; const isFF = navigator.userAgent.indexOf('Firefox') !== -1; function openResource( fileName: string, lineNumber: number, stackFrame: StackFrame ) { const adjustedLineNumber = Math.max(lineNumber - 1, 0); chrome.devtools.panels.openResource(fileName, adjustedLineNumber, ((result: { isError?: boolean; }) => { //console.log("openResource callback args: ", callbackArgs); if (result.isError) { const { fileName: finalFileName, lineNumber: finalLineNumber } = stackFrame; const adjustedLineNumber = Math.max(finalLineNumber! - 1, 0); chrome.devtools.panels.openResource( finalFileName!, adjustedLineNumber, (/* result */) => { // console.log("openResource result: ", result); } ); } }) as () => void); } function openAndCloseTab(url: string) { chrome.tabs.create({ url }, (tab) => { const removeTab = () => { chrome.windows.onFocusChanged.removeListener(removeTab); if (tab && tab.id) { chrome.tabs.remove(tab.id, async () => { // eslint-disable-next-line no-console if (chrome.runtime.lastError) console.log(chrome.runtime.lastError); else if (chrome.devtools && chrome.devtools.inspectedWindow) { await chrome.tabs.update(chrome.devtools.inspectedWindow.tabId, { active: true, }); } }); } }; if (chrome.windows) chrome.windows.onFocusChanged.addListener(removeTab); }); } function openInIframe(url: string) { const iframe = document.createElement('iframe'); iframe.src = url; iframe.style.display = 'none'; document.body.appendChild(iframe); setTimeout(() => iframe.parentNode!.removeChild(iframe), 3000); } function openInEditor(editor: string, path: string, stackFrame: StackFrame) { const projectPath = path.replace(/\/$/, ''); const file = stackFrame._originalFileName || (stackFrame as unknown as { finalFileName: string }).finalFileName || stackFrame.fileName || ''; let filePath = /^https?:\/\//.test(file) ? file.replace(/^https?:\/\/[^/]*/, '') : file.replace(/^\w+:\/\//, ''); filePath = filePath.replace(/^\/~\//, '/node_modules/'); const line = stackFrame._originalLineNumber || stackFrame.lineNumber || '0'; const column = stackFrame._originalColumnNumber || stackFrame.columnNumber || '0'; let url; switch (editor) { case 'vscode': case 'code': url = `vscode://file/${projectPath}${filePath}:${line}:${column}`; break; case 'atom': url = `atom://core/open/file?filename=${projectPath}${filePath}&line=${line}&column=${column}`; break; case 'webstorm': case 'phpstorm': case 'idea': url = `${editor}://open?file=${projectPath}${filePath}&line=${line}&column=${column}`; break; default: // sublime, emacs, macvim, textmate + custom like https://github.com/eclemens/atom-url-handler url = `${editor}://open/?url=file://${projectPath}${filePath}&line=${line}&column=${column}`; } if (chrome.devtools && !isFF) { if (chrome.tabs) openAndCloseTab(url); else window.open(url); } else { openInIframe(url); } } export default function openFile( fileName: string, lineNumber: number, stackFrame: StackFrame ) { if (!chrome || !chrome.storage) return; // TODO: Pass editor settings for using outside of browser extension const storage = isFF ? chrome.storage.local : chrome.storage.sync || chrome.storage.local; storage.get( ['useEditor', 'editor', 'projectPath'], function ({ useEditor, editor, projectPath }) { if ( useEditor && projectPath && typeof editor === 'string' && /^\w{1,30}$/.test(editor) ) { openInEditor(editor.toLowerCase(), projectPath as string, stackFrame); } else { if ( chrome.devtools && chrome.devtools.panels && !!chrome.devtools.panels.openResource ) { openResource(fileName, lineNumber, stackFrame); } else if (chrome.runtime && (chrome.runtime.openOptionsPage || isFF)) { if (chrome.devtools && isFF) { chrome.devtools.inspectedWindow.eval( 'confirm("Set the editor to open the file in?")', (result) => { if (!result) return; chrome.runtime.sendMessage({ type: 'OPEN_OPTIONS' }); } ); } else if (confirm('Set the editor to open the file in?')) { chrome.runtime.openOptionsPage(); } } } } ); }