src/components/ErrorDecoder/ErrorDecoder.js (82 lines of code) (raw):

/** * Copyright (c) Facebook, Inc. and its affiliates. * * @emails react-core * @flow */ import React from 'react'; import type {Node} from 'react'; function replaceArgs(msg: string, argList: Array<string>): string { let argIdx = 0; return msg.replace(/%s/g, function() { const arg = argList[argIdx++]; return arg === undefined ? '[missing argument]' : arg; }); } // When the message contains a URL (like https://fb.me/react-refs-must-have-owner), // make it a clickable link. function urlify(str: string): Node { const urlRegex = /(https:\/\/fb\.me\/[a-z\-]+)/g; const segments = str.split(urlRegex); return segments.map((message, i) => { if (i % 2 === 1) { return ( <a key={i} target="_blank" rel="noopener" href={message}> {message} </a> ); } return message; }); } // `?invariant=123&args[]=foo&args[]=bar` // or `// ?invariant=123&args[0]=foo&args[1]=bar` function parseQueryString( search: string, ): ?{|code: string, args: Array<string>|} { const rawQueryString = search.substring(1); if (!rawQueryString) { return null; } let code = ''; let args = []; const queries = rawQueryString.split('&'); for (let i = 0; i < queries.length; i++) { const query = decodeURIComponent(queries[i]); if (query.indexOf('invariant=') === 0) { code = query.slice(10); } else if (query.indexOf('args[') === 0) { args.push(query.slice(query.indexOf(']=') + 2)); } } return {args, code}; } function ErrorResult(props: {|code: ?string, msg: string|}) { const code = props.code; const errorMsg = props.msg; if (!code) { return ( <p> When you encounter an error, you'll receive a link to this page for that specific error and we'll show you the full error text. </p> ); } return ( <div> <p> <b>The full text of the error you just encountered is:</b> </p> <code> <b>{urlify(errorMsg)}</b> </code> </div> ); } function ErrorDecoder(props: {| errorCodesString: string, location: {search: string}, |}) { let code = null; let msg = ''; const errorCodes = JSON.parse(props.errorCodesString); const parseResult = parseQueryString(props.location.search || ''); if (parseResult != null) { code = parseResult.code; msg = replaceArgs(errorCodes[code], parseResult.args); } return <ErrorResult code={code} msg={msg} />; } export default ErrorDecoder;