feat(various): gql api (tests & resolvers), added eslint & editorconfig

This commit is contained in:
Dimitrie Stefanescu
2020-07-20 15:33:56 +01:00
parent 9715129284
commit 2b33ab5aa2
11 changed files with 718 additions and 121 deletions
+9
View File
@@ -0,0 +1,9 @@
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
+18
View File
@@ -0,0 +1,18 @@
{
"env": {
"browser": true,
"commonjs": true,
"es2020": true
},
"parserOptions": {
"ecmaVersion": 11
},
"rules": {
"arrow-spacing": [ 2, { "before": true, "after": true } ],
"array-bracket-spacing": [ 2, "always" ],
"block-spacing": [ 2, "always" ],
"camelcase": [ 1, { "properties": "always" } ],
"space-in-parens": [ 2, "always" ],
"keyword-spacing": 2
}
}
+21 -13
View File
@@ -1,7 +1,7 @@
'use strict'
const appRoot = require( 'app-root-path' )
const { AuthorizationError, ApolloError } = require( 'apollo-server-express' )
const { ForbiddenError, ApolloError } = require( 'apollo-server-express' )
const { validateServerRole, validateScopes, authorizeResolver } = require( `${appRoot}/modules/shared` )
const {
@@ -25,10 +25,10 @@ module.exports = {
Query: {},
Stream: {
async branches( parent, args, context, info ) {
throw new ApolloError('not implemented')
throw new ApolloError( 'not implemented' )
},
async branch( parent, args, context, info ) {
throw new ApolloError('not implemented')
async branch( parent, args, context, info) {
throw new ApolloError( 'not implemented' )
},
},
Branch: {
@@ -40,26 +40,34 @@ module.exports = {
async branchCreate( parent, args, context, info ) {
await validateServerRole( context, 'server:user' )
await validateScopes( context.scopes, 'streams:write' )
await authorizeResolver( context.userId, args.streamId, 'stream:contributor' )
await authorizeResolver( context.userId, args.branch.streamId, 'stream:contributor' )
let id = await createBranch( args.branch, args.streamId, context.userId )
let id = await createBranch( { ...args.branch, authorId: context.userId } )
return id
},
async branchUpdate( parent, args, context, info ) {
await validateServerRole( context, 'server:user' )
await validateScopes( context.scopes, 'streams:write' )
await authorizeResolver( context.userId, args.streamId, 'stream:contributor' )
await authorizeResolver( context.userId, args.branch.streamId, 'stream:contributor' )
await updateBranch( args.branch )
return true
return await updateBranch( { ...args.branch } )
},
async branchDelete( parent, args, context, info ) {
await validateServerRole( context, 'server:user' )
await validateScopes( context.scopes, 'streams:write' )
await authorizeResolver( context.userId, args.streamId, 'stream:contributor' )
let role = await authorizeResolver( context.userId, args.branch.streamId, 'stream:contributor' )
await deleteBranchById( args.branchId )
return true
let branch = await getBranchById( { id: args.branch.id } )
if ( !branch ) {
throw new ApolloError( 'Branch not found.' )
}
if ( branch.authorId !== context.userId && role !== 'stream:owner' )
throw new ForbiddenError( 'Only the branch creator or stream owners are allowed to delete branches.' )
return await deleteBranchById( { id: args.branch.id } )
}
}
}
}
+1 -1
View File
@@ -50,7 +50,7 @@ module.exports = {
await validateScopes( context.scopes, 'streams:write' )
await authorizeResolver( context.userId, args.id, 'stream:owner' )
await deleteStream( args.id )
await deleteStream( { streamId: args.id } )
return true
},
async streamGrantPermission( parent, args, context, info ) {
+1 -1
View File
@@ -38,4 +38,4 @@ module.exports = {
async deleteBranchById( { id } ) {
return await Branches( ).where( { id: id } ).del( )
},
}
}
+3
View File
@@ -46,6 +46,7 @@ module.exports = {
},
async createCommitByBranchName( { streamId, branchName, objectId, authorId, message, previousCommitIds } ) {
branchName = branchName.toLowerCase()
let branches = await getBranchesByStreamId( { streamId: streamId } )
let myBranch = branches.find( b => b.name === branchName )
@@ -74,6 +75,7 @@ module.exports = {
},
async getCommitsTotalCountByBranchName( { streamId, branchName } ) {
branchName = branchName.toLowerCase()
let branches = await getBranchesByStreamId( { streamId: streamId } )
let myBranch = branches.find( b => b.name === branchName )
@@ -102,6 +104,7 @@ module.exports = {
},
async getCommitsByBranchName( { streamId, branchName, limit, cursor } ) {
branchName = branchName.toLowerCase()
let branches = await getBranchesByStreamId( { streamId: streamId } )
let myBranch = branches.find( b => b.name === branchName )
+1 -1
View File
@@ -97,4 +97,4 @@ describe( 'Branches', ( ) => {
expect( branches ).to.have.lengthOf( 3 )
} )
} )
} )
+164 -93
View File
@@ -33,11 +33,11 @@ describe( 'GraphQL API Core', ( ) => {
testServer = server
userA.id = await createUser( userA )
userA.token = `Bearer ${(await createPersonalAccessToken( userA.id, 'test token user A', [ 'streams:read', 'streams:write', 'users:read', 'users:email', 'tokens:write', 'tokens:read', 'profile:read', 'profile:email' ] ))}`
userA.token = `Bearer ${( await createPersonalAccessToken( userA.id, 'test token user A', [ 'streams:read', 'streams:write', 'users:read', 'users:email', 'tokens:write', 'tokens:read', 'profile:read', 'profile:email' ] ) )}`
userB.id = await createUser( userB )
userB.token = `Bearer ${(await createPersonalAccessToken( userB.id, 'test token user B', [ 'streams:read', 'streams:write', 'users:read', 'users:email', 'tokens:write', 'tokens:read', 'profile:read', 'profile:email' ] ))}`
userB.token = `Bearer ${( await createPersonalAccessToken( userB.id, 'test token user B', [ 'streams:read', 'streams:write', 'users:read', 'users:email', 'tokens:write', 'tokens:read', 'profile:read', 'profile:email' ] ) )}`
userC.id = await createUser( userC )
userC.token = `Bearer ${(await createPersonalAccessToken( userC.id, 'test token user B', [ 'streams:read', 'streams:write', 'users:read', 'users:email', 'tokens:write', 'tokens:read', 'profile:read', 'profile:email' ] ))}`
userC.token = `Bearer ${( await createPersonalAccessToken( userC.id, 'test token user B', [ 'streams:read', 'streams:write', 'users:read', 'users:email', 'tokens:write', 'tokens:read', 'profile:read', 'profile:email' ] ) )}`
addr = `http://localhost:${process.env.PORT || 3000}`
} )
@@ -66,9 +66,9 @@ describe( 'GraphQL API Core', ( ) => {
let c2 = {}
// some branches
let b1 = { name: 'branch 1', description: 'test branch' }
let b2 = { name: 'master', description: 'master branch' }
let b3 = { name: 'branch 3', description: 'wow' }
let b1 = {}
let b2 = {}
let b3 = {}
describe( 'Mutations', ( ) => {
@@ -154,7 +154,12 @@ describe( 'GraphQL API Core', ( ) => {
expect( res.body.data.streamGrantPermission ).to.equal( true )
const res2 = await sendRequest( userB.token, { query: `mutation{ streamGrantPermission( streamId: "${ts5}", userId: "${userA.id}" role: "stream:owner") }` } )
expect( res2 ).to.be.json
expect( res2.body.errors ).to.not.exist
const res3 = await sendRequest( userB.token, { query: `mutation{ streamGrantPermission( streamId: "${ts3}", userId: "${userC.id}" role: "stream:owner") }` } )
expect( res3 ).to.be.json
expect( res3.body.errors ).to.not.exist
} )
it( 'Should fail to grant permissions if not owner', async ( ) => {
@@ -172,7 +177,7 @@ describe( 'GraphQL API Core', ( ) => {
} )
it( 'Should update permissions', async ( ) => {
const res = await sendRequest( userA.token, { query: `mutation{ streamGrantPermission( streamId: "${ts1}", userId: "${userB.id}" role: "stream:reviewer") }` } )
const res = await sendRequest( userA.token, { query: `mutation{ streamGrantPermission( streamId: "${ts1}", userId: "${userB.id}" role: "stream:contributor") }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.streamGrantPermission ).to.equal( true )
@@ -218,6 +223,7 @@ describe( 'GraphQL API Core', ( ) => {
it( 'Should delete a stream', async ( ) => {
const res = await sendRequest( userB.token, { query: `mutation { streamDelete( id:"${ts4}")}` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data ).to.have.property( 'streamDelete' )
@@ -305,22 +311,36 @@ describe( 'GraphQL API Core', ( ) => {
} )
it( 'Should create several branches', async ( ) => {
const res1 = await sendRequest( userA.token, { query: `mutation($branch:BranchCreateInput!) { branchCreate(streamId:"${ts1}", branch:$branch) }`, variables: { branch: b1 } } )
b1 = { streamId: ts1, name: 'dim/dev', description: 'dimitries development branch' }
const res1 = await sendRequest( userA.token, { query: `mutation( $branch:BranchCreateInput! ) { branchCreate( branch:$branch ) }`, variables: { branch: b1 } } )
expect( res1 ).to.be.json
expect( res1.body.errors ).to.not.exist
expect( res1.body.data ).to.have.property( 'branchCreate' )
expect( res1.body.data.branchCreate ).to.be.a( 'string' )
b1.id = res1.body.data.branchCreate
const res2 = await sendRequest( userB.token, { query: `mutation($branch:BranchCreateInput!) { branchCreate(streamId:"${ts1}", branch:$branch) }`, variables: { branch: b2 } } )
b2 = { streamId: ts1, name: 'dim/dev/api-surgery', description: 'another branch' }
const res2 = await sendRequest( userB.token, { query: `mutation( $branch:BranchCreateInput! ) { branchCreate( branch:$branch ) }`, variables: { branch: b2 } } )
expect( res2.body.errors ).to.not.exist
b2.id = res2.body.data.branchCreate
const res3 = await sendRequest( userB.token, { query: `mutation($branch:BranchCreateInput!) { branchCreate(streamId:"${ts1}", branch:$branch) }`, variables: { branch: b3 } } )
b3 = { streamId: ts1, name: 'userB/dev/api', description: 'more branches branch' }
const res3 = await sendRequest( userB.token, { query: `mutation( $branch:BranchCreateInput! ) { branchCreate( branch:$branch ) }`, variables: { branch: b3 } } )
expect( res3.body.errors ).to.not.exist
b3.id = res3.body.data.branchCreate
} )
it( 'Should update a branch', async ( ) => {
const res1 = await sendRequest( userA.token, { query: `mutation($branch:BranchUpdateInput!) { branchUpdate(streamId:"${ts1}", branch:$branch) }`, variables: { branch: { id: b1.id, commits: [ c1.id ] } } } )
let payload = {
streamId: ts1,
id: b2.id,
name: 'userb/whatever/whatever'
}
const res1 = await sendRequest( userA.token, { query: `mutation( $branch:BranchUpdateInput! ) { branchUpdate( branch:$branch ) }`, variables: { branch: payload } } )
expect( res1 ).to.be.json
expect( res1.body.errors ).to.not.exist
expect( res1.body.data ).to.have.property( 'branchUpdate' )
@@ -328,11 +348,50 @@ describe( 'GraphQL API Core', ( ) => {
} )
it( 'Should delete a branch', async ( ) => {
const res = await sendRequest( userA.token, { query: `mutation { branchDelete(streamId:"${ts1}", branchId:"${b2.id}")}` } )
// give C some access permissions
const perms = await sendRequest( userA.token, { query: `mutation{ streamGrantPermission( streamId: "${ts1}", userId: "${userC.id}" role: "stream:contributor") }` } )
let payload = {
streamId: ts1,
id: b2.id
}
let badPayload = {
streamId: ts1,
id: 'APRIL FOOOLS!'
}
const res = await sendRequest( userC.token, { query: `mutation( $branch:BranchDeleteInput! ) { branchDelete( branch: $branch ) }`, variables: { branch: badPayload } } )
expect( res ).to.be.json
expect( res.body.errors ).to.exist
expect( res.body.errors[ 0 ].message ).to.equal( 'Branch not found.' )
const res1 = await sendRequest( userC.token, { query: `mutation( $branch:BranchDeleteInput! ) { branchDelete( branch: $branch ) }`, variables: { branch: payload } } )
expect( res1 ).to.be.json
expect( res1.body.errors ).to.exist
expect( res1.body.errors[ 0 ].message ).to.equal( 'Only the branch creator or stream owners are allowed to delete branches.' )
const res2 = await sendRequest( userA.token, { query: `mutation( $branch:BranchDeleteInput! ) { branchDelete( branch: $branch ) }`, variables: { branch: payload } } )
expect( res2 ).to.be.json
expect( res2.body.errors ).to.not.exist
// revoke perms for c back (dont' wanna mess up our integration-unit tests below)
await sendRequest( userA.token, { query: `mutation{ streamRevokePermission( streamId: "${ts1}", userId: "${userC.id}" ) }` } )
} )
it( 'Should commit to a non-master branch as well...', async ( ) => {
let cc = {}
cc.message = 'what a message for a second commit'
cc.streamId = ts1
cc.objectId = objIds[ 3 ]
cc.branchName = 'userB/dev/api'
let res = await sendRequest( userB.token, { query: `mutation( $myCommit: CommitCreateInput! ) { commitCreate( commit: $myCommit ) }`, variables: { myCommit: cc } } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data ).to.have.property( 'branchDelete' )
expect( res.body.data.branchDelete ).to.equal( true )
expect( res.body.data ).to.have.property( 'commitCreate' )
expect( res.body.data.commitCreate ).to.be.a( 'string' )
} )
} )
@@ -341,61 +400,73 @@ describe( 'GraphQL API Core', ( ) => {
describe( 'Queries', ( ) => {
it( 'Should retrieve my profile', async ( ) => {
const res = await sendRequest( userA.token, { query: `{ user { id name email role apiTokens { id name } } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data ).to.have.property( 'user' )
expect( res.body.data.user.name ).to.equal( 'Miticå' )
expect( res.body.data.user.email ).to.equal( 'd.1@speckle.systems' )
expect( res.body.data.user.role ).to.equal( 'server:admin' )
describe( 'My Profile', ( ) => {
it( 'Should retrieve my profile', async ( ) => {
const res = await sendRequest( userA.token, { query: `{ user { id name email role apiTokens { id name } } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data ).to.have.property( 'user' )
expect( res.body.data.user.name ).to.equal( 'Miticå' )
expect( res.body.data.user.email ).to.equal( 'd.1@speckle.systems' )
expect( res.body.data.user.role ).to.equal( 'server:admin' )
} )
it( 'Should retrieve my streams', async ( ) => {
const res = await sendRequest( userA.token, { query: `{ user { streamCollection { totalCount streams { id name role } } } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.user.streamCollection.totalCount ).to.equal( 3 )
let streams = res.body.data.user.streamCollection.streams
let s1 = streams.find( s => s.name === 'TS1 (u A) Private UPDATED' )
expect( s1 ).to.exist
} )
} )
it( 'Should retrieve a different profile profile', async ( ) => {
const res = await sendRequest( userA.token, { query: ` { user(id:"${userB.id}") { id name email } }` } )
describe( 'Different Users` Profile', ( ) => {
it( 'Should retrieve a different profile profile', async ( ) => {
const res = await sendRequest( userA.token, { query: ` { user(id:"${userB.id}") { id name email } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data ).to.have.property( 'user' )
expect( res.body.data.user.name ).to.equal( 'd2' )
expect( res.body.data.user.email ).to.equal( 'd.2@speckle.systems' )
} )
it( 'Should not retrieve a profile if no auth', async ( ) => {
const res = await sendRequest( null, { query: `{ user { id name email } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.exist
} )
it( 'Should not retrieve user email field if out of scope', async ( ) => {
// token1 has only users:read scope
const res = await sendRequest( token1, { query: ` { user(id:"${userB.id}") { id name email } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.user.email ).to.be.null
} )
it( 'Should only retrieve public streams from a different user profile ', async ( ) => {
const res = await sendRequest( token1, { query: `query { user(id:"${userB.id}") { streamCollection { totalCount streams { id name isPublic role }} } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.user.streamCollection.totalCount ).to.equal( 1 )
} )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data ).to.have.property( 'user' )
expect( res.body.data.user.name ).to.equal( 'd2' )
expect( res.body.data.user.email ).to.equal( 'd.2@speckle.systems' )
} )
it( 'Should not retrieve a profile if no auth', async ( ) => {
const res = await sendRequest( null, { query: `{ user { id name email } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.exist
} )
describe( 'Streams', ( ) => {
it( 'Should not retrieve user email field if out of scope', async ( ) => {
// token1 has only users:read scope
const res = await sendRequest( token1, { query: ` { user(id:"${userB.id}") { id name email } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.user.email ).to.be.null
} )
let retrievedStream
it( 'Should retrieve my streams', async ( ) => {
const res = await sendRequest( userA.token, { query: `{ user { streamCollection { totalCount streams { id name role } } } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.user.streamCollection.totalCount ).to.equal( 3 )
let streams = res.body.data.user.streamCollection.streams
let s1 = streams.find( s => s.name === 'TS1 (u A) Private UPDATED' )
expect( s1 ).to.exist
} )
it( 'Should only retrieve public streams from a different user profile ', async ( ) => {
const res = await sendRequest( token1, { query: `query { user(id:"${userB.id}") { streamCollection { totalCount streams { id name isPublic role }} } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.user.streamCollection.totalCount ).to.equal( 1 )
} )
let retrievedStream
it( 'Should fully retrieve a stream', async ( ) => {
const res = await sendRequest( userA.token, { query: `query {
it( 'Should fully retrieve a stream', async ( ) => {
const res = await sendRequest( userA.token, { query: `query {
stream(id:"${ts1}") {
id
name
@@ -437,39 +508,39 @@ describe( 'GraphQL API Core', ( ) => {
}
}` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
let stream = res.body.data.stream
retrievedStream = stream
let stream = res.body.data.stream
retrievedStream = stream
expect( stream.name ).to.equal( 'TS1 (u A) Private UPDATED' )
expect( stream.tags.totalCount ).to.equal( 2 )
expect( stream.branches.totalCount ).to.equal( 1 )
expect( stream.commits.totalCount ).to.equal( 2 )
expect( stream.users ).to.have.lengthOf( 2 )
expect( stream.name ).to.equal( 'TS1 (u A) Private UPDATED' )
expect( stream.tags.totalCount ).to.equal( 2 )
expect( stream.branches.totalCount ).to.equal( 1 )
expect( stream.commits.totalCount ).to.equal( 2 )
expect( stream.users ).to.have.lengthOf( 2 )
} )
it( 'should retrieve a stream branch', async ( ) => {
// note: adding another commit for the sake of it
const res1 = await sendRequest( userA.token, { query: `mutation($branch:BranchUpdateInput!) { branchUpdate(streamId:"${ts1}", branch:$branch) }`, variables: { branch: { id: b1.id, commits: [ c2.id ] } } } )
const res = await sendRequest( userA.token, { query: `query { stream(id:"${ts1}") { branch(id:"${retrievedStream.branches.branches[0].id}") { name description commits { totalCount } } } } ` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.stream.branch.name ).to.equal( 'branch 1' )
expect( res.body.data.stream.branch.commits.totalCount ).to.equal( 2 )
} )
it( 'should retrieve a stream commit', async ( ) => {
const res = await sendRequest( userA.token, { query: `query { stream(id:"${ts1}") { commit(id:"${c2.id}") { id description data } } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.stream.commit.description ).to.equal( 'test second commit' )
} )
} )
it( 'should retrieve a stream branch', async ( ) => {
// note: adding another commit for the sake of it
const res1 = await sendRequest( userA.token, { query: `mutation($branch:BranchUpdateInput!) { branchUpdate(streamId:"${ts1}", branch:$branch) }`, variables: { branch: { id: b1.id, commits: [ c2.id ] } } } )
const res = await sendRequest( userA.token, { query: `query { stream(id:"${ts1}") { branch(id:"${retrievedStream.branches.branches[0].id}") { name description commits { totalCount } } } } ` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.stream.branch.name ).to.equal( 'branch 1' )
expect( res.body.data.stream.branch.commits.totalCount ).to.equal( 2 )
} )
it( 'should retrieve a stream commit', async ( ) => {
const res = await sendRequest( userA.token, { query: `query { stream(id:"${ts1}") { commit(id:"${c2.id}") { id description data } } }` } )
expect( res ).to.be.json
expect( res.body.errors ).to.not.exist
expect( res.body.data.stream.commit.description ).to.equal( 'test second commit' )
} )
describe( 'Objects', ( ) => {
let myCommit
let myObjs
@@ -681,4 +752,4 @@ function createManyObjects( shitTon, noise ) {
function getAFuckingId( obj ) {
obj.id = obj.id || crypto.createHash( 'md5' ).update( JSON.stringify( obj ) ).digest( 'hex' )
}
}
+6 -6
View File
@@ -37,7 +37,7 @@ async function contextApiTokenHelper( { req, res } ) {
async function contextMiddleware( req, res, next ) {
let result = await contextApiTokenHelper( { req, res } )
req.context = result
next()
next( )
}
/*
@@ -107,14 +107,14 @@ async function authorizeResolver( userId, resourceId, requiredRole ) {
throw new ApolloError( `Resource of type ${role.resourceTarget} with ${resourceId} not found` )
}
let entry = await knex( role.aclTableName ).select( '*' ).where( { resourceId: resourceId, userId: userId } ).first( )
let userAclEntry = await knex( role.aclTableName ).select( '*' ).where( { resourceId: resourceId, userId: userId } ).first( )
if ( !entry ) throw new ForbiddenError( 'You are not authorized' )
if ( !userAclEntry ) throw new ForbiddenError( 'You are not authorized' )
entry.role = roles.find( r => r.name === entry.role )
userAclEntry.role = roles.find( r => r.name === userAclEntry.role )
if ( entry.role.weight >= role.weight )
return true
if ( userAclEntry.role.weight >= role.weight )
return userAclEntry.role.name
else
throw new ForbiddenError( 'You are not authorized' )
+493 -6
View File
@@ -643,6 +643,18 @@
"negotiator": "0.6.2"
}
},
"acorn": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz",
"integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==",
"dev": true
},
"acorn-jsx": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz",
"integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==",
"dev": true
},
"aggregate-error": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz",
@@ -653,6 +665,18 @@
"indent-string": "^4.0.0"
}
},
"ajv": {
"version": "6.12.3",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz",
"integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"ansi-colors": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz",
@@ -977,6 +1001,12 @@
"resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
"integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c="
},
"astral-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
"dev": true
},
"async-limiter": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
@@ -1263,8 +1293,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true,
"optional": true
"dev": true
},
"camelcase": {
"version": "5.3.1",
@@ -1881,6 +1910,12 @@
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
},
"deep-is": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
"dev": true
},
"default-require-extensions": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz",
@@ -1995,6 +2030,15 @@
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
"dev": true
},
"doctrine": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
"dev": true,
"requires": {
"esutils": "^2.0.2"
}
},
"dotenv": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
@@ -2016,6 +2060,23 @@
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"enquirer": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
"integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
"dev": true,
"requires": {
"ansi-colors": "^4.1.1"
},
"dependencies": {
"ansi-colors": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
"integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
"dev": true
}
}
},
"error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
@@ -2070,17 +2131,229 @@
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
"eslint": {
"version": "7.5.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.5.0.tgz",
"integrity": "sha512-vlUP10xse9sWt9SGRtcr1LAC67BENcQMFeV+w5EvLEoFe3xJ8cF1Skd0msziRx/VMC+72B4DxreCE+OR12OA6Q==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
"debug": "^4.0.1",
"doctrine": "^3.0.0",
"enquirer": "^2.3.5",
"eslint-scope": "^5.1.0",
"eslint-utils": "^2.1.0",
"eslint-visitor-keys": "^1.3.0",
"espree": "^7.2.0",
"esquery": "^1.2.0",
"esutils": "^2.0.2",
"file-entry-cache": "^5.0.1",
"functional-red-black-tree": "^1.0.1",
"glob-parent": "^5.0.0",
"globals": "^12.1.0",
"ignore": "^4.0.6",
"import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
"js-yaml": "^3.13.1",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.4.1",
"lodash": "^4.17.19",
"minimatch": "^3.0.4",
"natural-compare": "^1.4.0",
"optionator": "^0.9.1",
"progress": "^2.0.0",
"regexpp": "^3.1.0",
"semver": "^7.2.1",
"strip-ansi": "^6.0.0",
"strip-json-comments": "^3.1.0",
"table": "^5.2.3",
"text-table": "^0.2.0",
"v8-compile-cache": "^2.0.3"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
"dev": true
},
"ansi-styles": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
"dev": true,
"requires": {
"@types/color-name": "^1.1.1",
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"globals": {
"version": "12.4.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
"integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
"dev": true,
"requires": {
"type-fest": "^0.8.1"
}
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"lodash": {
"version": "4.17.19",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
"dev": true
},
"semver": {
"version": "7.3.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
"integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
"dev": true
},
"strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.0"
}
},
"strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"dev": true
},
"supports-color": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
"integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"eslint-scope": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz",
"integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==",
"dev": true,
"requires": {
"esrecurse": "^4.1.0",
"estraverse": "^4.1.1"
}
},
"eslint-utils": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
"integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
"dev": true,
"requires": {
"eslint-visitor-keys": "^1.1.0"
}
},
"eslint-visitor-keys": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
"integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
"dev": true
},
"esm": {
"version": "3.2.25",
"resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
"integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA=="
},
"espree": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-7.2.0.tgz",
"integrity": "sha512-H+cQ3+3JYRMEIOl87e7QdHX70ocly5iW4+dttuR8iYSPr/hXKFb+7dBsZ7+u1adC4VrnPlTkv0+OwuPnDop19g==",
"dev": true,
"requires": {
"acorn": "^7.3.1",
"acorn-jsx": "^5.2.0",
"eslint-visitor-keys": "^1.3.0"
}
},
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
},
"esquery": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz",
"integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==",
"dev": true,
"requires": {
"estraverse": "^5.1.0"
},
"dependencies": {
"estraverse": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz",
"integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==",
"dev": true
}
}
},
"esrecurse": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
"integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
"dev": true,
"requires": {
"estraverse": "^4.1.0"
}
},
"estraverse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
"dev": true
},
"esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
@@ -2330,11 +2603,23 @@
}
}
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"dev": true
},
"figures": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
@@ -2344,6 +2629,15 @@
"escape-string-regexp": "^1.0.5"
}
},
"file-entry-cache": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
"integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==",
"dev": true,
"requires": {
"flat-cache": "^2.0.1"
}
},
"fill-range": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
@@ -2475,6 +2769,34 @@
}
}
},
"flat-cache": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
"integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
"dev": true,
"requires": {
"flatted": "^2.0.0",
"rimraf": "2.6.3",
"write": "1.0.3"
},
"dependencies": {
"rimraf": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"dev": true,
"requires": {
"glob": "^7.1.3"
}
}
}
},
"flatted": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
"integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==",
"dev": true
},
"follow-redirects": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz",
@@ -2600,6 +2922,12 @@
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
"functional-red-black-tree": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
"dev": true
},
"gauge": {
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
@@ -3019,6 +3347,12 @@
"safer-buffer": ">= 2.1.2 < 3"
}
},
"ignore": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
"dev": true
},
"ignore-walk": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz",
@@ -3032,7 +3366,6 @@
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
"integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==",
"dev": true,
"optional": true,
"requires": {
"parent-module": "^1.0.0",
"resolve-from": "^4.0.0"
@@ -3042,8 +3375,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"dev": true,
"optional": true
"dev": true
}
}
},
@@ -3525,6 +3857,18 @@
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
"dev": true
},
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
},
"json-stable-stringify-without-jsonify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
"dev": true
},
"json5": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
@@ -3590,6 +3934,16 @@
}
}
},
"levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
"integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
"dev": true,
"requires": {
"prelude-ls": "^1.2.1",
"type-check": "~0.4.0"
}
},
"liftoff": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz",
@@ -3978,6 +4332,12 @@
"to-regex": "^3.0.1"
}
},
"natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
"dev": true
},
"needle": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.3.3.tgz",
@@ -4476,6 +4836,20 @@
"mimic-fn": "^1.0.0"
}
},
"optionator": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
"integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
"dev": true,
"requires": {
"deep-is": "^0.1.3",
"fast-levenshtein": "^2.0.6",
"levn": "^0.4.1",
"prelude-ls": "^1.2.1",
"type-check": "^0.4.0",
"word-wrap": "^1.2.3"
}
},
"os-homedir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
@@ -4550,7 +4924,6 @@
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
"dev": true,
"optional": true,
"requires": {
"callsites": "^3.0.0"
}
@@ -4851,6 +5224,12 @@
"xtend": "^4.0.0"
}
},
"prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
"dev": true
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -4865,6 +5244,12 @@
"fromentries": "^1.2.0"
}
},
"progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true
},
"proxy-addr": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
@@ -4874,6 +5259,12 @@
"ipaddr.js": "1.9.1"
}
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
"dev": true
},
"qs": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
@@ -4998,6 +5389,12 @@
"safe-regex": "^1.1.0"
}
},
"regexpp": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz",
"integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==",
"dev": true
},
"release-zalgo": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
@@ -5285,6 +5682,17 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
},
"slice-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
"integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.0",
"astral-regex": "^1.0.0",
"is-fullwidth-code-point": "^2.0.0"
}
},
"snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@@ -5669,6 +6077,46 @@
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
},
"table": {
"version": "5.4.6",
"resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
"integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==",
"dev": true,
"requires": {
"ajv": "^6.10.2",
"lodash": "^4.17.14",
"slice-ansi": "^2.1.0",
"string-width": "^3.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true
},
"string-width": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"dev": true,
"requires": {
"emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^5.1.0"
}
},
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"dev": true,
"requires": {
"ansi-regex": "^4.1.0"
}
}
}
},
"tar": {
"version": "4.4.13",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz",
@@ -5715,6 +6163,12 @@
}
}
},
"text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
"dev": true
},
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
@@ -5811,6 +6265,15 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz",
"integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA=="
},
"type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
"dev": true,
"requires": {
"prelude-ls": "^1.2.1"
}
},
"type-detect": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
@@ -5916,6 +6379,15 @@
}
}
},
"uri-js": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
"dev": true,
"requires": {
"punycode": "^2.1.0"
}
},
"urix": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
@@ -5952,6 +6424,12 @@
"resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.2.tgz",
"integrity": "sha512-vy9V/+pKG+5ZTYKf+VcphF5Oc6EFiu3W8Nv3P3zIh0EqVI80ZxOzuPfe9EHjkFNvf8+xuTHVeei4Drydlx4zjw=="
},
"v8-compile-cache": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz",
"integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==",
"dev": true
},
"v8flags": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz",
@@ -6047,6 +6525,15 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"write": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz",
"integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==",
"dev": true,
"requires": {
"mkdirp": "^0.5.1"
}
},
"write-file-atomic": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
+1
View File
@@ -63,6 +63,7 @@
"chai-http": "^4.3.0",
"concurrently": "^5.2.0",
"cz-conventional-changelog": "^3.1.0",
"eslint": "^7.5.0",
"http-proxy-middleware": "^1.0.4",
"mocha": "^7.1.1",
"nyc": "^15.0.1",