Merge pull request #206 from napi-rs/bench

feat: add benchmark crate and frameworks
This commit is contained in:
LongYinan 2020-09-30 15:54:23 +08:00 committed by GitHub
commit 4460f43be8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 509 additions and 55 deletions

View file

@ -213,3 +213,10 @@ overrides:
- '@typescript-eslint'
parserOptions:
project: ./test_module/tsconfig.json
- files:
- ./bench/**/*.{ts,js}
plugins:
- '@typescript-eslint'
parserOptions:
project: ./bench/tsconfig.json

View file

@ -33,6 +33,9 @@ jobs:
- name: 'Install node dependencies'
run: docker run --rm -v $(pwd)/.cargo:/root/.cargo -v $(pwd):/napi-rs -w /napi-rs builder yarn
- name: 'Install swc musl'
run: docker run --rm -v $(pwd)/.cargo:/root/.cargo -v $(pwd):/napi-rs -w /napi-rs builder yarn add @swc/core-linux-musl --dev
- name: 'Build TypeScript'
run: docker run --rm -v $(pwd)/.cargo:/root/.cargo -v $(pwd):/napi-rs -w /napi-rs builder yarn build

View file

@ -6,4 +6,4 @@ members = [
"./napi-derive-example",
"./sys"
]
exclude = ["./test_module"]
exclude = ["./test_module", "./bench"]

25
bench/Cargo.toml Normal file
View file

@ -0,0 +1,25 @@
[package]
name = "bench"
version = "0.1.0"
authors = ["LongYinan <lynweklm@gmail.com>"]
edition = "2018"
[lib]
crate-type = ["cdylib"]
[dependencies]
futures = "0.3"
napi = { path = "../napi", features = ["libuv", "tokio_rt", "serde-json", "latin1"] }
napi-derive = { path = "../napi-derive" }
serde = "1"
serde_bytes = "0.11"
serde_derive = "1"
serde_json = "1"
tokio = { version = "0.2", features = ["default", "fs"]}
[build-dependencies]
napi-build = { path = "../build" }
[profile.release]
opt-level = 3
lto = true

15
bench/async.ts Normal file
View file

@ -0,0 +1,15 @@
import b from 'benny'
const { benchAsyncTask } = require('./index.node')
const buffer = Buffer.from('hello 🚀 rust!')
export const benchAsync = () =>
b.suite(
'Async task',
b.add('napi-rs', async () => {
await benchAsyncTask(buffer)
}),
b.cycle(),
b.complete(),
)

13
bench/bench.ts Normal file
View file

@ -0,0 +1,13 @@
import { benchAsync } from './async'
import { benchNoop } from './noop'
import { benchPlus } from './plus'
async function run() {
await benchNoop()
await benchPlus()
await benchAsync()
}
run().catch((e) => {
console.error(e)
})

5
bench/build.rs Normal file
View file

@ -0,0 +1,5 @@
extern crate napi_build;
fn main() {
napi_build::setup();
}

19
bench/noop.ts Normal file
View file

@ -0,0 +1,19 @@
import b from 'benny'
const { noop: napiNoop } = require('./index.node')
function noop() {}
export const benchNoop = () =>
b.suite(
'noop',
b.add('napi-rs', () => {
napiNoop()
}),
b.add('JavaScript', () => {
noop()
}),
b.cycle(),
b.complete(),
)

7
bench/package.json Normal file
View file

@ -0,0 +1,7 @@
{
"name": "test-module",
"version": "1.0.0",
"scripts": {
"build": "cargo build --release && node ../scripts/index.js build --release"
}
}

21
bench/plus.ts Normal file
View file

@ -0,0 +1,21 @@
import b from 'benny'
const { plus } = require('./index.node')
function plusJavascript(a: number, b: number) {
return a + b
}
export const benchPlus = () =>
b.suite(
'Plus number',
b.add('napi-rs', () => {
plus(1, 100)
}),
b.add('JavaScript', () => {
plusJavascript(1, 100)
}),
b.cycle(),
b.complete(),
)

View file

