|
|
@ -2,14 +2,17 @@ |
|
|
|
* Copyright (c) 2013-present, Facebook, Inc. |
|
|
|
* |
|
|
|
* @emails react-core |
|
|
|
* @flow |
|
|
|
*/ |
|
|
|
|
|
|
|
'use strict'; |
|
|
|
|
|
|
|
import React, {Component} from 'react'; |
|
|
|
import PropTypes from 'prop-types'; |
|
|
|
import React from 'react'; |
|
|
|
import qs from 'qs'; |
|
|
|
|
|
|
|
function replaceArgs(msg, argList) { |
|
|
|
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++]; |
|
|
@ -17,48 +20,39 @@ function replaceArgs(msg, argList) { |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
function urlify(str) { |
|
|
|
// 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); |
|
|
|
|
|
|
|
for (let i = 0; i < segments.length; i++) { |
|
|
|
return segments.map((message, i) => { |
|
|
|
if (i % 2 === 1) { |
|
|
|
segments[i] = ( |
|
|
|
<a key={i} target="_blank" rel="noopener" href={segments[i]}> |
|
|
|
{segments[i]} |
|
|
|
return ( |
|
|
|
<a key={i} target="_blank" rel="noopener" href={message}> |
|
|
|
{message} |
|
|
|
</a> |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return segments; |
|
|
|
return message; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// ?invariant=123&args[]=foo&args[]=bar
|
|
|
|
function parseQueryString(location) { |
|
|
|
const rawQueryString = location.search.substring(1); |
|
|
|
if (!rawQueryString) { |
|
|
|
// `?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 qsResult = qs.parse(search, {ignoreQueryPrefix: true}); |
|
|
|
if (!qsResult.invariant) { |
|
|
|
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(7)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return [code, args]; |
|
|
|
return { |
|
|
|
code: qsResult.invariant, |
|
|
|
args: qsResult.args || [], |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
function ErrorResult(props) { |
|
|
|
function ErrorResult(props: {code: ?string, msg: string}) { |
|
|
|
const code = props.code; |
|
|
|
const errorMsg = props.msg; |
|
|
|
|
|
|
@ -79,39 +73,21 @@ function ErrorResult(props) { |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
class ErrorDecoder extends Component { |
|
|
|
constructor(...args) { |
|
|
|
super(...args); |
|
|
|
|
|
|
|
this.state = { |
|
|
|
code: null, |
|
|
|
errorMsg: '', |
|
|
|
}; |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
componentWillMount() { |
|
|
|
const {errorCodesString} = this.props; |
|
|
|
const errorCodes = JSON.parse(errorCodesString); |
|
|
|
const parseResult = parseQueryString(this.props.location); |
|
|
|
if (parseResult != null) { |
|
|
|
const [code, args] = parseResult; |
|
|
|
if (errorCodes[code]) { |
|
|
|
this.setState({ |
|
|
|
code: code, |
|
|
|
errorMsg: replaceArgs(errorCodes[code], args), |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
render() { |
|
|
|
return <ErrorResult code={this.state.code} msg={this.state.errorMsg} />; |
|
|
|
} |
|
|
|
return <ErrorResult code={code} msg={msg} />; |
|
|
|
} |
|
|
|
|
|
|
|
ErrorDecoder.propTypes = { |
|
|
|
errorCodesString: PropTypes.string.isRequired, |
|
|
|
location: PropTypes.object.isRequired, |
|
|
|
}; |
|
|
|
|
|
|
|
export default ErrorDecoder; |
|
|
|