react-dev-utils
Advanced tools
Comparing version
@@ -60,2 +60,3 @@ /** | ||
'ansi-magenta': 'magenta', | ||
'ansi-white': 'darkgrey', | ||
}; | ||
@@ -85,3 +86,5 @@ | ||
} else { | ||
if (fg != null) console.log('Missing color mapping: ', fg); | ||
if (fg != null) { | ||
console.log('Missing color mapping: ', fg); | ||
} | ||
result += '<span>' + part + '</span>'; | ||
@@ -88,0 +91,0 @@ } |
@@ -19,2 +19,3 @@ /** | ||
var chalk = require('chalk'); | ||
var friendlySyntaxErrorLabel = 'Syntax error:'; | ||
@@ -27,5 +28,11 @@ | ||
// Cleans up webpack error messages. | ||
function formatMessage(message) { | ||
// eslint-disable-next-line no-unused-vars | ||
function formatMessage(message, isError) { | ||
var lines = message.split('\n'); | ||
if (lines.length > 2 && lines[1] === '') { | ||
// Remove extra newline. | ||
lines.splice(1, 1); | ||
} | ||
// Remove webpack-specific loader notation from filename. | ||
@@ -40,2 +47,11 @@ // Before: | ||
lines = lines.filter(function(line) { | ||
// Webpack adds a list of entry points to warning messages: | ||
// @ ./src/index.js | ||
// @ multi react-scripts/~/react-dev-utils/webpackHotDevClient.js ... | ||
// It is misleading (and unrelated to the warnings) so we clean it up. | ||
// It is only useful for syntax errors but we have beautiful frames for them. | ||
return line.indexOf(' @ ') !== 0; | ||
}); | ||
// line #0 is filename | ||
@@ -56,6 +72,2 @@ // line #1 is the main error message | ||
.replace('Error: ', ''), | ||
// Skip all irrelevant lines. | ||
// (For some reason they only appear on the client in browser.) | ||
'', | ||
lines[lines.length - 1], // error location is the last line | ||
]; | ||
@@ -66,35 +78,2 @@ } | ||
if (lines[1].indexOf('Module build failed: ') === 0) { | ||
// For some reason, on the client messages appear duplicated: | ||
// https://github.com/webpack/webpack/issues/3008 | ||
// This won't happen in Node but since we share this helpers, | ||
// we will dedupe them right here. We will ignore all lines | ||
// after the original error message text is repeated the second time. | ||
var errorText = lines[1].substr('Module build failed: '.length); | ||
var cleanedLines = []; | ||
var hasReachedDuplicateMessage = false; | ||
// Gather lines until we reach the beginning of duplicate message. | ||
lines.forEach(function(line, index) { | ||
if ( | ||
// First time it occurs is fine. | ||
index !== 1 && | ||
// line.endsWith(errorText) | ||
line.length >= errorText.length && | ||
line.indexOf(errorText) === line.length - errorText.length | ||
) { | ||
// We see the same error message for the second time! | ||
// Filter out repeated error message and everything after it. | ||
hasReachedDuplicateMessage = true; | ||
} | ||
if ( | ||
!hasReachedDuplicateMessage || | ||
// Print last line anyway because it contains the source location | ||
index === lines.length - 1 | ||
) { | ||
// This line is OK to appear in the output. | ||
cleanedLines.push(line); | ||
} | ||
}); | ||
// We are clean now! | ||
lines = cleanedLines; | ||
// Finally, brush up the error message a little. | ||
lines[1] = lines[1].replace( | ||
@@ -106,2 +85,14 @@ 'Module build failed: SyntaxError:', | ||
// Clean up export errors. | ||
// TODO: we should really send a PR to Webpack for this. | ||
var exportError = /\s*(.+?)\s*(")?export '(.+?)' was not found in '(.+?)'/; | ||
if (lines[1].match(exportError)) { | ||
lines[1] = lines[1].replace( | ||
exportError, | ||
"$1 '$4' does not contain an export named '$3'." | ||
); | ||
} | ||
lines[0] = chalk.inverse(lines[0]); | ||
// Reassemble the message. | ||
@@ -118,3 +109,3 @@ message = lines.join('\n'); | ||
return message; | ||
return message.trim(); | ||
} | ||
@@ -124,6 +115,6 @@ | ||
var formattedErrors = json.errors.map(function(message) { | ||
return 'Error in ' + formatMessage(message); | ||
return formatMessage(message, true); | ||
}); | ||
var formattedWarnings = json.warnings.map(function(message) { | ||
return 'Warning in ' + formatMessage(message); | ||
return formatMessage(message, false); | ||
}); | ||
@@ -140,2 +131,7 @@ var result = { | ||
} | ||
// Only keep the first error. Others are often indicative | ||
// of the same problem, but confuse the reader with noise. | ||
if (result.errors.length > 1) { | ||
result.errors.length = 1; | ||
} | ||
return result; | ||
@@ -142,0 +138,0 @@ } |
@@ -30,6 +30,5 @@ /** | ||
function getProcessIdOnPort(port) { | ||
return execSync( | ||
'lsof -i:' + port + ' -P -t -sTCP:LISTEN', | ||
execOptions | ||
).trim(); | ||
return execSync('lsof -i:' + port + ' -P -t -sTCP:LISTEN', execOptions) | ||
.split('\n')[0] | ||
.trim(); | ||
} | ||
@@ -36,0 +35,0 @@ |
@@ -12,3 +12,5 @@ /** | ||
var chalk = require('chalk'); | ||
var execSync = require('child_process').execSync; | ||
var spawn = require('cross-spawn'); | ||
var opn = require('opn'); | ||
@@ -19,13 +21,49 @@ | ||
function openBrowser(url) { | ||
const Actions = Object.freeze({ | ||
NONE: 0, | ||
BROWSER: 1, | ||
SCRIPT: 2, | ||
}); | ||
function getBrowserEnv() { | ||
// Attempt to honor this environment variable. | ||
// It is specific to the operating system. | ||
// See https://github.com/sindresorhus/opn#app for documentation. | ||
var browser = process.env.BROWSER; | ||
// Special case: BROWSER="none" will prevent opening completely. | ||
if (browser === 'none') { | ||
return false; | ||
const value = process.env.BROWSER; | ||
let action; | ||
if (!value) { | ||
// Default. | ||
action = Actions.BROWSER; | ||
} else if (value.toLowerCase().endsWith('.js')) { | ||
action = Actions.SCRIPT; | ||
} else if (value.toLowerCase() === 'none') { | ||
action = Actions.NONE; | ||
} else { | ||
action = Actions.BROWSER; | ||
} | ||
return { action, value }; | ||
} | ||
function executeNodeScript(scriptPath, url) { | ||
const extraArgs = process.argv.slice(2); | ||
const child = spawn('node', [scriptPath, ...extraArgs, url], { | ||
stdio: 'inherit', | ||
}); | ||
child.on('close', code => { | ||
if (code !== 0) { | ||
console.log(); | ||
console.log( | ||
chalk.red( | ||
'The script specified as BROWSER environment variable failed.' | ||
) | ||
); | ||
console.log(chalk.cyan(scriptPath) + ' exited with code ' + code + '.'); | ||
console.log(); | ||
return; | ||
} | ||
}); | ||
return true; | ||
} | ||
function startBrowserProcess(browser, url) { | ||
// If we're on OS X, the user hasn't specifically | ||
@@ -43,3 +81,3 @@ // requested a different browser, we can try opening | ||
execSync('ps cax | grep "Google Chrome"'); | ||
execSync('osascript openChrome.applescript ' + url, { | ||
execSync('osascript openChrome.applescript "' + encodeURI(url) + '"', { | ||
cwd: __dirname, | ||
@@ -73,2 +111,21 @@ stdio: 'ignore', | ||
/** | ||
* Reads the BROWSER evironment variable and decides what to do with it. Returns | ||
* true if it opened a browser or ran a node.js script, otherwise false. | ||
*/ | ||
function openBrowser(url) { | ||
const { action, value } = getBrowserEnv(); | ||
switch (action) { | ||
case Actions.NONE: | ||
// Special case: BROWSER="none" will prevent opening completely. | ||
return false; | ||
case Actions.SCRIPT: | ||
return executeNodeScript(value, url); | ||
case Actions.BROWSER: | ||
return startBrowserProcess(value, url); | ||
default: | ||
throw new Error('Not implemented.'); | ||
} | ||
} | ||
module.exports = openBrowser; |
{ | ||
"name": "react-dev-utils", | ||
"version": "0.6.0-alpha.f55d2212", | ||
"version": "1.0.0-alpha.58689133", | ||
"description": "Webpack utilities used by Create React App", | ||
@@ -11,3 +11,3 @@ "repository": "facebookincubator/create-react-app", | ||
"engines": { | ||
"node": ">=4" | ||
"node": ">=6" | ||
}, | ||
@@ -19,2 +19,3 @@ "files": [ | ||
"crashOverlay.js", | ||
"eslintFormatter.js", | ||
"FileSizeReporter.js", | ||
@@ -24,5 +25,6 @@ "formatWebpackMessages.js", | ||
"InterpolateHtmlPlugin.js", | ||
"launchEditor.js", | ||
"openBrowser.js", | ||
"openChrome.applescript", | ||
"prompt.js", | ||
"prepareProxy.js", | ||
"WatchMissingNodeModulesPlugin.js", | ||
@@ -32,15 +34,20 @@ "webpackHotDevClient.js" | ||
"dependencies": { | ||
"anser": "1.1.0", | ||
"babel-code-frame": "6.20.0", | ||
"address": "1.0.1", | ||
"anser": "1.3.0", | ||
"babel-code-frame": "6.22.0", | ||
"chalk": "1.1.3", | ||
"cross-spawn": "4.0.2", | ||
"escape-string-regexp": "1.0.5", | ||
"filesize": "3.3.0", | ||
"gzip-size": "3.0.0", | ||
"html-entities": "1.2.0", | ||
"opn": "4.0.2", | ||
"recursive-readdir": "2.1.1", | ||
"sockjs-client": "1.1.2", | ||
"stack-frame-resolver": "0.1.3", | ||
"html-entities": "1.2.1", | ||
"opn": "5.0.0", | ||
"recursive-readdir": "2.2.1", | ||
"shell-quote": "1.6.1", | ||
"sockjs-client": "1.1.4", | ||
"stack-frame-mapper": "0.4.0", | ||
"stack-frame-parser": "0.4.0", | ||
"stack-frame-unmapper": "0.4.0", | ||
"strip-ansi": "3.0.1" | ||
} | ||
} |
@@ -113,2 +113,32 @@ # react-dev-utils | ||
#### `eslintFormatter(results: Object): string` | ||
This is our custom ESLint formatter that integrates well with Create React App console output. | ||
You can use the default one instead if you prefer so. | ||
```js | ||
const eslintFormatter = require('react-dev-utils/eslintFormatter'); | ||
// In your webpack config: | ||
// ... | ||
module: { | ||
rules: [ | ||
{ | ||
test: /\.(js|jsx)$/, | ||
include: paths.appSrc, | ||
enforce: 'pre', | ||
use: [ | ||
{ | ||
loader: 'eslint-loader', | ||
options: { | ||
// Pass the formatter: | ||
formatter: eslintFormatter, | ||
}, | ||
}, | ||
], | ||
} | ||
] | ||
} | ||
``` | ||
#### `FileSizeReporter` | ||
@@ -202,25 +232,2 @@ | ||
#### `prompt(message: string, isYesDefault: boolean): Promise<boolean>` | ||
This function displays a console prompt to the user. | ||
By convention, "no" should be the conservative choice.<br> | ||
If you mistype the answer, we'll always take it as a "no".<br> | ||
You can control the behavior on `<Enter>` with `isYesDefault`. | ||
```js | ||
var prompt = require('react-dev-utils/prompt'); | ||
prompt( | ||
'Are you sure you want to eat all the candy?', | ||
/* isYesDefault */ false | ||
).then(shouldEat => { | ||
if (shouldEat) { | ||
console.log('You have successfully consumed all the candy.'); | ||
} else { | ||
console.log('Phew, candy is still available!'); | ||
} | ||
}); | ||
``` | ||
#### `webpackHotDevClient.js` | ||
@@ -227,0 +234,0 @@ |
@@ -185,4 +185,9 @@ /** | ||
// Print warnings to the console. | ||
for (var i = 0; i < warnings.length; i++) { | ||
console.warn(stripAnsi(warnings[i])); | ||
var formatted = formatWebpackMessages({ | ||
warnings: warnings, | ||
errors: [], | ||
}); | ||
for (var i = 0; i < formatted.warnings.length; i++) { | ||
console.warn(stripAnsi(formatted.warnings[i])); | ||
} | ||
@@ -189,0 +194,0 @@ } |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
16
6.67%252
2.86%55045
-16.18%17
41.67%1294
-23.75%13
160%3
50%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated
Updated
Updated
Updated