@ -0,0 +1,30 @@
use napi::{CallContext, Env, JsBuffer, JsNumber, JsObject, Module, Result, Task};
#[repr(transparent)]
struct BufferLength(&'static [u8]);
impl Task for BufferLength {
type Output = usize;
type JsValue = JsNumber;
fn compute(&mut self) -> Result<Self::Output> {
Ok(self.0.len())
}
fn resolve(&self, env: &mut Env, output: Self::Output) -> Result<Self::JsValue> {
env.create_uint32(output as u32)
}
}
#[js_function(1)]
fn bench_async_task(ctx: CallContext) -> Result<JsObject> {
let n = ctx.get::<JsBuffer>(0)?;
let task = BufferLength(n.data);
let async_promise = ctx.env.spawn(task)?;
Ok(async_promise.promise_object())
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("benchAsyncTask", bench_async_task)?;
Ok(())
}

21
bench/src/lib.rs Normal file
View file

@ -0,0 +1,21 @@
#[macro_use]
extern crate napi;
#[macro_use]
extern crate napi_derive;
use napi::{Module, Result};
mod async_compute;
mod noop;
mod plus;
register_module!(bench, init);
fn init(module: &mut Module) -> Result<()> {
module.create_named_method("noop", noop::noop)?;
async_compute::register_js(module)?;
plus::register_js(module)?;
Ok(())
}

6
bench/src/noop.rs Normal file
View file

@ -0,0 +1,6 @@
use napi::{ContextlessResult, Env, JsUndefined};
#[contextless_function]
pub fn noop(_env: Env) -> ContextlessResult<JsUndefined> {
Ok(None)
}

15
bench/src/plus.rs Normal file
View file

@ -0,0 +1,15 @@
use std::convert::TryInto;
use napi::{CallContext, JsNumber, Module, Result};
#[js_function(2)]
fn bench_plus(ctx: CallContext) -> Result<JsNumber> {
let a: u32 = ctx.get::<JsNumber>(0)?.try_into()?;
let b: u32 = ctx.get::<JsNumber>(1)?.try_into()?;
ctx.env.create_uint32(a + b)
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("plus", bench_plus)?;
Ok(())
}

8
bench/tsconfig.json Normal file
View file

@ -0,0 +1,8 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"target": "ESNext"
},
"include": ["."],
"exclude": ["target", "src"]
}

View file

@ -1,5 +1,7 @@
extern crate proc_macro;
use std::mem;
use proc_macro::TokenStream;
use proc_macro2::{Ident, Literal};
use quote::{format_ident, quote};
@ -9,22 +11,25 @@ use syn::punctuated::Punctuated;
use syn::{parse_macro_input, Block, FnArg, ItemFn, Signature, Token, Visibility};
struct ArgLength {
length: Option<Literal>,
length: Literal,
}
impl Parse for ArgLength {
fn parse(input: ParseStream) -> Result<Self> {
let vars = Punctuated::<Literal, Token![,]>::parse_terminated(input)?;
Ok(ArgLength {
length: vars.first().map(|i| i.clone()),
length: vars
.first()
.map(|i| i.clone())
.unwrap_or(Literal::usize_unsuffixed(0)),
})
}
}
struct JsFunction {
args: Vec<FnArg>,
name: Option<Ident>,
signature: Option<Signature>,
name: mem::MaybeUninit<Ident>,
signature: mem::MaybeUninit<Signature>,
block: Vec<Block>,
visibility: Visibility,
}
@ -33,8 +38,8 @@ impl JsFunction {
pub fn new() -> Self {
JsFunction {
args: vec![],
name: None,
signature: None,
name: mem::MaybeUninit::uninit(),
signature: mem::MaybeUninit::uninit(),
visibility: Visibility::Inherited,
block: vec![],
}
@ -48,10 +53,10 @@ impl Fold for JsFunction {
}
fn fold_signature(&mut self, signature: Signature) -> Signature {
self.name = Some(format_ident!("{}", signature.ident));
self.name = mem::MaybeUninit::new(format_ident!("{}", signature.ident));
let mut new_signature = signature.clone();
new_signature.ident = format_ident!("_{}", signature.ident);
self.signature = Some(new_signature);
self.signature = mem::MaybeUninit::new(new_signature);
fold_signature(self, signature)
}
@ -69,16 +74,18 @@ impl Fold for JsFunction {
#[proc_macro_attribute]
pub fn js_function(attr: TokenStream, input: TokenStream) -> TokenStream {
let arg_len = parse_macro_input!(attr as ArgLength);
let arg_len_span = arg_len.length.unwrap_or(Literal::usize_unsuffixed(0));
let arg_len_span = arg_len.length;
let input = parse_macro_input!(input as ItemFn);
let mut js_fn = JsFunction::new();
js_fn.fold_item_fn(input);
let fn_name = js_fn.name.unwrap();
let fn_name = unsafe { js_fn.name.assume_init() };
let fn_block = js_fn.block;
let signature = js_fn.signature.unwrap();
let signature = unsafe { js_fn.signature.assume_init() };
let visibility = js_fn.visibility;
let new_fn_name = signature.ident.clone();
let execute_js_function = get_execute_js_code(new_fn_name, FunctionKind::JsFunction);
let expanded = quote! {
#[inline]
#signature #(#fn_block)*
#visibility extern "C" fn #fn_name(
@ -112,30 +119,94 @@ pub fn js_function(attr: TokenStream, input: TokenStream) -> TokenStream {
let mut env = Env::from_raw(raw_env);
let ctx = CallContext::new(&mut env, cb_info, raw_this, &raw_args, #arg_len_span, argc as usize);
match panic::catch_unwind(AssertUnwindSafe(move || #new_fn_name(ctx))).map_err(|e| {
let message = {
if let Some(string) = e.downcast_ref::<String>() {
string.clone()
} else if let Some(string) = e.downcast_ref::<&str>() {
string.to_string()
} else {
format!("panic from Rust code: {:?}", e)
}
};
Error::from_reason(message)
}).and_then(|v| v)
{
Ok(v) => v.raw_value(),
Err(e) => {
let message = format!("{}", e);
unsafe {
napi::sys::napi_throw_error(raw_env, ptr::null(), CString::from_vec_unchecked(message.into()).as_ptr() as *const c_char);
}
ptr::null_mut()
}
}
#execute_js_function
}
};
// Hand the output tokens back to the compiler
TokenStream::from(expanded)
}
#[proc_macro_attribute]
pub fn contextless_function(_attr: TokenStream, input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as ItemFn);
let mut js_fn = JsFunction::new();
js_fn.fold_item_fn(input);
let fn_name = unsafe { js_fn.name.assume_init() };
let fn_block = js_fn.block;
let signature = unsafe { js_fn.signature.assume_init() };
let visibility = js_fn.visibility;
let new_fn_name = signature.ident.clone();
let execute_js_function = get_execute_js_code(new_fn_name, FunctionKind::Contextless);
let expanded = quote! {
#[inline]
#signature #(#fn_block)*
#visibility extern "C" fn #fn_name(
raw_env: napi::sys::napi_env,
cb_info: napi::sys::napi_callback_info,
) -> napi::sys::napi_value {
use std::io::Write;
use std::mem;
use std::os::raw::c_char;
use std::ptr;
use std::panic::{self, AssertUnwindSafe};
use std::ffi::CString;
use napi::{Env, NapiValue, Error, Status};
let mut has_error = false;
let ctx = Env::from_raw(raw_env);
#execute_js_function
}
};
// Hand the output tokens back to the compiler
TokenStream::from(expanded)
}
enum FunctionKind {
Contextless,
JsFunction,
}
#[inline]
fn get_execute_js_code(
new_fn_name: Ident,
function_kind: FunctionKind,
) -> proc_macro2::TokenStream {
let return_token_stream = match function_kind {
FunctionKind::Contextless => {
quote! {
Ok(Some(v)) => v.raw_value(),
Ok(None) => ptr::null_mut(),
}
}
FunctionKind::JsFunction => {
quote! {
Ok(v) => v.raw_value(),
}
}
};
quote! {
match panic::catch_unwind(AssertUnwindSafe(move || #new_fn_name(ctx))).map_err(|e| {
let message = {
if let Some(string) = e.downcast_ref::<String>() {
string.clone()
} else if let Some(string) = e.downcast_ref::<&str>() {
string.to_string()
} else {
format!("panic from Rust code: {:?}", e)
}
};
Error::from_reason(message)
}).and_then(|v| v) {
#return_token_stream
Err(e) => {
let message = format!("{}", e);
unsafe {
napi::sys::napi_throw_error(raw_env, ptr::null(), CString::from_vec_unchecked(message.into()).as_ptr() as *const c_char);
}
ptr::null_mut()
}
}
}
}

View file

@ -126,6 +126,8 @@ pub use tokio_rt::shutdown as shutdown_tokio_rt;
#[macro_use]
extern crate serde;
pub type ContextlessResult<T> = Result<Option<T>>;
/// register nodejs module
///
/// ## Example

View file

@ -21,7 +21,10 @@
],
"license": "MIT",
"scripts": {
"bench": "cross-env SWC_NODE_PROJECT='./bench/tsconfig.json' node -r @swc-node/register bench/bench.ts",
"build": "tsc -p tsconfig.json && chmod 777 scripts/index.js",
"build:bench": "yarn --cwd ./bench build",
"build:test": "yarn --cwd ./test_module build",
"format": "run-p format:md format:json format:yaml format:source format:rs",
"format:md": "prettier --parser markdown --write './**/*.md'",
"format:json": "prettier --parser json --write './**/*.json'",
@ -55,12 +58,23 @@
"trailingComma": "all",
"arrowParens": "always"
},
"files": ["scripts", "LICENSE"],
"files": [
"scripts",
"LICENSE"
],
"lint-staged": {
"*.js": ["prettier --write"],
"*.@(yml|yaml)": ["prettier --parser yaml --write"],
"*.json": ["prettier --parser json --write"],
"*.md": ["prettier --parser markdown --write"]
"*.js": [
"prettier --write"
],
"*.@(yml|yaml)": [
"prettier --parser yaml --write"
],
"*.json": [
"prettier --parser json --write"
],
"*.md": [
"prettier --parser markdown --write"
]
},
"husky": {
"hooks": {
@ -77,6 +91,8 @@
"@typescript-eslint/eslint-plugin": "^4.3.0",
"@typescript-eslint/parser": "^4.2.0",
"ava": "^3.13.0",
"benny": "^3.6.14",
"cross-env": "^7.0.2",
"eslint": "^7.10.0",
"eslint-config-prettier": "^6.12.0",
"eslint-plugin-import": "^2.22.1",
@ -89,8 +105,5 @@
"source-map-support": "^0.5.19",
"ts-node": "^9.0.0",
"typescript": "^4.0.3"
},
"optionalDependencies": {
"@swc/core-linux-musl": "^1.2.34"
}
}

View file

@ -1,7 +1,5 @@
extern crate napi_build;
fn main() {
use napi_build::setup;
setup();
napi_build::setup();
}

View file

@ -30,5 +30,5 @@
"lib": ["dom", "DOM.Iterable", "ES2019", "ES2020", "esnext"]
},
"include": ["./src"],
"exclude": ["node_modules"]
"exclude": ["node_modules", "bench"]
}

193
yarn.lock
View file

@ -2,6 +2,40 @@
# yarn lockfile v1
"@arrows/array@^1.4.0":
version "1.4.0"
resolved "https://registry.npmjs.org/@arrows/array/-/array-1.4.0.tgz#4d0180b531da57e5de01f181d7f8abe6aea9b70f"
integrity sha512-kzd9z63lqqvyqkQ4kONGMTor3jl/zf4H7RvX4hoyG6mF7Ii01wx1JSHpDU5zhQIM+bqY7m4uaeqc+XADgKZLmA==
dependencies:
"@arrows/composition" "^1.0.0"
"@arrows/composition@^1.0.0", "@arrows/composition@^1.2.2":
version "1.2.2"
resolved "https://registry.npmjs.org/@arrows/composition/-/composition-1.2.2.tgz#d0a213cac8f8c36c1c75856a1e6ed940c27e9169"
integrity sha512-9fh1yHwrx32lundiB3SlZ/VwuStPB4QakPsSLrGJFH6rCXvdrd060ivAZ7/2vlqPnEjBkPRRXOcG1YOu19p2GQ==
"@arrows/dispatch@^1.0.2":
version "1.0.3"
resolved "https://registry.npmjs.org/@arrows/dispatch/-/dispatch-1.0.3.tgz#c4c06260f89e9dd4ce280df3712980aa2f3de976"
integrity sha512-v/HwvrFonitYZM2PmBlAlCqVqxrkIIoiEuy5bQgn0BdfvlL0ooSBzcPzTMrtzY8eYktPyYcHg8fLbSgyybXEqw==
dependencies:
"@arrows/composition" "^1.2.2"
"@arrows/error@^1.0.2":
version "1.0.2"
resolved "https://registry.npmjs.org/@arrows/error/-/error-1.0.2.tgz#4e68036f901118ba6f1de88656ef6be49e650414"
integrity sha512-yvkiv1ay4Z3+Z6oQsUkedsQm5aFdyPpkBUQs8vejazU/RmANABx6bMMcBPPHI4aW43VPQmXFfBzr/4FExwWTEA==
"@arrows/multimethod@^1.1.6":
version "1.1.7"
resolved "https://registry.npmjs.org/@arrows/multimethod/-/multimethod-1.1.7.tgz#bc7c26c3aa7703fc967e65da4f00718b1428eb4a"
integrity sha512-EjHD3XuGAV4G28rm7mu8k7zQJh/EOizh104/p9i2ofGcnL5mgKONFH/Bq6H3SJjM+WDAlKcR9WBpNhaAKCnH2g==
dependencies:
"@arrows/array" "^1.4.0"
"@arrows/composition" "^1.2.2"
"@arrows/error" "^1.0.2"
fast-deep-equal "^3.1.1"
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4":
version "7.10.4"
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
@ -419,11 +453,6 @@
resolved "https://registry.npmjs.org/@swc/core-darwin/-/core-darwin-1.2.34.tgz#dd69b1a12b7a2cb9e43a5e8a78a8d2d7ff392f53"
integrity sha512-OKOHOcqBgvBQiGC7doCa4CXKVDpO1QMIQogCFelqs82YbcQa6YEWvB6+ujiw1oUWaXP2fed1TFHDpHFJWorxIQ==
"@swc/core-linux-musl@^1.2.34":
version "1.2.34"
resolved "https://registry.npmjs.org/@swc/core-linux-musl/-/core-linux-musl-1.2.34.tgz#6853a747ce23dcb42754a04bdf753cb15f96a67d"
integrity sha512-et8kebSpVjWPNzuxqGALShhsIJymHzX63Auyqi9oyPiR9vEvMiIGvbTwH5eAHdM0Qc5iV0u8XyidHpoN2wtTYA==
"@swc/core-linux@^1.2.34":
version "1.2.34"
resolved "https://registry.npmjs.org/@swc/core-linux/-/core-linux-1.2.34.tgz#927fbdbfed1e842bbda4dc96d1407c5a0e67234d"
@ -662,6 +691,11 @@ ansi-colors@^4.1.1:
resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
ansi-escapes@^3.2.0:
version "3.2.0"
resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
ansi-escapes@^4.2.1, ansi-escapes@^4.3.0:
version "4.3.1"
resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61"
@ -855,6 +889,30 @@ before-after-hook@^2.1.0:
resolved "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635"
integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==
benchmark@^2.1.4:
version "2.1.4"
resolved "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz#09f3de31c916425d498cc2ee565a0ebf3c2a5629"
integrity sha1-CfPeMckWQl1JjMLuVloOvzwqVik=
dependencies:
lodash "^4.17.4"
platform "^1.3.3"
benny@^3.6.14:
version "3.6.14"
resolved "https://registry.npmjs.org/benny/-/benny-3.6.14.tgz#961e9cfce2eae69585ad8a8aeeaff13fe6eff458"
integrity sha512-Y9O44pD4Woes+K6OQtIVh9FvghtAPr/CdncdYnc+p1bpQuRahU4GbtCGGwVQwxAbgR2CBpVJtf79cWv1ePcLWQ==
dependencies:
"@arrows/composition" "^1.0.0"
"@arrows/dispatch" "^1.0.2"
"@arrows/multimethod" "^1.1.6"
benchmark "^2.1.4"
fs-extra "^8.1.0"
json2csv "^4.5.3"
kleur "^3.0.3"
log-update "^3.3.0"
prettier "^1.18.2"
stats-median "^1.0.1"
binary-extensions@^2.0.0:
version "2.1.0"
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9"
@ -1012,6 +1070,13 @@ cli-boxes@^2.2.0:
resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f"
integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==
cli-cursor@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=
dependencies:
restore-cursor "^2.0.0"
cli-cursor@^3.1.0:
version "3.1.0"
resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
@ -1103,6 +1168,11 @@ color-name@~1.1.4:
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
commander@^2.15.1:
version "2.20.3"
resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
commander@^6.0.0:
version "6.1.0"
resolved "https://registry.npmjs.org/commander/-/commander-6.1.0.tgz#f8d722b78103141006b66f4c7ba1e97315ba75bc"
@ -1182,6 +1252,13 @@ cosmiconfig@^7.0.0:
path-type "^4.0.0"
yaml "^1.10.0"
cross-env@^7.0.2:
version "7.0.2"
resolved "https://registry.npmjs.org/cross-env/-/cross-env-7.0.2.tgz#bd5ed31339a93a3418ac4f3ca9ca3403082ae5f9"
integrity sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw==
dependencies:
cross-spawn "^7.0.1"
cross-spawn@^6.0.0, cross-spawn@^6.0.5:
version "6.0.5"
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
@ -1193,7 +1270,7 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5:
shebang-command "^1.2.0"
which "^1.2.9"
cross-spawn@^7.0.0, cross-spawn@^7.0.2:
cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2:
version "7.0.3"
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
@ -1788,6 +1865,15 @@ fromentries@^1.2.0:
resolved "https://registry.npmjs.org/fromentries/-/fromentries-1.2.1.tgz#64c31665630479bc993cd800d53387920dc61b4d"
integrity sha512-Xu2Qh8yqYuDhQGOhD5iJGninErSfI9A3FrriD3tjUgV5VbJFeH8vfgZ9HnC6jWN80QDVNQK5vmxRAmEAp7Mevw==
fs-extra@^8.1.0:
version "8.1.0"
resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^4.0.0"
universalify "^0.1.0"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@ -1914,7 +2000,7 @@ got@^9.6.0:
to-readable-stream "^1.0.0"
url-parse-lax "^3.0.0"
graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.2.4:
graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4:
version "4.2.4"
resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
@ -2372,6 +2458,15 @@ json-stable-stringify-without-jsonify@^1.0.1:
resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
json2csv@^4.5.3:
version "4.5.4"
resolved "https://registry.npmjs.org/json2csv/-/json2csv-4.5.4.tgz#2b59c2869a137ec48cd2e243e0180466155f773f"
integrity sha512-YxBhY4Lmn8IvVZ36nqg5omxneLy9JlorkqW1j/EDCeqvmi+CQ4uM+wsvXlcIqvGDewIPXMC/O/oF8DX9EH5aoA==
dependencies:
commander "^2.15.1"
jsonparse "^1.3.1"
lodash.get "^4.4.2"
json5@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
@ -2386,6 +2481,18 @@ json5@^2.1.2:
dependencies:
minimist "^1.2.5"
jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
optionalDependencies:
graceful-fs "^4.1.6"
jsonparse@^1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=
keyv@^3.0.0:
version "3.1.0"
resolved "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
@ -2393,6 +2500,11 @@ keyv@^3.0.0:
dependencies:
json-buffer "3.0.0"
kleur@^3.0.3:
version "3.0.3"
resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
latest-version@^5.0.0:
version "5.1.0"
resolved "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face"
@ -2507,7 +2619,12 @@ lodash.flattendeep@^4.4.0:
resolved "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=
lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20:
lodash.get@^4.4.2:
version "4.4.2"
resolved "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.4:
version "4.17.20"
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
@ -2519,6 +2636,15 @@ log-symbols@^4.0.0:
dependencies:
chalk "^4.0.0"
log-update@^3.3.0:
version "3.4.0"
resolved "https://registry.npmjs.org/log-update/-/log-update-3.4.0.tgz#3b9a71e00ac5b1185cc193a36d654581c48f97b9"
integrity sha512-ILKe88NeMt4gmDvk/eb615U/IVn7K9KWGkoYbdatQ69Z65nj1ZzjM6fHXfcs0Uge+e+EGnMW7DY4T9yko8vWFg==
dependencies:
ansi-escapes "^3.2.0"
cli-cursor "^2.1.0"
wrap-ansi "^5.0.0"
log-update@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1"
@ -2620,6 +2746,11 @@ mime-types@^2.1.21:
dependencies:
mime-db "1.44.0"
mimic-fn@^1.0.0:
version "1.2.0"
resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
mimic-fn@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
@ -2815,6 +2946,13 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0:
dependencies:
wrappy "1"
onetime@^2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=
dependencies:
mimic-fn "^1.0.0"
onetime@^5.1.0:
version "5.1.2"
resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
@ -3114,6 +3252,11 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0:
dependencies:
find-up "^4.0.0"
platform@^1.3.3:
version "1.3.6"
resolved "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7"
integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==
please-upgrade-node@^3.2.0:
version "3.2.0"
resolved "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942"
@ -3145,6 +3288,11 @@ prettier-linter-helpers@^1.0.0:
dependencies:
fast-diff "^1.1.2"
prettier@^1.18.2:
version "1.19.1"
resolved "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
prettier@^2.1.2:
version "2.1.2"
resolved "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz#3050700dae2e4c8b67c4c3f666cdb8af405e1ce5"
@ -3329,6 +3477,14 @@ responselike@^1.0.2:
dependencies:
lowercase-keys "^1.0.0"
restore-cursor@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368=
dependencies:
onetime "^2.0.0"
signal-exit "^3.0.2"
restore-cursor@^3.1.0:
version "3.1.0"
resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
@ -3559,6 +3715,11 @@ stack-utils@^2.0.2:
dependencies:
escape-string-regexp "^2.0.0"
stats-median@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/stats-median/-/stats-median-1.0.1.tgz#ca8497cb1014d23d145db4d6fc93c8e815eed3ef"
integrity sha512-IYsheLg6dasD3zT/w9+8Iq9tcIQqqu91ZIpJOnIEM25C3X/g4Tl8mhXwW2ZQpbrsJISr9+wizEYgsibN5/b32Q==
string-argv@0.3.1:
version "0.3.1"
resolved "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da"
@ -3622,7 +3783,7 @@ strip-ansi@^4.0.0:
dependencies:
ansi-regex "^3.0.0"
strip-ansi@^5.1.0:
strip-ansi@^5.0.0, strip-ansi@^5.1.0:
version "5.2.0"
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
@ -3875,6 +4036,11 @@ universal-user-agent@^6.0.0:
resolved "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee"
integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==
universalify@^0.1.0:
version "0.1.2"
resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
update-notifier@^4.1.1:
version "4.1.1"
resolved "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.1.tgz#895fc8562bbe666179500f9f2cebac4f26323746"
@ -3981,6 +4147,15 @@ word-wrap@^1.2.3:
resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
wrap-ansi@^5.0.0:
version "5.1.0"
resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"
integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==
dependencies:
ansi-styles "^3.2.0"
string-width "^3.0.0"
strip-ansi "^5.0.0"
wrap-ansi@^6.2.0:
version "6.2.0"
resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"